2016-07-05 15 views
0

Ich habe einen Pandas Datenrahmen voller Tuple (es könnte das gleiche mit Arrays sein) und ich würde gerne alle Spalten in noch mehr Spalten aufteilen (jedes Array oder Tupel hat das gleiche Länge). Nehmen wir dies als Beispiel:Mehrere/alle Spalten eines Pandas Datenrahmens teilen

df=pd.DataFrame([[(1,2),(3,4)],[(5,6),(7,8)]], df.columns=['column0', 'column1']) 

die Ausgänge:

column0 column1 
0 (1, 2) (3, 4) 
1 (5, 6) (7, 8) 

Ich habe versucht, hier über diese Lösung zu bauen (https://stackoverflow.com/a/16245109/4218755) Derivate aus dem Ausdruck mit:

df.textcol.apply(lambda s: pd.Series({'feature1':s+1, 'feature2':s-1}) 

wie

df.column0.apply(lambda s: pd.Series({'feature1':s[0], 'feature2':s[1]}) 

die Ausgänge:

 feature1 feature2 
0   1   2 
1   5   6 

Dies ist das gewünschte Verhalten. Also es funktioniert gut, aber wenn ich zufällig versuchen

df2=df[df.columns].apply(lambda s: pd.Series({'feature1':s[0], 'feature2':s[1]})) 

zu verwenden, dann DF2 ist:

  colonne0 colonne1 
feature1 (1, 2) (3, 4) 
feature2 (5, 6) (7, 8) 

, die offensichtlich falsch ist. Ich kann nicht auf df anwenden, es gibt das gleiche Ergebnis wie df2 aus.

Wie man solche Splitting-Technik auf einen ganzen Datenrahmen anwenden, und gibt es Alternativen? Dank

+0

gibt, gebe ich die Lösung mit bin näher: df2 = df.applymap (Lambda s: pd.Series ({ 'feat1': s [0], 'feat2': s [ 1]})). Es gibt aus; colonne0 colonne1 0 feat1 1 feat2 2 dtype: int64 feat1 3 feat2 4 dtype: int64 1 feat1 5 feat2 6 dtype: int64 feat1 7 feat2 8 dtype: int64 aber ich bin mit diesem Index stecken (und df2.reset_index funktioniert nicht) –

Antwort

1

Sie könnten den Datenrahmen-Wert als NumPy Array extrahieren, verwenden IT.chain.from_iterable die Ints aus den Tupeln zu extrahieren und dann neu zu gestalten und das Array in einen neuen Datenrahmen wieder aufbauen :

import itertools as IT 
import numpy as np 
import pandas as pd 
df = pd.DataFrame([[(1,2),(3,4)],[(5,6),(7,8)]], columns=['column0', 'column1']) 
arr = df.values 
arr = np.array(list(IT.chain.from_iterable(arr))).reshape(len(df), -1) 
result = pd.DataFrame(arr) 

ergibt

0 1 2 3 
0 1 2 3 4 
1 5 6 7 8 

By the way, haben Sie vielleicht in einer XY-Falle getappt - du bist für X fragen, wann Sie wirklich für Y suchen sollte. Anstatt df in result zu transformieren, könnte es einfacher sein, den gewünschten Datenrahmen, result, von der ursprünglichen Datenquelle zu erstellen.

Zum Beispiel, wenn die Originaldaten eine Liste von Listen von Tupeln:

data = [[(1,2),(3,4)],[(5,6),(7,8)]] 

Dann wird der gewünschte Datenrahmen gebaut werden kann

df = pd.DataFrame(np.array(data).reshape(2,-1)) 
# 0 1 2 3 
# 0 1 2 3 4 
# 1 5 6 7 8 

Verwendung Wenn Sie nicht-NumPy-native Daten Typen in Ihrem Dataframe (wie Tupel), sind Sie dazu verdammt, mindestens eine Python-Schleife zu verwenden, um die Ints aus den Tupeln zu extrahieren.(Ich bin in Bezug auf Dinge wie df.apply(func) und list(IT.chain.from_iterable(arr)) im Wesentlichen Schleife Python, da sie bei Python-Loop-Geschwindigkeit arbeiten.)

+0

Danke für Ihre Hilfe! Eigentlich glaubte ich, dass applymap und apply irgendeine Art von vektorisierten Operationen ausführte, deshalb habe ich es vorgezogen, mit den Tupeln df zu beginnen, anstatt das ursprüngliche df, aus dem es gemacht wurde, wiederzuverwenden (was ziemlich einfach zu konvertieren war). Schließlich habe ich selbst etwas auf der Linie der Erstellung von 2 Kopien verwendet, dann mit splitframe1.applymap (Lambda x: x [0]) und splitframe2.applymap (Lambda x: x [1]) und merge nach dem Umbenennen von Spalten. In jedem Fall, Ihre Lösung und zusätzliche Infos sind es wert, Ihre Antwort als die beste zu akzeptieren. –

1

IIUC Sie verwenden können:

df=pd.DataFrame([[(1,2),(3,4)],[(5,6),(7,8)]], columns=['column0', 'column1']) 
print (df) 
    column0 column1 
0 (1, 2) (3, 4) 
1 (5, 6) (7, 8) 


for col in df.columns: 
    df[col]=df[col].apply(lambda s: pd.Series({'feature1':s[0], 'feature2':s[1]})) 

print (df) 
    column0 column1 
0  1  3 
1  5  7 
+0

Danke für die Idee. Eigentlich würde ich 2,6 in einer zweiten Spalte und 4,8 in einer vierten Spalte erwarten. Ich verstehe nicht, warum dein Code das nicht ausgibt, ich habe das erwartet, indem ich es gelesen habe. Ich habe es auch nicht präzisiert, aber ich möchte Schleifen möglichst vermeiden (ich halte die Idee für wertvoll, dachte, wenn keine Alternative verfügbar ist). –

1

Sie über jede Spalte durchlaufen können Sie die neuen Spalten auf Ihre Datenrahmen aufgeteilt und zugewiesen werden sollen:

import pandas as pd 

df=pd.DataFrame([ [ (1,2), (3,4)], 
        [ (5,6), (7,8)] ], columns=['column0', 'column1']) 

# empty DataFrame 
df2 = pd.DataFrame() 

for col in df.columns: 
    # names of new columns 
    feature_columns = [ "{col}_feature1".format(col=col), "{col}_feature2".format(col=col) ] 
    # split current column 
    df2[ feature_columns ] = df[ col ].apply(lambda s: pd.Series({ feature_columns[0]: s[0], 
                    feature_columns[1]: s[1]})) 

print df2 

die

column0_feature1 column0_feature2 column1_feature1 column2_feature2 
0    1     2     3     4 
1    5     6     7     8 
+0

Sehr schlau, danke. Es wird nicht die akzeptierte Antwort sein, weil die Itertools Schleifen besser zu vermeiden scheinen, aber es scheint wertvoll. –

Verwandte Themen