webentwicklung-frage-antwort-db.com.de

Berechnen Sie den Durchschnitt aller x Zeilen in einer Tabelle und erstellen Sie eine neue Tabelle

Ich habe eine lange Datentabelle (~ 200 Zeilen mal 50 Spalten) und ich muss einen Code erstellen, der die Mittelwerte aller zwei Zeilen und für jede Spalte in der Tabelle berechnen kann, wobei die endgültige Ausgabe eine neue Tabelle des Mittelwerts ist Werte. Das ist natürlich verrückt in Excel! Ich benutze Python3 und kenne ähnliche Fragen: hier , hier und hier . Aber nichts davon hilft, da ich eleganten Code brauche, um mit mehreren Spalten zu arbeiten und eine organisierte Datentabelle zu erzeugen. Meine ursprüngliche Datentabelle wurde übrigens mit Pandas importiert und ist als Dataframe definiert, konnte jedoch bei Pandas keine einfache Methode finden. Hilfe wird sehr geschätzt.

Ein Beispiel für die Tabelle (kurze Version) ist:

a   b   c   d
2   50  25  26
4   11  38  44
6   33  16  25
8   37  27  25
10  28  48  32
12  47  35  45
14  8   16  7
16  12  16  30
18  22  39  29
20  9   15  47

Erwartete mittlere Tabelle: 

a    b     c     d
3   30.5  31.5  35
7   35    21.5  25
11  37.5  41.5  38.5
15  10    16    18.5
19  15.5  27    38
13
Gnu

Sie können eine künstliche Gruppe mit df.index//2 (oder wie @DSM darauf hinweisen, mit np.arange(len(df))//2 - so dass sie für alle Indizes funktioniert) erstellen und dann groupby verwenden:

df.groupby(np.arange(len(df))//2).mean()
Out[13]: 
      a     b     c     d
0   3.0  30.5  31.5  35.0
1   7.0  35.0  21.5  25.0
2  11.0  37.5  41.5  38.5
3  15.0  10.0  16.0  18.5
4  19.0  15.5  27.0  38.0
18
ayhan

Die Methode von NumPythonic wäre, die Elemente als NumPy-Array mit df.values zu extrahieren, dann in ein 3D-Array mit 2-Elementen entlang von axis=1 und 4 zusammen mit axis=2 umzuwandeln und die Durchschnittsreduktion entlang von axis=1 durchzuführen und schließlich wie in einem Datenrahmen zurück zu konvertieren.

pd.DataFrame(df.values.reshape(-1,2,df.shape[1]).mean(1))

Wie sich herausstellt, können Sie das sehr effiziente Werkzeug von NumPy einführen: np.einsum , um diesen average-reduction als Kombination aus sum-reduction und scaling-down auszuführen, wie so -

pd.DataFrame(np.einsum('ijk->ik',df.values.reshape(-1,2,df.shape[1]))/2.0)

Bitte beachten Sie, dass die vorgeschlagenen Ansätze davon ausgehen, dass die Anzahl der Zeilen durch 2 teilbar ist. 

Um die Spaltennamen beizubehalten, müssen Sie auch als noted by @DSMcolumns=df.columns hinzufügen, wenn Sie wieder in Dataframe konvertieren, d. H.

pd.DataFrame(...,columns=df.columns)

Probelauf -

>>> df
    0   1   2   3
0   2  50  25  26
1   4  11  38  44
2   6  33  16  25
3   8  37  27  25
4  10  28  48  32
5  12  47  35  45
6  14   8  16   7
7  16  12  16  30
8  18  22  39  29
9  20   9  15  47
>>> pd.DataFrame(df.values.reshape(-1,2,df.shape[1]).mean(1))
    0     1     2     3
0   3  30.5  31.5  35.0
1   7  35.0  21.5  25.0
2  11  37.5  41.5  38.5
3  15  10.0  16.0  18.5
4  19  15.5  27.0  38.0
>>> pd.DataFrame(np.einsum('ijk->ik',df.values.reshape(-1,2,df.shape[1]))/2.0)
    0     1     2     3
0   3  30.5  31.5  35.0
1   7  35.0  21.5  25.0
2  11  37.5  41.5  38.5
3  15  10.0  16.0  18.5
4  19  15.5  27.0  38.0

Laufzeittests -

Testen Sie in diesem Abschnitt alle drei bisher aufgeführten Ansätze, um das Leistungsproblem zu lösen, einschließlich @ayhan's solution with groupby .

In [24]: A = np.random.randint(0,9,(200,50))

In [25]: df = pd.DataFrame(A)

In [26]: %timeit df.groupby(df.index//2).mean() # @ayhan's solution
1000 loops, best of 3: 1.61 ms per loop

In [27]: %timeit pd.DataFrame(df.values.reshape(-1,2,df.shape[1]).mean(1))
1000 loops, best of 3: 317 µs per loop

In [28]: %timeit pd.DataFrame(np.einsum('ijk->ik',df.values.reshape(-1,2,df.shape[1]))/2.0)
1000 loops, best of 3: 266 µs per loop
6
Divakar
df.set_index(np.arange(len(df)) // 2).mean(level=0)
4
piRSquared

Sie können dieses Problem mithilfe von pd.rolling() lösen, um einen rollenden Durchschnitt zu erstellen, und dann einfach jedes zweite Element mithilfe von iloc zu greifen. 

df = df.rolling(2).mean() 
df = df.iloc[::2, :]

Beachten Sie, dass die erste Beobachtung fehlt (d. H. Das Rollen beginnt oben). 

1
seeiespi