2016-07-13 72 views
5

ho un dataframe panda che ha due colonne chiave e il valore, e il valore è sempre costituito da un numero di 8 cifre qualcosa comeSplit panda colonna dataframe basa sul numero di cifre

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

ora ho bisogno di prendere la colonna del valore e dividerlo sulle cifre attuali, in modo tale che il mio risultato è un nuovo frame di dati

>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 

non posso cambiare il formato dei dati in ingresso, la cosa più convenzionale ho pensato è stato quello di convertire il valore in una stringa e ciclo tramite ogni carattere numerico e inserendolo in un elenco, tuttavia lo sono oking per qualcosa di più elegante e veloce, gentile aiuto.

MODIFICA: l'input non è in stringa, è intero.

+0

Non avete questi elementi nella colonna 'value' come stringhe con cui cominciare? Oppure come potresti avere degli zeri in testa? – Divakar

+0

domanda modificata, il mio male con l'aggiunta di zeri iniziali nell'esempio –

risposta

3

Un approccio potrebbe essere:

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

Campione run -

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

dovrebbe essere dividere per 48 non -48? –

+0

@johnsmith Nah, sta ottenendo gli equivalenti ascii. Quindi, '0' diventa' 48' e '1' come' 49'. Quindi, per tornare indietro, sottraiamo 48. – Divakar

3

Supponendo che l'input è immagazzinato sotto forma di stringhe e tutti hanno la stessa lunghezza (8, come posato), poi i seguenti lavori:

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

questo dovrebbe funzionare:

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

enter image description here

+0

Impressionante grazie mille, funziona molto bene per il mio caso d'uso –

2

Un vettorizzati versione sarebbe:

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

Questo primo introduce spazi tra i caratteri e poi si divide. È solo una soluzione alternativa per poter utilizzare str.split (forse non necessario, non è sicuro). Ma è abbastanza veloce:

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 

Aggiornamento: Divakar's solution sembra essere il più veloce.