2016-07-13 14 views
5

Mam dataframe pandy, która ma dwie kolumny klucz i wartość, a wartość składa się zawsze z numerem 8 cyfr coś podobnegodzielona pandy kolumna dataframe na podstawie liczby cyfr

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

Teraz muszę wziąć kolumna wartość i podzielić ją na cyfry obecnych, tak że mój wynik jest nowa ramka danych

>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 

nie mogę zmienić format danych wejściowych, najbardziej konwencjonalny rzeczą, myślałem, że do konwersji wartości na ciąg i pętli poprzez każdą cyfrę char i umieścić ją na liście, jednak jestem lo oking na coś bardziej eleganckiego i szybszego, życzliwa pomoc.

EDYCJA: Wejście nie jest w łańcuchu, jest liczbą całkowitą.

+0

Nie masz tych elementów w kolumnie "wartość" jako ciągów na początek? Albo jak możesz mieć w tym miejscu wiodące zera? – Divakar

+0

pytanie edytowane, moje złe z dodaniem zer wiodących w przykładzie –

Odpowiedz

3

Jednym z podejść może być -

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

Sample 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

należy podzielić przez 48 nie -48? –

+0

@johnsmith Nah, jego uzyskanie ascii odpowiedników. Tak więc '0' zmienia się w' 48' i '1' w' 49'. Tak więc, aby odzyskać ints, odejmujemy 48. – Divakar

3

Zakładając, że wejście jest przechowywane jako ciągi i wszystkie mają taką samą długość (8, jak pozowała), wówczas następujące prace:

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

To powinno działać:

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

enter image description here

+0

Niesamowite dzięki bardzo, działa bardzo dobrze do mojego przypadku użycia –

2

Vectorized wersja będzie:

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

Ten pierwszy wprowadza odstępy między znakami, a następnie dzieli. Jest to tylko obejście, aby móc użyć str.split (może nie jest to konieczne, nie jestem pewien). Ale jest to znacznie szybsze:

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 

Aktualizacja: Divakar's solution wydaje się być najszybsza.