2009-11-20 3 views
5

Ich habe mehrere (10 oder so) CSV-formatierte Datensätze. Jede Spalte eines Datensatzes repräsentiert einen Aspekt eines laufenden Systems (verfügbarer RAM, CPU-Auslastung, offene TCP-Verbindungen usw.). Jede Zeile enthält die Werte für diese Spalten zu einem bestimmten Zeitpunkt.Mit Numpy, um den Durchschnittswert über Datensätze zu finden, mit einigen fehlenden Daten

Die Datensätze wurden während einzelner Durchläufe des gleichen Tests erfasst. Es ist nicht garantiert, dass die Anzahl der Zeilen in jedem Datensatz gleich ist (d. H. Einige Tests liefen länger als andere).

Ich möchte eine neue CSV-Datei erstellen, die den "durchschnittlichen" Wert für alle Datensätze für einen bestimmten Zeitversatz und eine bestimmte Spalte darstellt. Im Idealfall würden in einem Datensatz fehlende Werte ignoriert. Falls erforderlich, kann jedoch angenommen werden, dass fehlende Werte mit dem letzten bekannten Wert oder dem Durchschnitt bekannter Werte für diese Zeile übereinstimmen.

Ein vereinfachtes Beispiel:

+---------------+ +---------------+  +---------------+ 
|  Set 1  | |  Set 2  |  | Average | 
+---+-----+-----+ +---+-----+-----+  +---+-----+-----+ 
| t | A | B | | t | A | B |  | t | A | B | 
+---+-----+-----+ +---+-----+-----+  +---+-----+-----+ 
| 1 | 10 | 50 | | 1 | 12 | 48 |  | 1 | 11 | 49 | 
| 2 | 13 | 58 | | 2 | 7 | 60 |  | 2 | 10 | 59 | 
| 3 | 9 | 43 | | 3 | 17 | 51 | => | 3 | 13 | 47 | 
| 4 | 14 | 61 | | 4 | 12 | 57 |  | 4 | 13 | 59 | 
| : | : | : | | : | : | : |  | : | : | : | 
| 7 | 4 | 82 | | 7 | 10 | 88 |  | 7 | 7 | 86 | 
+---+-----+-----+ | 8 | 15 | 92 |  | 8 | 15 | 92 | 
        | 9 | 6 | 63 |  | 9 | 6 | 63 | 
        +---+-----+-----+  +---+-----+-----+ 

Ich bin neu in numpy, es hat für dieses Projekt speziell aufgegriffen. Was ist der beste Weg, dies zu tun? Für Datensätze mit der gleichen Anzahl von Zeilen (die ich gezwungen habe durch längere Daten Hacken setzen kurz), das tue ich gerade:

d_avg = sum(dsets)/float(len(dsets)) 

wo „dsets“ ist eine Liste des ndarrays die Daten von jeweils CSV-Datei. Das funktioniert gut, aber ich möchte die Daten der längeren Läufe nicht verwerfen.

Ich kann auch die kürzeren Läufe auf die längste Länge ändern, aber alle neuen Felder sind mit "NoneType" gefüllt. Spätere Operationen dann Fehler beim Hinzufügen (zum Beispiel) eines Floats und eines NoneType.

Irgendwelche Vorschläge?

+0

Ich denke, der Durchschnitt für Zeile 7 ist falsch –

+0

Ich wusste, ich würde eine dieser Zeilen verpassen! Aktualisiert. – Lemur

Antwort

3

Warum uns nicht nur numpy der ma (maskierte Array) Modul?

maxLen = reduce(lambda a,b : max(a, b.shape[0]), 
       dSets, 0) 
all = N.ma.zeros((maxLen,)+ dSets[0].shape[1:] + (len(dSets),), 
        dtype=float)  # set the dtype to whatever 
all.mask = True 
for i, set in enumerate(dSets): 
    all.mask[:len(set),...,i] = False 
    all[:len(set),...,i] = set 

mean = all.mean(axis=-1) 

Natürlich funktioniert dies nur, wenn Sie, dass die Zeit in jeder Reihe garantieren kann das gleiche über alle Arrays ist, dh festgelegt [i, 0] == gesetzt [j, 0] für alle i, j

+0

Auch wenn die Zeit nicht gleich ist, können Sie maskierte Arrays verwenden. Sie müssen nur schlauer sein beim Einrichten des maskierten Arrays, so dass die Daten für jedes Mal in derselben Zeile sind. – AFoglia

+0

Das funktioniert super. Vielen Dank! Eine Sache: Das reduce/lambda-Konstrukt kann fehlschlagen, wenn ein früher Wert am höchsten ist: 'int' hat keine Methode 'shape'. ersetzt durch: maxLen = max ([a.shape [0] für eine in dSets)) – Lemur

