python, csv Dateien, Arrays und Excel

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.
snoozy
User
Beiträge: 10
Registriert: Freitag 20. April 2012, 08:31

Hey Leute, ich bin Student und habe den Auftrag bekommen eine riesige Menge an Messdaten aufzuarbeiten.
Die Daten liegen in sehr großen csv Dateien vor (~900000 Zeilen).
Es geht nun darum gleiche Messungen zu finden und Mittelwerte zu bilden.
Mein Plan ist es eine Index Datei anzulegen, die erzeugt wird, indem das Array, oder csv file, einmal durchgegangen wird.
Die Datei soll dann für jede Messung (diese unterscheiden sich jeweils in 5 strings z.B. testname, datenrate...) eine Zahl bestimmen.
Also z.B.:
[0,0,1,5,2,3.2312]
wobei 0,0,1,5,2 einen bestimmten Test markieren und 3.2312 das Ergebnis ist.
Diese index datei will ich anschließend sortieren, durchgehen und dann die Mittelwerte jeweils bilden, bis sich eine der Indexzahlen ändert.

Nun zu dem Hauptproblem:

Ich bekomme es einfach nicht hin ein ordentliches Array (wie in C) zu erzeugen. Bisher hab ich das so gelöst (code auszug):

Code: Alles auswählen

filecsv = open(infile, "r")
reader = csv.reader(filecsv, delimiter=",")

new_row={}

for row in reader:
    k=0
    index_temp = 99
    
    for k in range(len(band)):       
        if (band[k]==row[2]):            
            index_temp = k            
    index[i,0] = index_temp
         
    for k in range(len(datarate)):
        if (datarate[k]==row[6]):
            index_temp = k
    index[i,1] = index_temp
            
    for k in range(len(PCL)):
        if (PCL[k]==row[7]):
            index_temp = k
    index[i,2] = index_temp
    
    for k in range(len(test)):
        if (test[k]==row[8]):
            index[i,3] = k
    index[i,3] = index_temp
            
    for k in range(len(measurement)):
        if (measurement[k]==row[9]):
            index[i,4] = k
    index[i,4] = index_temp

    index[i,5] = row[10] #messergebnis

#das hier soll die csv Datei in den RAM holen, zum schnelleren durchsuchen
    new_row[i,0] = row[0]
    new_row[i,1] = row[1]
    new_row[i,2] = row[2]
    new_row[i,3] = row[3]
    new_row[i,4] = row[4]
    new_row[i,5] = row[5]
    new_row[i,6] = row[6]
    new_row[i,7] = row[7]
    new_row[i,8] = row[8]
    new_row[i,9] = row[9]
    new_row[i,10] = row[10] 
Mittlerweile hab ich gemerkt, dass es so sehr schlecht ist, weil das zum Durchsuchen falsch in der liste steht. (zum Schreiben in eine csv Datei auch.)
Habe aber bisher keine Möglichkeit gefunden, um eine liste freier größe zu erstellen, wo ich per index drauf zugreifen kann.

Danke für jede Hilfe (auch andere Lösungsvorschläge für das Problem willkommen!)
Zuletzt geändert von snoozy am Freitag 20. April 2012, 09:02, insgesamt 2-mal geändert.
Benutzeravatar
sparrow
User
Beiträge: 4176
Registriert: Freitag 17. April 2009, 10:28

snoozy hat geschrieben:Habe aber bisher keine möglichkeit gefunden, um eine liste freier größe zu erstellen, wo ich per index drauf zugreifen kann.
Zumindest die Frage kann ich dir beanworten:

Code: Alles auswählen

>>> a = ["Hallo", "du"]
>>> a
['Hallo', 'du']
>>> a[1]
'du'
>>> a[0]
'Hallo'
>>> a.append("!")
>>> a[3]

Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    a[3]
IndexError: list index out of range
>>> a[2]
'!'
>>> a
['Hallo', 'du', '!']
Die Antwort war aber so leicht, dass ich mir nicht vorstellen kann, dass du das meintest ;)
snoozy
User
Beiträge: 10
Registriert: Freitag 20. April 2012, 08:31

