Textdatei auswerten

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Chill-man
User
Beiträge: 24
Registriert: Dienstag 8. Januar 2008, 10:46

Freitag 4. April 2008, 08:49

Hallo,

Ich habe ein Versuch bei dem Daten in eine Textdatei geschrieben werden.
Die Daten sind zum Beispiel Reaktionszeit, Falsch/Richtig, ...

Wie kann ich jetzt mit Python alle richtigen Ergebnisse zusammenzählen lassen, und wie kann ich aus allen Versuchspersonen einen Mittelwert bilden (wiederum unter Hilfe von Python)

Hier ein Link zu einer solchen Textdatei:

http://rapidshare.com/files/104741987/0 ... such1.html

einfach mit dem Editor öffnen.

Danke schonmal für eure Hilfe.

Cheers Chill-man
Benutzeravatar
Hyperion
Moderator
Beiträge: 7472
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Freitag 4. April 2008, 09:15

Wie groß / gut sind denn Deine Python-Kenntnisse? Eigentlich ein relativ simples Problem, da hier offensichtlich Tabs als Trennzeichen verwendet werden. Also eigentlich muss man die Datei nur öffnen, bis zum Start der Tabelle "vorspulen" und dann die Zeilen per split auftrenne und entsprechend scannen (also sich irgendwo merken und ggf. konvertieren in den erwünschten Typ). Das Speichern ginge z.B. als Liste von Dictionaries.

Das "vorspulen" kann man wohl auf verschiedene Arten erledigen. Also entweder solange gucken, bis man nach einem Tab genau eine "1" stehen hat, oder evtl. nen regexp bauen, der nur Ziffern und Tabs akzeptiert o.ä.

Wenn die Datei extrem stabil ist, reicht es zur Not auch aus, stumpf die Zeilen zu zählen! Allerdings ist man dann wirklich sehr unflexibel ...
Chill-man
User
Beiträge: 24
Registriert: Dienstag 8. Januar 2008, 10:46

Freitag 4. April 2008, 10:17

Hallo,

also meine Python Kenntnisse sind nicht all zu groß. Das die einzelnen Reihen mit Tabs erstellt wurden ist richtig. Hast du vielleicht irgendwo eine Anleitung oder kennst ein Tutorial welches ein solches Thema behandelt?

Danke für die schnelle Antwort.

MfG Chill-man
Benutzeravatar
Hyperion
Moderator
Beiträge: 7472
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Freitag 4. April 2008, 10:20

Hm ... also am besten arbeitest Du das offizielle Tutorial mal durch. Desweiteren suchst Du einfach mal hier im Forum danach. Eigentlich sollte das damit leicht lösbar sein!
Jan-Peer
User
Beiträge: 166
Registriert: Dienstag 2. Oktober 2007, 10:55

Freitag 4. April 2008, 10:38

Hyperion hat geschrieben:Hm ... also am besten arbeitest Du das offizielle Tutorial mal durch. Desweiteren suchst Du einfach mal hier im Forum danach. Eigentlich sollte das damit leicht lösbar sein!
Ich überlege gerade, ob sich das nicht gut in einer Standard-Signatur für alle Forennutzer machen würde :lol:
Benutzeravatar
Masaru
User
Beiträge: 425
Registriert: Mittwoch 4. August 2004, 22:17

Freitag 4. April 2008, 14:21

Hallo Chill-man,

wenn ich das richtig sehe, hast du mehrere dieser Dateien. Und jede Datei enthällt Meta-Datein zur Person (und zum Versuch), eine Legende und dann nach einer Kopf-Zeile mehrere Zeilen an Werten.

Fangen wir doch erstmal an, wie du eine Datei so in die Python-Welt bringst, dass du damit dann vernünftig weiterarbeiten kannst.

Die folgenden Beispiel-Codesnippets sind noch nicht zusammenhängend, du musst sie noch zu einem vernüftigen Script/Programm zusammenschrauben.

1.) Einlesen der Datei
Als ersten Schritt, musst du eine solche Datei ja erstmal irgendwie in Python hinneinbringen. Dies machst du mit der Python Standardfunktion file().

