Als Benutzer mit beiden Rund habe pythonich diese Art von Frage ein paar Mal gesehen.
In R haben sie die eingebaute Funktion aus dem tidyraufgerufenen Paket unnest. In Python( pandas) gibt es jedoch keine integrierte Funktion für diese Art von Frage.
Ich weiß, dass objectSpalten es typeimmer schwierig machen, Daten mit einer pandasFunktion zu konvertieren . Als ich die Daten so erhielt, fiel mir als erstes ein, die Spalten zu "glätten" oder zu entfernen.
Ich benutze pandasund pythonFunktionen für diese Art von Frage. Wenn Sie sich Sorgen über die Geschwindigkeit der oben genannten Lösungen machen, überprüfen Sie die Antwort von user3483203, da er verwendet numpyund die meiste Zeit numpyschneller ist. Ich empfehle Cpythonund numbawenn Geschwindigkeit in Ihrem Fall wichtig ist.
Methode 0 [pandas> = 0.25]
Ab pandas 0.25 können Sie die folgende Funktion verwenden , wenn Sie nur eine Spalte auflösen explodemüssen:
df.explode('B')
A B
0 1 1
1 1 2
0 2 1
1 2 2
Methode 1
apply + pd.Series (leicht zu verstehen, aber in Bezug auf die Leistung nicht empfohlen.)
df.set_index('A').B.apply(pd.Series).stack().reset_index(level=0).rename(columns={0:'B'})
Out[463]:
A B
0 1 1
1 1 2
0 2 1
1 2 2
Methode 2
Verwenden repeatmit DataFrameKonstruktor, erstellen Sie Ihren Datenrahmen (gut an Leistung, nicht gut an mehreren Spalten)
df=pd.DataFrame({'A':df.A.repeat(df.B.str.len()),'B':np.concatenate(df.B.values)})
df
Out[465]:
A B
0 1 1
0 1 2
1 2 1
1 2 2
Methode 2.1
zum Beispiel neben A haben wir A.1 ..... An Wenn wir die obige Methode ( Methode 2 ) noch verwenden , ist es für uns schwierig, die Spalten einzeln neu zu erstellen.
Lösung: joinoder mergemit dem indexNach 'unnest' die einzelnen Spalten
s=pd.DataFrame({'B':np.concatenate(df.B.values)},index=df.index.repeat(df.B.str.len()))
s.join(df.drop('B',1),how='left')
Out[477]:
B A
0 1 1
0 2 1
1 1 2
1 2 2
Wenn Sie die Spaltenreihenfolge genau wie zuvor benötigen, fügen Sie sie reindexam Ende hinzu.
s.join(df.drop('B',1),how='left').reindex(columns=df.columns)
Methode 3
erstellt das neulist
pd.DataFrame([[x] + [z] for x, y in df.values for z in y],columns=df.columns)
Out[488]:
A B
0 1 1
1 1 2
2 2 1
3 2 2
Wenn mehr als zwei Spalten vorhanden sind, verwenden Sie
s=pd.DataFrame([[x] + [z] for x, y in zip(df.index,df.B) for z in y])
s.merge(df,left_on=0,right_index=True)
Out[491]:
0 1 A B
0 0 1 1 [1, 2]
1 0 2 1 [1, 2]
2 1 1 2 [1, 2]
3 1 2 2 [1, 2]
Methode 4
mit reindex oderloc
df.reindex(df.index.repeat(df.B.str.len())).assign(B=np.concatenate(df.B.values))
Out[554]:
A B
0 1 1
0 1 2
1 2 1
1 2 2
#df.loc[df.index.repeat(df.B.str.len())].assign(B=np.concatenate(df.B.values))
Methode 5,
wenn die Liste nur eindeutige Werte enthält:
df=pd.DataFrame({'A':[1,2],'B':[[1,2],[3,4]]})
from collections import ChainMap
d = dict(ChainMap(*map(dict.fromkeys, df['B'], df['A'])))
pd.DataFrame(list(d.items()),columns=df.columns[::-1])
Out[574]:
B A
0 1 1
1 2 1
2 3 2
3 4 2
Methode 6
mit numpyhoher Leistung:
newvalues=np.dstack((np.repeat(df.A.values,list(map(len,df.B.values))),np.concatenate(df.B.values)))
pd.DataFrame(data=newvalues[0],columns=df.columns)
A B
0 1 1
1 1 2
2 2 1
3 2 2
Methode 7
mit Basisfunktion itertools cycleund chain: Reine Python-Lösung nur zum Spaß
from itertools import cycle,chain
l=df.values.tolist()
l1=[list(zip([x[0]], cycle(x[1])) if len([x[0]]) > len(x[1]) else list(zip(cycle([x[0]]), x[1]))) for x in l]
pd.DataFrame(list(chain.from_iterable(l1)),columns=df.columns)
A B
0 1 1
1 1 2
2 2 1
3 2 2
Verallgemeinern auf mehrere Spalten
df=pd.DataFrame({'A':[1,2],'B':[[1,2],[3,4]],'C':[[1,2],[3,4]]})
df
Out[592]:
A B C
0 1 [1, 2] [1, 2]
1 2 [3, 4] [3, 4]
Self-Def-Funktion:
def unnesting(df, explode):
idx = df.index.repeat(df[explode[0]].str.len())
df1 = pd.concat([
pd.DataFrame({x: np.concatenate(df[x].values)}) for x in explode], axis=1)
df1.index = idx
return df1.join(df.drop(explode, 1), how='left')
unnesting(df,['B','C'])
Out[609]:
B C A
0 1 1 1
0 2 2 1
1 3 3 2
1 4 4 2
Spaltenweise Unnesting
Alles oben genanntes Verfahren spricht über das vertikale Auseinanderschieben und explodiert, wenn Sie tun müssen , um die Liste aufwenden horizontal , Check mit pd.DataFrameKonstruktor
df.join(pd.DataFrame(df.B.tolist(),index=df.index).add_prefix('B_'))
Out[33]:
A B C B_0 B_1
0 1 [1, 2] [1, 2] 1 2
1 2 [3, 4] [3, 4] 3 4
Aktualisierte Funktion
def unnesting(df, explode, axis):
if axis==1:
idx = df.index.repeat(df[explode[0]].str.len())
df1 = pd.concat([
pd.DataFrame({x: np.concatenate(df[x].values)}) for x in explode], axis=1)
df1.index = idx
return df1.join(df.drop(explode, 1), how='left')
else :
df1 = pd.concat([
pd.DataFrame(df[x].tolist(), index=df.index).add_prefix(x) for x in explode], axis=1)
return df1.join(df.drop(explode, 1), how='left')
Testausgabe
unnesting(df, ['B','C'], axis=0)
Out[36]:
B0 B1 C0 C1 A
0 1 2 1 2 1
1 3 4 3 4 2