Danke dir, aber ich brauche eine liste unbestimmter Größe, die in der Schleife gefüllt wird.
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

Listen haben keine vorbestimmte Größe (da wir es ja nicht mit C zu tun haben und Speicherallokation nicht manuell durchgeführt werden muss).
snoozy
User
Beiträge: 10
Registriert: Freitag 20. April 2012, 08:31

ja, nur wie soll ich sie denn definieren?

Code: Alles auswählen

index = [[]] ??
index = [] ??
hab schon alles durchprobiert...
es geht einfach nicht

ich möchte gerne so darauf zugreifen können:
index[j]
Benutzeravatar
sparrow
User
Beiträge: 4176
Registriert: Freitag 17. April 2009, 10:28

Code: Alles auswählen

>>> a = []
>>> a.append(["ich", "bin", "eine", "Liste"])
>>> a.append(["ich", "auch"])
>>> a
[['ich', 'bin', 'eine', 'Liste'], ['ich', 'auch']]
>>> a[0][1]
'bin'
>>> a[1][1]
'auch'
Ich glaube aber, das ist nicht das was du willst. Das ist noch zu viel C-Denken.
Bitte zeig mal einige Beispieldaten wie du sie aus der CSV-Datei bekommst, und welches Ergebnis du haben möchtest.

Gruß
Sebastian
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

Deine vorgeschlagene Syntax sieht erstens verwirrend aus, da ``index`` darauf schließen lässt, dass du an den Index eines Elements kommen willst und die beiden Paare eckiger Klammern verschachtelt auf ein Element zugreifen. Und wenn du zweitens auf ein Element einer Liste zugreifst, wirst du wohl kaum so an den Index kommen. Insbesondere wenn man bedenkt, dass sich wiederholende Elemente gar nicht mal so unwahrscheinlich sind, wäre es besser du nutzt ``enumerate`` wenn du Dateneinträgen Indizes verpassen willst.

Ich rate dir also dazu das offizielle Python-Tutorial durchzuarbeiten bevor du weiterhin versuchst Python wie C anzugehen.
snoozy
User
Beiträge: 10
Registriert: Freitag 20. April 2012, 08:31

Ok, das mit dem C-Denken ist wohl war....

Leider stehen in dem Tutorial auch nur Beispiele, wie sparrow es gepostet hat.

so scheint es zu gehen

Code: Alles auswählen

new_row=[]
for row in reader:
    new_row.append([row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7],row[8], row[9],row[10]])
Wenn ich allerdings die Daten zurückschreibe in ein csv file, ist immer eine zeile leer?!

Code: Alles auswählen

csv_writer = csv.writer(open("index.csv", "w")) 
csv_writer.writerows(new_row)
hier die Struktur der Daten:
  • temperature,position,band,voltage,timeslot,channel,datarate,PCL,test,measurement,result,lower,upper,units,meas_status
    25,11,WLANB,4.2,none,1,11,18000,DSSS.DEMOD,BitRate,11,-999,999,enum,Pass
    25,11,WLANB,4.2,none,1,11,18000,DSSS.DEMOD,BurstGood,1,1,1,bool,Pass
    25,11,WLANB,4.2,none,1,11,18000,DSSS.DEMOD,ChipClockFrequencyError,-0.026401,-25,25,ppm,Pass
Benutzeravatar
sparrow
User
Beiträge: 4176
Registriert: Freitag 17. April 2009, 10:28

Ich bin trotzdem dafür, dass du hier einmal den Ursprung zeigst und das erhoffte Ergebnis.

Wenn es darum geht nach Werten zu gruppieren und deren Durchschnitt zu errechnen geht das mit den vorgestellten Daten zum Beispiel so:

Code: Alles auswählen

>>> a = [(0,0,1,5,2,3.2312), (0,0,1,5,2,3.2310), (0,0,1,5,2,3.2311), (0,0,1,5,4,4.5311), (0,0,1,5,3,4.5317)]
>>> groups = {}
>>> for part in a:
	testname = part[0:5]
	if testname not in groups:
		groups[testname] = []
	groups[testname].append(part[5])

	