Code: Alles auswählen

subject_file = file(r'e:\01_01.BlendVersuch1')
subject_content = subject_file.read()
subject_file.close()
lines = subject_content.splitlines() # hier wird der Inhalt in eine Liste aufgesplittet
Nun hast du eine Liste mit den Zeilen deiner Datei. Dabei ist jeder Eintrag eine Zeichenkette, mit der du so natürlich noch nichts anfangen kannst.

Interessant für dich ist ja der Teil nach dieser Kopfzeile, vermute ich mal:

Code: Alles auswählen

	block	trial	object_type	preview_duration	response	RT		error_code
... weswegen der nächste Schritt wäre, die Zeilen solange durchzugehen, bis du diese Stelle erreicht hast.

Wie auch immer du es machst ... ist letztendlich dir überlassen ;).
Hier wäre aber z.B. ein Biespiel, wie du die Position dieser Kopfzeile in der Liste ermitten "könntest" (den Listenindex):

Code: Alles auswählen

headers = ['block', 'trial', 'object_type', 'preview_duration', 'response', 'RT', 'error_code']
header_index = -1 
for line in lines:
    if line.strip().replace('\t','').replace(' ','') == ''.join(headers):
        header_index = lines.index(line)
Anmrk: Bei deiner Beispieldatei sollte header_index den Wert 20 nach diesem Ablauf haben. Prüfe zudem am besten, dass du auch wirklich einen gültigen Index bekommen hast (z.B. header_index != -1 ... oder so).

Nun hast du aber schonmal auf jeden Fall die Stelle ab der die gelisteten Testdaten auftauchen, aber die müssen nun ebenfalls in eine für Weiterbearbeitungen sinnvolle Struktur gebracht werden: nämlich in eine Liste von Dictionaries.


2.) Die Testdaten-Zeilen in Dictionary-Form parsen
Für das Parsen verwende ich in dem nachfolgendem Beispiel die Regular Expressions
Um mit Regular Expressions zu arbeiten, musst zu Begin die ensprichtende Lib hiefür geladen haben.
Danach kannst du dir ein RE-Objet zusammenbrauen:

Code: Alles auswählen

import re # wie ja bereits erwähnt erforderlich
testdata_pattern = '^\s*' + '\s*'.join(['(?P<%s>\d*)'%h for h in headers]) + '.*$'
testdataRE = re.compile(testdata_pattern)
... mit welchem man die einzelnen Zeilen ab dem Header-Index ganz einfach in fertige Dictionaries zerlegen kann:

Code: Alles auswählen

subject_testdata = []
for line in lines[header_index+1:]:
    match = testdataRE.match(line)
    if match:
        subject_testdata.append(match.groupdict())
.... und nun hat man eine Liste von Dictionaries mit den Schlüsseln der Kopfzeile und den jeweiligen Werten (Achtung: es sind noch alles Strings .. du könntest sie der Einfachheit versuchen in Integer oder auch Booleans umzuwandeln).

3.) Auswertung
Nun kann man diese Strutkur nach eigenen Wünschen und Kriterien auswerten.

Z.B. wenn du die Anzahl aller richtigen Ergebnisse haben möchtest:

Code: Alles auswählen

true_counter = 0
for test in subject_testdata:
    if test['error_code'] and int(test['error_code']) == 1:
        true_counter += 1
... etc. pp.


Achja .. die anderen Metadaten einer Probanten-Datei kannst du natürlich ebenfalls ausparsen. Brauchst nur andere RE-Patterns, Listenstrukturen, etc. dafür ;).

Viel Spass dabei,

>>Masaru<<
Chill-man
User
Beiträge: 24
Registriert: Dienstag 8. Januar 2008, 10:46

Freitag 4. April 2008, 16:29

Ja hallo,

vielen vielen Dank für deine Anleitung Masaru.
Hat mir sehr geholfen.

MfG Chill-man
Chill-man
User
Beiträge: 24
Registriert: Dienstag 8. Januar 2008, 10:46

Mittwoch 9. April 2008, 10:40

Hallo,