+0

Ja, du hast Recht, ich habe das Lambda aufgemotzt. Bearbeitet, um zu korrigieren. Prost! –

0

Nun, eine Möglichkeit wäre, über jede Zeile jedes Datensatzes zu iterieren und einen gegebenen Spaltenwert an ein Array anzuhängen, das in einem Wörterbuch gespeichert ist, wo der Zeitindex für seinen Schlüsselwert verwendet wird. Sie durchlaufen dann das Wörterbuch und ziehen den Durchschnitt für jedes dort gespeicherte Array.

Dies ist nicht besonders effizient - die andere Option besteht darin, das längste Array zu finden, darüber zu iterieren und die anderen Datasets abzufragen, um ein temporäres Array für den Durchschnitt zu erstellen. Auf diese Weise speichern Sie die sekundäre Iteration über das Wörterbuch.

+0

Ich hatte wirklich gehofft, dass numpy mit seiner Array-orientierten Effizienz eine Möglichkeit bieten würde, genau das zu tun. Sie haben Recht, ich muss auf die Methode zurückgreifen, die Sie vorschlagen, wenn es keine Operation dafür gibt. – Lemur

+0

Wenn Sie wirklich in numpy bleiben wollen, werfen Sie einen Blick auf maskierte Arrays hier: http://docs.scipy.org/doc/numpy/reference/maskedarray.generic.html –

+0

Es ist nicht so viel nummy selbst, dass ich wollen. Es ist sauberer, leicht verständlicher Code! Ehrlich gesagt würde ich Python für (hypothetisch) R fallen lassen, wenn das eine elegante Lösung bedeutete. Aber ich weiß noch weniger über R als über Numpy. Danke für den Tipp auf maskierte Arrays. Ich werde das überprüfen. – Lemur

2

Edit: Ich habe meine Methode überarbeitet, Scipy.nanmean für maskierte Arrays verzichten.

Wenn es unklar ist, was der Code an irgendeinem Punkt tut, versuchen Sie zuerst drucken Anweisungen in. Wenn es noch unklar ist, fühlen Sie sich frei zu fragen; Ich werde versuchen, mein Bestes zu erklären. Der Trick besteht darin, die t-Werte zusammenzuführen. (Das wurde getan mit numpy Arrays searchsorted Methode.)

mit numpy Spielen hat mich dazu gebracht zu glauben, dass seine Geschwindigkeitsvorteile kann nicht existieren, bis die Datensätze recht groß werden (vielleicht werden Sie mindestens 10.000 Zeilen pro Datensatz benötigen). Andernfalls ist eine reine Python-Lösung möglicherweise einfacher zu schreiben und schneller.

Hier sind die Spielzeug-Datensätze I verwendet:

% cat set1 
1, 10, 50 
2, 13, 58 
3,9,43 
4,14,61 
7, 4, 82 

% cat set2 
1, 12, 48 
2, 7, 60 
3,17,51 
4,12,57 
7,10,88 
8,15,92 
9,6,63 

Und hier ist der Code:

#!/usr/bin/env python 
import numpy as np 

filenames=('set1','set2') # change this to list all your csv files 
column_names=('t','a','b') 

# slurp the csv data files into a list of numpy arrays 
data=[np.loadtxt(filename, delimiter=',') for filename in filenames] 

# Find the complete list of t-values 
# For each elt in data, elt[a,b] is the value in the a_th row and b_th column 
t_values=np.array(list(reduce(set.union,(set(elt[:,0]) for elt in data)))) 
t_values.sort() 
# print(t_values) 
# [ 1. 2. 3. 4. 7. 8. 9.] 

num_rows=len(t_values) 
num_columns=len(column_names) 
num_datasets=len(filenames) 

# For each data set, we compute the indices of the t_values that are used. 
idx=[(t_values.searchsorted(data[n][:,0])) for n in range(num_datasets)] 

data2=np.ma.zeros((num_rows,num_columns,num_datasets)) 
for n in range(num_datasets): 
    data2[idx[n],:,n]=data[n][:,:] 
data2=np.ma.masked_equal(data2, 0) 
averages=data2.mean(axis=-1) 
print(averages) 
# [[1.0 11.0 49.0] 
# [2.0 10.0 59.0] 
# [3.0 13.0 47.0] 
# [4.0 13.0 59.0] 
# [7.0 7.0 85.0] 
# [8.0 15.0 92.0] 
# [9.0 6.0 63.0]] 
+0

Schön! Ich wusste nichts von loadtxt. Ich benutzte das 'tabular' Modul, das sich als Overkill herausstellte. Vielen Dank. – Lemur