>>> groups
{(0, 0, 1, 5, 4): [4.5311], (0, 0, 1, 5, 3): [4.5317], (0, 0, 1, 5, 2): [3.2312, 3.231, 3.2311]}
>>> for testname, values in groups.items():
	avg = sum(values) / len(values)
	print "Test '%s' hat einen Durchschnitt von: %f" % (testname, avg)

	
Test '(0, 0, 1, 5, 4)' hat einen Durchschnitt von: 4.531100
Test '(0, 0, 1, 5, 3)' hat einen Durchschnitt von: 4.531700
Test '(0, 0, 1, 5, 2)' hat einen Durchschnitt von: 3.231100
Das geht mit itertools oder so bestimmt schöner, aber das hier sollte verständlich sein. Das dict "groups" wird mit den Werten gefüllt, als Schlüssel dient der Testname (Wenn ich dich richtig verstanden habe).

Am Ende hast du in groups einen Schlüssel auf der einen Seite und eine Liste auf der Werte-Seite. Und daraus dann den Durchschnitt zu berechnen ist kein Problem.

Ist das nahe an deinem Problem?
snoozy
User
Beiträge: 10
Registriert: Freitag 20. April 2012, 08:31

Ja, das klingt schon sehr schön.

Also, wie die Daten aussehen hab ich ja gepostet.

Die Messungen unterscheiden sich in
band,datarate,PCL,test,measurement
und sind in der Datei verteilt.

Es müssen also alle Messungen zusammengefasst werden (Mittelwert,Min,Max), die in den 5 Punkten übereinstimmen.

Das Ergebnis soll ein Excel file sein, wo die Mittelwerte vieler solcher csv files gegenüber gestellt werden.

EDIT:
Im Prinzip kann ich mir den Index dann auch sparen und einfach nach strings gruppieren, oder?

Hab mal versucht deinen Code für mich passend zu machen:

Code: Alles auswählen

groups = {}
for part in new_row:
    testname = part[0:5]
    if testname not in groups:
        groups[testname] = []
    groups[testname].append(part[5])
Bekomme allerdings diesen error:
Type error: unhashable type: 'list'

In new_row stehen die Werte jetzt richtig drin, allerdings als string.
Benutzeravatar
sparrow
User
Beiträge: 4176
Registriert: Freitag 17. April 2009, 10:28

snoozy hat geschrieben:Bekomme allerdings diesen error:
Type error: unhashable type: 'list'
In welcher Zeile? Bei mir war new_row eine Liste. Wenn es bei dir etwas anderes ist wird man auf die Elemente 1-4 nicht mit [0:5] zugreifen können.
BlackJack

@snoozy: Als Schlüssel in Wörterbüchern gehen nur Objekte von denen man einen unveränderlichen Hashwert errechnen kann, weil Wörterbücher als Hashtabelle implementiert sind. Listen kann man verändern, darum meckert deren `__hash__()`-Methode wenn man versucht einen Hash zu ermitteln. Tupel sind unveränderbar, also müsstest Du die Liste mit dem Testnamen einfach nur in ein Tupel umwandeln.

Statt eines normalen Wörterbuchs könnte man hier `collections.defaultdict` einsetzen um den Code einfacher zu machen.

Falls Speicherplatz ein Problem werden könnte/sollte, kann man statt Listen in dem Wörterbuch zu speichern auch einen eigenen Typ implementieren der sich Summe, Anzahl, Minimum, und Maximum merkt und auf verlangen den Durchschnitt aus Anzahl und Summe berechnet. Dann braucht man nur diese vier Werte pro Messung speichern und nicht eine potentiell lange Liste von Werten.

Der Name `new_row` für mehr als eine Zeile ist irreführend.

