2015-04-09 11 views
28

Mam dataframe pandy (jest to tylko mały kawałek)jak podzielić kolumnę krotek w ramce danych pandy?

>>> d1 
    y norm test y norm train len(y_train) len(y_test) \ 
0 64.904368 116.151232   1645   549 
1 70.852681 112.639876   1645   549 

            SVR RBF \ 
0 (35.652207342877873, 22.95533537448393) 
1 (39.563683797747622, 27.382483096332511) 

             LCV \ 
0 (19.365430594452338, 13.880062435173587) 
1 (19.099614489458364, 14.018867136617146) 

            RIDGE CV \ 
0 (4.2907610988480362, 12.416745648065584) 
1 (4.18864306788194, 12.980833914392477) 

             RF \ 
0 (9.9484841581029428, 16.46902345373697) 
1 (10.139848213735391, 16.282141345406522) 

              GB \ 
0 (0.012816232716538605, 15.950164822266007) 
1 (0.012814519804493328, 15.305745202851712) 

              ET DATA 
0 (0.00034337162272515505, 16.284800366214057) j2m 
1 (0.00024811554516431878, 15.556506191784194) j2m 
>>> 

Chcę podzielić wszystkie kolumny, które zawierają krotki. Na przykład chcę zamienić kolumnę LCV na kolumny LCV-a i LCV-b.

Jak mogę to zrobić?

EDYTOWANIE:

Proponowane rozwiązanie nie działa, dlaczego?

>>> d1['LCV'].apply(pd.Series) 
              0 
0 (19.365430594452338, 13.880062435173587) 
1 (19.099614489458364, 14.018867136617146) 
>>> 

EDIT: To wydaje się działać

>>> d1['LCV'].apply(eval).apply(pd.Series) 
      0   1 
0 19.365431 13.880062 
1 19.099614 14.018867 
>>> 
+0

Czy możesz podać jakiś powtarzalny kod, który pokazuje problem? A jakiej wersji pandy używasz? – joris

+0

Wersja to "0.15.1". Właśnie czytam csv z 'pd.read_csv'. Może to czyta wiersze jako ciąg, a nie jako krotki – Donbeo

+0

@joris być może rozwiązałem – Donbeo

Odpowiedz

50

Można to zrobić przez apply(pd.Series) na tej kolumnie:

In [13]: df = pd.DataFrame({'a':[1,2], 'b':[(1,2), (3,4)]}) 

In [14]: df 
Out[14]: 
    a  b 
0 1 (1, 2) 
1 2 (3, 4) 

In [16]: df['b'].apply(pd.Series) 
Out[16]: 
    0 1 
0 1 2 
1 3 4 

In [17]: df[['b1', 'b2']] = df['b'].apply(pd.Series) 

In [18]: df 
Out[18]: 
    a  b b1 b2 
0 1 (1, 2) 1 2 
1 2 (3, 4) 3 4 

To działa, ponieważ to sprawia, że ​​z każdej krotki serii, który jest następnie postrzegany jako rząd ramki danych.

+0

jest sposób na automatyzację ze względu na dużą liczbę kolumn? – Donbeo

+0

Nie bezpośrednio myślę. Ale możesz łatwo napisać dla niego funkcję za pomocą powyższego kodu (+ usunięcie oryginalnego) – joris

+0

czekaj, że to nie działa dla mnie. Aktualizuję pytanie – Donbeo

15

Na znacznie większych zbiorów danych, stwierdziliśmy, że .apply() jest kilka rzędów wolniejsze niż pd.DataFrame(df['b'].values.tolist())

Ten problem wydajność została zamknięta w GitHub, choć nie zgadzam się z tą decyzją:

https://github.com/pandas-dev/pandas/issues/11615

+3

'pd.DataFrame (df ['b']. Tolist())' bez '.values' również działa dobrze. (I dzięki, twoje rozwiązanie jest _ dużo szybsze niż '.apply()') – Swier

+0

Martwiłem się o przechwytywanie indeksu, stąd wyraźne użycie wartości .values. – denfromufa

3

ja wiadomo, że jest to od jakiegoś czasu, ale zastrzeżenie drugiego rozwiązania:

pd.DataFrame (df ['b']. values.tolist())

jest to, że wyraźnie odrzucić indeks i dodać w domyślnej indeksu sekwencyjnym, natomiast zaakceptowane odpowiedź

zastosowania (pd.Series)

nie będzie, ponieważ wynik zastosowania zachowa indeks wiersza. Chociaż zamówienie jest początkowo zachowane z oryginalnej tablicy, pandy spróbują dopasować wskazania z dwóch ramek danych.

Może to być bardzo ważne, jeśli próbujesz ustawić wiersze w indeksowanej numerycznie tablicy, a pandy automatycznie spróbują dopasować indeks nowej tablicy do starej i spowodować pewne zakłócenia w porządku.

Lepsze rozwiązanie hybrydowe będzie ustawić wskaźnik pierwotnego dataframe na nowy, to

pd.DataFrame (DF [ 'b']. Values.tolist() Indeks = DF. indeks)

Który zachowa prędkość korzystania z drugiej metody, zapewniając, że zamówienie i indeksowanie zostanie zachowane na wyniku.