ich bins nochmal.
Ich hab da nur noch eine kleine Frage und zwar rechne ich alle Reaktionszeiten der richtigen Ergebnisse zusammen und teile diese dann durch die Anzahl der richtigen Ergebnisse. Allerdings habe ich Probleme beim Zusammenrechnen. Irgendwie rechnet der etwas falsches zusammen. Aufgrund dessen wollte ich fragen ob ihr mir da vielleicht noch einmal weiterhelfen könnt.

hier der Code:

Code: Alles auswählen

for test in subject_testdata:
    if test['error_code'] and int(test['error_code']) == 0:
        Richtig += 1
        if test['object_type'] and test['object_type'] == '1':
            r_Bed_1 += 1
            RT_1 += int(test['RT'])
        elif test['object_type'] and test['object_type'] == '2':
            r_Bed_2 += 1
            RT_1 += int(test['RT'])
        elif test['object_type'] and test['object_type'] == '3':
            r_Bed_3 += 1
            RT_1 += int(test['RT'])
        elif test['object_type'] and test['object_type'] == '4':
            r_Bed_4 += 1
            RT_1 += int(test['RT'])

RT_Bed_1 = RT_1 / r_Bed_1
RT_Bed_2 = RT_1 / r_Bed_2
RT_Bed_3 = RT_1 / r_Bed_3
RT_Bed_4 = RT_1 / r_Bed_4

Erkennt ihr da irgend einen Fehler?

Vielen Dank schonmal,

cheers Tillmann


edit: Ohh man Problem gelöst habe immer auf die gleiche Variable geschrieben ...
BlackJack

Mittwoch 9. April 2008, 11:55

Du testest in der "innersten Ebene" immer wieder unnötigerweise den Wahrheitsgehalt von ``test['object_type']``. Wenn der zweite Teil nach dem ``and`` wahr ist, dann ist der Ausdruck ``test['object_type']`` auch wahr. (Es sei denn man hätte sich einen ziemlich kranken Datentyp selbst gebastelt.)

Und man kann ``RT_1 += int(test['RT'])`` heraus ziehen. Das wird in jedem Zweig wiederholt, wird also in jedem Fall ausgeführt.

Nur um sicher zu gehen würde ich nach das letzte ``elif`` noch ein ``else`` anhängen, dass eine Ausnahme auslöst, zum Beispiel mit Hilfe von ``assert``, oder zumindest eine Warnung ausgibt, dass da etwas nicht stimmt.

Und nun zur wahrscheinlichen Problemursache: `RT_1` und `r_Bed_*` sind ganze Zahlen und eine Division ergibt normalerweise wieder eine ganze Zahl. Entweder musst Du mindestens eine an der Division beteiligte Zahl in eine Fliesskommazahl umwandeln, oder ganz am Anfang des Moduls ``from __future__ import division`` verwenden.

Und Du könntest Dir überlegen die Objekte `RT_Bed_*` und `r_Bed_*` in Listen zu stecken. Wenn man anfängt Namen durch zu nummerieren, dann möchte man in der Regel eigentlich Listen verwenden. Ungetestet:

Code: Alles auswählen

r_bed = [0] * 4
reaction_time = 0
for test in subject_testdata:
    if int(test['error_code']) == 0:
        r_bed[int(test['object_type']) - 1] += 1
        reaction_time += int(test['RT'])
richtig = sum(r_bed)
average_reaction_time = [float(reaction_time) / n for n in r_bed]
BlackJack

Mittwoch 9. April 2008, 12:00

Falls `RT_1` eigentlich auch eine Liste sein sollte (ungetestet):

Code: Alles auswählen

OBJECT_COUNT = 4

r_bed = [0] * OBJECT_COUNT
reaction_time = [0] * OBJECT_COUNT
for test in subject_testdata:
    if int(test['error_code']) == 0:
        object_type = int(test['object_type']) - 1
        r_bed[object_type] += 1
        reaction_time[object_type] += int(test['RT'])
richtig = sum(r_bed)
average_reaction_time = [float(rt) / n for rt, n in zip(reaction_time, r_bed)]
Antworten