Öffne die Datei für den `writer` mal im Binärmodus. Das CSV-Modul schreibt explizit '\r\n' als Zeilenende raus und unter Windows zumindest verändert die C-Laufzeitbibliothek das dann in '\r\r\n'. Vielleicht nicht das was man haben möchte.

Das `itertools`-Modul wurde ja schon erwähnt — da stecken nützliche Funktionen drin, wenn man Datenströme „lazy” verarbeiten möchte. Und mit `operator.itemgetter()` kann man sich eine Funktion erstellen um die gewünschten Spalten aus einer Eingabezeile zu holen.

Wenn Du mit dem Messergebnis rechnen willst, musst Du die Zeichenkette an irgendeiner Stelle in eine Zahl umwandeln.
snoozy
User
Beiträge: 10
Registriert: Freitag 20. April 2012, 08:31

Danke erstmal für den tollen support hier im Forum :!:

@sparrow: Der Fehler tritt in dieser zeile auf:

Code: Alles auswählen

if testname not in groups:
new_row ist eine liste:

Code: Alles auswählen

new_row=[]
for row in reader:
    new_row.append([row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7],row[8], row[9],row[10]])
@BlackJack: das mit dem Umwandeln scheint zu funktionieren

Code: Alles auswählen

groups = {}
for part in new_row:
    testname = part[0:5]
    testname2 = tuple(testname)
    if testname2 not in groups:
        groups[testname2] = []
    groups[testname2].append(part[4])
Was allerdings noch nicht klappt, ist dieser Teil:

Code: Alles auswählen

for testname2, values in groups.items():
    avg = sum(values) / len(values)
Das Problem ist, dass values eine liste ist und sum() darauf nicht angewendet werden kann.
Leider hab ich den code noch nicht ganz verstanden, daher finde ich keine Lösung.
Bisher konnte ich die Werte ja einfach mit int() bzw. float() casten, aber wie soll das bei values gehen, denn das scheint eine liste zu sein?!


Achso, wenn ich das csv im Binärmodus öffne, kann ich keine strings reinschreiben.

Code: Alles auswählen

csv_writer = csv.writer(open("index.csv", "wb")) 
Zuletzt geändert von snoozy am Freitag 20. April 2012, 12:56, insgesamt 3-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Code: Alles auswählen

new_row=[]
for row in reader:
    new_row.append([row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7],row[8], row[9],row[10]])
So etwas sieht einfach nur scheußlich aus ;-)

Wieso nicht so?

Code: Alles auswählen

new_row=[]
for row in reader:
    new_row.append(row[0:11])
Oder als List-Comprehension:

Code: Alles auswählen

new_row = [row[0:11] for row in reader]
Der Name `new_row` passt auch nicht wirklich... da stehen ja *viele* `rows` drin.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
snoozy
User
Beiträge: 10
Registriert: Freitag 20. April 2012, 08:31

ja, warum eigentlich nicht^^

Ich habe jetzt allerdings weniger items in der "new_row" (jetzt new_list :lol: ),
habs so gemacht:

Code: Alles auswählen

new_list.append([row[2],row[6],row[7],row[8],row[10]])
nicht schön, aber funzt...

EDIT:
Das o.g. Problem konnte ich nun lösen:

Code: Alles auswählen

