2016-07-13 19 views
5

ich Pandas Datenrahmen haben, die zwei Spalten Schlüssel und Wert hat, und der Wert besteht immer aus einem 8-stellige Zahl etwas wieSplit Pandas Datenrahmen Spalte basierend auf der Anzahl der Ziffern

>df1 
key value 
10 10000100 
20 10000000 
30 10100000 
40 11110000 

Jetzt muss ich die nehmen Spaltenwert und teilen sie es auf den Ziffern vorhanden ist, so dass mein Ergebnis ein neuer Datenrahmen

>df_res 
key 0 1 2 3 4 5 6 7 
10 1 0 0 0 0 1 0 0 
20 1 0 0 0 0 0 0 0 
30 1 0 1 0 0 0 0 0 
40 1 1 1 1 0 0 0 0 

ich nicht das Eingangsdatenformat ändern können, die meisten herkömmlichen, was ich dachte, war der Wert in einen String und Schleife zu konvertieren durch jede Ziffer char und lege es in eine Liste, aber bin lo für etwas eleganteres und schnelleres bitten, freundlicherweise helfen.

EDIT: Die Eingabe ist nicht in Zeichenfolge, es ist Integer.

+0

Haben Sie diese Elemente in der Spalte "value" nicht als Strings? Oder wie könnten Sie führende Nullen darin haben? – Divakar

+0

Frage bearbeitet, meine schlechte mit führenden Nullen in dem Beispiel –

Antwort

3

Ein Ansatz könnte sein -

arr = df.value.values.astype('S8') 
df = pd.DataFrame(np.fromstring(arr, dtype=np.uint8).reshape(-1,8)-48) 

Probelauf -

In [58]: df 
Out[58]: 
    key  value 
0 10 10000100 
1 20 10000000 
2 30 10100000 
3 40 11110000 

In [59]: arr = df.value.values.astype('S8') 

In [60]: pd.DataFrame(np.fromstring(arr, dtype=np.uint8).reshape(-1,8)-48) 
Out[60]: 
    0 1 2 3 4 5 6 7 
0 1 0 0 0 0 1 0 0 
1 1 0 0 0 0 0 0 0 
2 1 0 1 0 0 0 0 0 
3 1 1 1 1 0 0 0 0 
+0

sollte durch 48 nicht -48 dividieren? –

+0

@johnsmith Nah, es bekommt Ascii-Äquivalente. So wird "0" zu "48" und "1" zu "49". Um also zurück zu kommen, subtrahieren wir 48. – Divakar

3

Angenommen, Ihre Eingabe wird als Strings gespeichert und alle haben die gleiche Länge (8, wie gestellt), dann sind die folgenden Werke:

df1 = pd.concat([df1,pd.DataFrame(columns=range(8))]) 
df1[list(range(8))] = df1['Value'].apply(lambda x: pd.Series(list(str(x)),index=range(8))) 
9

Diese Arbeit sollte:

df.value.astype(str).apply(list).apply(pd.Series).astype(int) 

enter image description here

+0

Awesome vielen Dank, funktioniert sehr gut für meinen Anwendungsfall –

2

Eine vektorisierte Version wäre:

df['value'].astype(str).str.join(' ').str.split(' ', expand=True) 

Das erste führt Räume zwischen Zeichen und teilt sich dann. Es ist nur ein Workaround, um str.split verwenden zu können (vielleicht nicht notwendig, nicht sicher). Aber es ist ziemlich schneller:

df = pd.DataFrame({'value': np.random.randint(10**7, 10**8, 10**4)}) 

%timeit df['value'].astype(str).str.join(' ').str.split(' ', expand=True) 
10 loops, best of 3: 25.5 ms per loop 

%timeit df.value.astype(str).apply(list).apply(pd.Series).astype(int) 
1 loop, best of 3: 1.27 s per loop 

%timeit df['value'].apply(lambda x: pd.Series(list(str(x)),index=range(8))) 
1 loop, best of 3: 1.33 s per loop 


%%timeit 
arr = df.value.values.astype('S8') 
pd.DataFrame(np.fromstring(arr, dtype=np.uint8).reshape(-1,8)-48) 

1000 loops, best of 3: 1.14 ms per loop 

Update: Divakar's solution scheint die schnellste zu sein.

Verwandte Themen