Ich habe einen Datenrahmen, in dem einige Zellen Listen mit mehreren Werten enthalten. Anstatt mehrere Werte in einer Zelle zu speichern, möchte ich den Datenrahmen so erweitern, dass jedes Element in der Liste eine eigene Zeile erhält (mit denselben Werten in allen anderen Spalten). Also wenn ich habe:
import pandas as pd
import numpy as np
df = pd.DataFrame(
{'trial_num': [1, 2, 3, 1, 2, 3],
'subject': [1, 1, 1, 2, 2, 2],
'samples': [list(np.random.randn(3).round(2)) for i in range(6)]
}
)
df
Out[10]:
samples subject trial_num
0 [0.57, -0.83, 1.44] 1 1
1 [-0.01, 1.13, 0.36] 1 2
2 [1.18, -1.46, -0.94] 1 3
3 [-0.08, -4.22, -2.05] 2 1
4 [0.72, 0.79, 0.53] 2 2
5 [0.4, -0.32, -0.13] 2 3
Wie konvertiere ich in Langform, zB:
subject trial_num sample sample_num
0 1 1 0.57 0
1 1 1 -0.83 1
2 1 1 1.44 2
3 1 2 -0.01 0
4 1 2 1.13 1
5 1 2 0.36 2
6 1 3 1.18 0
# etc.
Der Index ist nicht wichtig, es ist in Ordnung, vorhandene Spalten als Index festzulegen, und die endgültige Reihenfolge ist nicht wichtig.
df.explode('samples')
lösen.explode
kann vorerst nur das Explodieren einer Spalte unterstützen.Antworten:
Ergebnis:
PS hier finden Sie möglicherweise eine etwas allgemeinere Lösung
UPDATE: einige Erklärungen: IMO Der einfachste Weg, diesen Code zu verstehen, besteht darin, ihn Schritt für Schritt auszuführen:
In der folgenden Zeile wiederholen wir die Werte in einer Spalte
N
, wobeiN
- die Länge der entsprechenden Liste ist:Dies kann für alle Spalten mit Skalarwerten verallgemeinert werden:
Mit können
np.concatenate()
wir alle Werte in derlist
Spalte (samples
) reduzieren und einen 1D-Vektor erhalten:alles zusammen:
Die Verwendung
pd.DataFrame()[df.columns]
garantiert, dass wir Spalten in der ursprünglichen Reihenfolge auswählen ...quelle
lst_col
vollständig enthalten ist. Um diese Zeilen beizubehalten undlst_col
mit ihnen zu füllennp.nan
, können Sie diesdf[lst_col] = df[lst_col].apply(lambda x: x if len(x) > 0 else [np.nan])
vor der Verwendung dieser Methode tun . Offensichtlich.mask
werden keine Listen zurückgegeben, daher die.apply
.Ein bisschen länger als ich erwartet hatte:
Wenn Sie einen sequentiellen Index wünschen, können Sie ihn
reset_index(drop=True)
auf das Ergebnis anwenden .Update :
quelle
df.apply(lambda x: pd.Series(x['samples']),axis=1)
mitdf.samples.apply(pd.Series)
.df.explode()
wie hierPandas> = 0,25
Serien- und DataFrame-Methoden definieren eine
.explode()
Methode, die Listen in separate Zeilen auflöst . Weitere Informationen finden Sie im Abschnitt "Dokumente" zum Auflösen einer listenartigen Spalte .Beachten Sie, dass dies auch gemischte Spalten von Listen und Skalaren sowie leere Listen und NaNs entsprechend behandelt (dies ist ein Nachteil von
repeat
Lösungen auf Basis ).Beachten Sie jedoch, dass dies (vorerst)
explode
nur für eine einzelne Spalte funktioniert .PS: Wenn Sie eine Spalte mit Zeichenfolgen auflösen möchten , müssen Sie zuerst ein Trennzeichen aufteilen und dann verwenden
explode
. Siehe diese (sehr) verwandte Antwort von mir.quelle
Sie können auch verwenden
pd.concat
undpd.melt
dafür:Zuletzt können Sie bei Bedarf die ersten drei Spalten nach der ersten sortieren.
quelle
Als ich versuchte, die Lösung von Roman Pekar Schritt für Schritt durchzuarbeiten, um sie besser zu verstehen, entwickelte ich eine eigene Lösung, mit der
melt
einige verwirrende Stapel- und Indexrücksetzungen vermieden werden. Ich kann nicht sagen, dass es offensichtlich eine klarere Lösung ist:Ausgabe (natürlich können wir jetzt die ursprüngliche Beispielspalte löschen):
quelle
Für diejenigen, die nach einer Version der Antwort von Roman Pekar suchen, die die manuelle Benennung von Spalten vermeidet:
quelle
Ich fand, der einfachste Weg war:
samples
Spalte in einen DataFrameHier gezeigt:
Es ist erwähnenswert, dass dies möglicherweise nur funktioniert hat, weil jeder Versuch die gleiche Anzahl von Proben hat (3). Für Versuche mit verschiedenen Stichprobengrößen kann etwas Klügeres erforderlich sein.
quelle
Sehr späte Antwort, aber ich möchte Folgendes hinzufügen:
Eine schnelle Lösung mit Vanilla Python, die sich auch um die
sample_num
Spalte im Beispiel von OP kümmert . Bei meinem eigenen großen Datensatz mit über 10 Millionen Zeilen und einem Ergebnis mit 28 Millionen Zeilen dauert dies nur etwa 38 Sekunden. Die akzeptierte Lösung bricht mit dieser Datenmenge vollständig zusammen und führtmemory error
auf meinem System zu einer Lösung mit 128 GB RAM.quelle
Auch sehr spät, aber hier ist eine Antwort von Karvy1, die für mich gut funktioniert hat, wenn Sie keine Pandas> = 0.25 Version haben: https://stackoverflow.com/a/52511166/10740287
Für das obige Beispiel können Sie schreiben:
Geschwindigkeitstest:
1,33 ms ± 74,8 µs pro Schleife (Mittelwert ± Standardabweichung von 7 Läufen, jeweils 1000 Schleifen)
4,9 ms ± 189 µs pro Schleife (Mittelwert ± Standardabweichung von 7 Läufen, jeweils 100 Schleifen)
1,38 ms ± 25 µs pro Schleife (Mittelwert ± Standardabweichung von 7 Läufen, jeweils 1000 Schleifen)
quelle
Versuchen Sie dies in der Version pandas> = 0.25
quelle
.str.split(',')
weilPrices
ist schon eine Liste.