for testname2, values in groups.items(): 
    for l in range(len(values)):
        values[l] = float(values[l])
    avg = sum(values) / len(values)
    print ("Test '%s' : %f" % (testname2, avg)
Jetzt habe ich aber ein Problem das in ein csv file zurückzuschreiben...
Zuletzt geändert von snoozy am Freitag 20. April 2012, 13:26, insgesamt 1-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

`new_list` ist auch kein schöner Name... wieso ist die denn "neu"? Beschreibe im Namen doch eher, *was* für Objekte dahinter stecken und nicht, von welchem Typ diese sind.

Du kannst Slicing auch mit einem einfachen Indexzugriff kombinieren:

Code: Alles auswählen

new_list.append([row[2]] + row[6:11])
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
sparrow
User
Beiträge: 4176
Registriert: Freitag 17. April 2009, 10:28

Zum Code-Verständnis:

Code: Alles auswählen

# Erstelle eine Liste mit 5 Tupeln. Liste = [] Tuple = ()
>>> a = [(0,0,1,5,2,3.2312), (0,0,1,5,2,3.2310), (0,0,1,5,2,3.2311), (0,0,1,5,4,4.5311), (0,0,1,5,3,4.5317)]
>>> groups = {} # Erstelle ein dict mit dem Namen groups
>>> for part in a: # Für jedes Element (part) in in a tue (Element sind hier die einzelnen Tuple in der Liste)
        testname = part[0:5] # testname sind die Elemente 0-4 von Part (beim ersten Durchlauf also 0,0,1,5,2)
        if testname not in groups: # wenn noch kein Schlüssel namens Testname in groups ist
                groups[testname] = [] # lege den Schlüssel an und hinterlege als Hinhalt eine leere Liste
        groups[testname].append(part[5]) # füge an die Liste mit Schlüssel 'testname' in groups das 4. Element aus part an
                                                       # dieser wert wird später in der schleifa ls "values" wieder abgerufen

       
>>> groups
{(0, 0, 1, 5, 4): [4.5311], (0, 0, 1, 5, 3): [4.5317], (0, 0, 1, 5, 2): [3.2312, 3.231, 3.2311]}
>>> for testname, values in groups.items(): # für jede schlüssel (testname) in dem dict groups finde den wert (values)
        avg = sum(values) / len(values) # avg ist die summe aller elemente in values durch deren anzahl
        print "Test '%s' hat einen Durchschnitt von: %f" % (testname, avg)

       
Test '(0, 0, 1, 5, 4)' hat einen Durchschnitt von: 4.531100
Test '(0, 0, 1, 5, 3)' hat einen Durchschnitt von: 4.531700
Test '(0, 0, 1, 5, 2)' hat einen Durchschnitt von: 3.231100
Und du solltest dir wirklich das Tutorial ansehen.
snoozy
User
Beiträge: 10
Registriert: Freitag 20. April 2012, 08:31

Bin jetzt einen großen Schritt weiter und bekomme die richtigen Resultate, wenn auch nicht ganz perfekt.
Hier aber mal der Code im ganzen:

Code: Alles auswählen

import csv
import string
import xlwt3
import os
import sys
import time
import re   #needed for whitelist / pattern search
from operator import itemgetter
from datetime import date

if len(sys.argv) < 2:
    print('error: specify input file path\n\nusage: phyton.exe create_xls2.py <input csv file>')
    sys.exit(2)

print('Parsing...')

infile = sys.argv[1] #'infiletest.csv'
outfile = infile.rsplit('\\',1)[0] + '\\Test'  + time.strftime("-%Y-%m-%d_%H-%M-%S") + '.xls'




#open csv file
filecsv = open(infile, "r")
reader = csv.reader(filecsv, delimiter=",")

csv_writer = csv.writer(open(infile.rsplit('\\',1)[0] + '\\Test'  + time.strftime("-%Y-%m-%d_%H-%M-%S") + '.csv', "w"), lineterminator='\n') 
title=("band","datarate","PCL","test","measurement","min","avg","max")
csv_writer.writerow(title)



new_list=[]

for row in reader:
       new_list.append([row[2],row[6],row[7],row[8],row[9],row[10]])

print("sorting")
sorted(new_list, key=itemgetter(0,1,2,3,4))
    
print("Build groups")
groups = {}
for part in new_list:
    testname = part[0:5]
    testname2 = tuple(testname)
    if testname2 not in groups:
        groups[testname2] = []
    groups[testname2].append(part[5])

print("calc avg,min,max")
for testname2, values in groups.items(): 
    for l in range(len(values)):
        values[l] = float(values[l])
    avg = sum(values) / len(values)
    maximum = max(values)
    minimum = min(values)
    
    temp = (testname2,minimum,avg,maximum)
    csv_writer.writerow(temp)

Die Ausgabe sieht wie folgt aus:
  • band,datarate,PCL,test,measurement,min,avg,max
    ('WLANG', '54', '13000', 'OFDM.CFL', 'FrequencyLeakage'),-47.316831,-41.10720679166666,-37.296583
To do:
1. Die Klammern des Tuples testname2 nicht ins csv schreiben
2. Sortierung, im Prinzip so, wie ich oben schon probiert habe mit sorted...
3. Es gibt Messungen, die sich nicht durch den Namen oder so unterscheiden, sondern nur dadurch, ob das Ergebnis negativ oder positiv ist.
4. Uninteressante Messungen sollen entfernt werden
5. Die Tabellenköpfe in den original Files können nicht durch die Guppierungsfunktion und müssen daher vorher gelöscht werden.

Nun gut, vielen Dank nochmal für die Hilfe und erstmal schönes Wochenende!
BlackJack

@snoozy: Sowas hier ist in Python ein totales Anti-Pattern:

Code: Alles auswählen

    for l in range(len(values)):
        values[l] = float(values[l])
Man kann über die Elemente von `values` *direkt* iterieren, ohne einen Umweg über einen Index. Wenn man zusätzlich zum Wert noch den Index braucht, gibt es die `enumerate()`-Funktion. Man könnte aber auch einfach eine neue Liste mit den umgewandelten Werten erstellen. Mit einer „list comprehension” (LC) oder `map()`. Oder, und das dürfte hier die beste Alternative sein: Man erstellt erst gar keine Liste mit Zeichenketten sondern steckt dort gleich von Anfang an Zahlen rein.

Wenn man anfängt Namen durch zu nummerieren, macht man meistens etwas falsch. Warum gibt es `testname` und `testname2`? Man muss nicht jedes kleine Zwischenergebnis an einen Namen binden. Warum die zweite Schleife mit `testname2`?

Pfadoperationen sollte man nicht mit Zeichenkettenoperationen selber basteln, sondern das nehmen was im `os.path`-Modul angeboten wird. Dann funktioniert das nicht nur unter Betriebssystemen die \ als Pfadtrenner verwenden und `os.path.dirname(in_filename)`` ist auch verständlicher als ``in_filename.rsplit('\\',1)[0]``. An der Stelle habe ich das mal `in_filename` genannt, weil `infile` irreführend ist. Ein Dateiname ist keine Datei.

`outfile` wird nicht verwendet und die Erstellung wird fast 1:1 später noch einmal gemacht.

Dateien sollte man mit der ``with``-Anweisung öffnen, dann kann man auch nicht vergessen sie wieder zu schliessen.

Der `sorted()`-Aufruf ist nutzlos. Der erstellt eine neue, sortierte Liste die Du dann aber einfach verfallen lässt, weil Du damit nichts machst. Du musst den Rückgabewert schon an einen Namen binden oder anderweitig weiter verwenden. Wobei das Sortieren an der Stelle sowieso nicht viel Sinn macht, denn Wörterbücher sind ungeordnet. Da kommt dann sowieso alles wieder durcheinander.

Binärmodus bei `csv` geht in Python 3 anscheinend wirklich nicht. Das verwende ich noch nicht.

Zu den ToDos: 1. Wenn Du von Klammern des Tupels nicht schreiben sprichst, befindest Du Dich IMHO auf der falschen Abstraktionsebene. Du willst keine Klammern weglassen, sondern für den `writerow()`-Aufruf den Wert richtig aufbauen — keine verschachtelte Sequenz sondern eine flache.

2. Die Sortierung kommt nach der Verarbeitung, weil Wörterbücher wie gesagt ungeordnet sind.

3. Da kann ich so nichts mit Anfangen.

4. Wenn sich „uninteressante Messung” als Prädikat ausdrücken lässt, dann kann man das beim einlesen einfach ausfiltern. `itertools.ifilter()` oder der ``if``-Teil einer LC oder eines Generatorausdrucks.

5. Einfach die erste Zeile aus dem `reader` mit `next()` überspringen.

Du solltest vielleicht auch jetzt schon mal anfangen Funktionen zu erstellen. Das ist auch jetzt schon komplex genug das man es auf mehrere aufteilen kann.

Ich habe das Einlesen und Durchschnitt/Minimal-/Maximalwert ermitteln mal ohne Listen (und für Python 2.x) geschrieben (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import csv
from collections import defaultdict
from itertools import imap
from operator import itemgetter


class Aggregator(object):
    def __init__(self):
        self.count = 0
        self.sum = 0
        self.min = self.max = None
    
    def __call__(self, value):
        self.count += 1
        self.sum += value
        if self.max is None:
            assert self.min is None
            self.max = self.min = value
        else:
            self.max = max(self.max, value)
            self.min = min(self.min, value)
    
    @property
    def average(self):
        return self.sum / self.count


def main():
    with open('test.csv', 'rb') as in_file:
        reader = csv.reader(in_file, delimiter=',')
        _headers = reader.next()
        results = defaultdict(Aggregator)
        rows = imap(itemgetter(2, 6, 7, 8, 9, 10), reader)
        for band, datarate, pcl, test, measurement, result in rows:
            results[(band, datarate, pcl, test, measurement)](float(result))

    for key, result in sorted(results.iteritems()):
        print '%r: #=%d avg=%.3f min=%.3f max=%.3f' % (
            key, result.count, result.average, result.min, result.max
        )


if __name__ == '__main__':
    main()
snoozy
User
Beiträge: 10
Registriert: Freitag 20. April 2012, 08:31

Hey, vielen Dank für die tollen Antworten!

Ein paar der Vorschläge habe ich schon umgesetzt, leider fehlt mir etwas Zeit und skill, um alles umzusetzen.

Die Daten zu filtern und die Mittelwerte in Zusammenhang mit den Messungen auszugeben klappt ja schon sehr gut.
Leider ist damit noch nicht das Ziel erreicht, und mein eigentlicher Plan geht nicht auf :?

Was nun noch gemacht werden muss:
Ich kann jetzt jede Menge csv Dateien erstellen, die die gewünschten Werte enthalten. Die sehen dann so aus:

Code: Alles auswählen

band,datarate,PCL,test,measurement,min,avg,max
('WLANG', '54', '13000', 'OFDM.CFL', 'FrequencyLeakage'),-47.316831,-41.10720679166667,-37.296583
('WLANA', '6', '17000', 'OFDM.Spectral.Mask', 'ReferenceLevelResult'),-53.010223,-52.609291722222224,-51.98594
('WLANB', '11', '18000', 'DSSS.POWERRAMP', 'NumDownRampVectorSamples'),1000.0,1000.0,1000.0
...
Jetzt müssen im Prinzip aus all diesen Dateien die gleichen Messungen (das was in den Klammern steht) herausgesucht werden und zusammen mit dem Dateinamen in eine csv oder excel Datei geschrieben werden, also so:

Code: Alles auswählen

Messung1,('WLANG', '54', '13000', 'OFDM.CFL', 'FrequencyLeakage'),-47.316831,-41.10720679166667,-37.296583
Messung2,('WLANG', '54', '13000', 'OFDM.CFL', 'FrequencyLeakage'),-45.316831,-45.10720679166667,-35296583
Messung3,('WLANG', '54', '13000', 'OFDM.CFL', 'FrequencyLeakage'),-46.316831,-46.10720679166667,-36.296583
...
Ich dachte, wenn ich erstmal alle Messungen in Excel hab, dann geht das schon irgendwie... naja falsch gedacht...

Jetzt hab ich überlegt, ob das nicht auch mit der Group Funktion geht, hab aber keine Ahnung wie genau.
Ich kann die Dateien, die die Messungen mit Mittelwerten enthalten alle in einen Ordner packen. Anschließend müsste ich die ja auch in python öffnen können.
Dann könnte ich doch die einzelnen Dateien gruppieren, oder irgendwie anders vergleichen.
Es sind nicht in allen Dateien die gleichen Messungen.

Hat jemand eine Idee, wie das gehen kann? :K
Antworten