pandalar veri çerçevesinde demet sütunu nasıl bölünür?


91

Pandalar veri çerçevem ​​var (bu sadece küçük bir parça)

>>> 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  
>>> 

Tuple içeren tüm sütunları bölmek istiyorum. Mesela ben sütunu değiştirmek istiyor LCVsütunlu LCV-ave LCV-b.

Bunu nasıl yapabilirim?

Yanıtlar:


167

Bunu pd.DataFrame(col.tolist())o sütunda yaparak yapabilirsiniz :

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

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

In [4]: df['b'].tolist()                                                                                                                                                        
Out[4]: [(1, 2), (3, 4)]

In [5]: pd.DataFrame(df['b'].tolist(), index=df.index)                                                                                                                                          
Out[5]: 
   0  1
0  1  2
1  3  4

In [6]: df[['b1', 'b2']] = pd.DataFrame(df['b'].tolist(), index=df.index)                                                                                                                       

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

Not: Daha önceki bir sürümde, bu cevabın df['b'].apply(pd.Series)yerine kullanılması önerilir pd.DataFrame(df['b'].tolist(), index=df.index). Bu da işe yarıyor (çünkü daha sonra bir veri çerçevesinin satırı olarak görülen her bir diziyi bir Seri yapıyor), ancak tolistburadaki diğer yanıtlarda belirtildiği gibi daha yavaştır / sürümden daha fazla bellek kullanır (@denfromufa sayesinde) .
En görünür yanıtın en iyi çözüme sahip olduğundan emin olmak için bu yanıtı güncelledim.


2
çok sayıda sütun nedeniyle bunu otomatikleştirmenin bir yolu var mı?
Donbeo

Doğrudan değil sanırım. Ancak yukarıdaki kodu kullanarak (+ orijinali kaldırarak) bunun için kolayca bir işlev yazabilirsiniz
joris

Çok sayıda sütununuz varsa, verilerinizi 'düzenlemeyi' düşünebilirsiniz: vita.had.co.nz/papers/tidy-data.html Bunu eritme işlevini kullanarak yapabilirsiniz.
Axel

.apply (pd.Series) iyi çalışıyor, ancak büyük veri kümeleri için çok fazla bellek tüketiyor ve Bellek Hatasına neden olabilir
Yury Wallet

27

Çok daha büyük veri kümelerinde, bunun .apply()daha az sipariş olduğunu buldumpd.DataFrame(df['b'].values.tolist(), index=df.index)

Bu performans sorunu GitHub'da kapatıldı, ancak bu karara katılmıyorum:

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

DÜZENLEME: bu yanıta göre: https://stackoverflow.com/a/44196843/2230844


5
pd.DataFrame(df['b'].tolist())olmadan da .valuesgayet iyi çalışıyor gibi görünüyor. (Ve teşekkürler, çözümünüz çok daha hızlı .apply())
Swier

İndeksi yakalama konusunda endişeliydim, dolayısıyla .değerlerinin açık kullanımı.
denfromufa

1
@denfromufa'nın çözümü süper hızlı çalışır df [['b1', 'b2']] = pd.DataFrame (df ['b']. values.tolist (), index = df.index) ve Bellek Hatasına neden olmaz (as .apply (pd.Series)) ile karşılaştırıldığında
Yury Wallet

22

strKullanılabilir erişimci pandas.Seriesnesneler dtype == objectaslında bir iterable olduğunu.

Bir varsayalım pandas.DataFrame df:

df = pd.DataFrame(dict(col=[*zip('abcdefghij', range(10, 101, 10))]))

df

        col
0   (a, 10)
1   (b, 20)
2   (c, 30)
3   (d, 40)
4   (e, 50)
5   (f, 60)
6   (g, 70)
7   (h, 80)
8   (i, 90)
9  (j, 100)

Tekrarlanabilir olup olmadığını test edebiliriz

from collections import Iterable

isinstance(df.col.str, Iterable)

True

Daha sonra, diğer yinelemeleri yaptığımız gibi ondan da atayabiliriz:

var0, var1 = 'xy'
print(var0, var1)

x y

En basit çözüm

Yani bir satırda her iki sütunu da atayabiliriz

df['a'], df['b'] = df.col.str

df

        col  a    b
0   (a, 10)  a   10
1   (b, 20)  b   20
2   (c, 30)  c   30
3   (d, 40)  d   40
4   (e, 50)  e   50
5   (f, 60)  f   60
6   (g, 70)  g   70
7   (h, 80)  h   80
8   (i, 90)  i   90
9  (j, 100)  j  100

Daha hızlı çözüm

Sadece biraz daha karmaşık, zipbenzer bir yinelenebilir oluşturmak için kullanabiliriz

df['c'], df['d'] = zip(*df.col)

df

        col  a    b  c    d
0   (a, 10)  a   10  a   10
1   (b, 20)  b   20  b   20
2   (c, 30)  c   30  c   30
3   (d, 40)  d   40  d   40
4   (e, 50)  e   50  e   50
5   (f, 60)  f   60  f   60
6   (g, 70)  g   70  g   70
7   (h, 80)  h   80  h   80
8   (i, 90)  i   90  i   90
9  (j, 100)  j  100  j  100

Çizgide

Anlamı, var olanı değiştirmeyin df
Bu işe yarar çünkü assignanahtar kelimelerin yeni (veya mevcut) sütun adları olduğu ve değerlerin yeni sütunun değerleri olacağı anahtar kelime argümanlarını alır. Bir sözlük kullanabilir, onu paketinden çıkarabilir **ve anahtar kelime argümanları olarak çalışmasını sağlayabilirsiniz. Bu 'g', df.col.stryinelenebilirdeki ilk öğe ve yinelenebilirdeki 'h'ikinci öğe olan yeni bir sütun atamanın akıllıca bir yoludur df.col.str.

df.assign(**dict(zip('gh', df.col.str)))

        col  g    h
0   (a, 10)  a   10
1   (b, 20)  b   20
2   (c, 30)  c   30
3   (d, 40)  d   40
4   (e, 50)  e   50
5   (f, 60)  f   60
6   (g, 70)  g   70
7   (h, 80)  h   80
8   (i, 90)  i   90
9  (j, 100)  j  100

Benim listyaklaşımım

Modern liste anlayışı ve değişken paket açma ile.
Not: ayrıca satır içi kullanarakjoin

df.join(pd.DataFrame([*df.col], df.index, [*'ef']))

        col  g    h
0   (a, 10)  a   10
1   (b, 20)  b   20
2   (c, 30)  c   30
3   (d, 40)  d   40
4   (e, 50)  e   50
5   (f, 60)  f   60
6   (g, 70)  g   70
7   (h, 80)  h   80
8   (i, 90)  i   90
9  (j, 100)  j  100

Değişen versiyon,

df[['e', 'f']] = pd.DataFrame([*df.col], df.index)

Naif Zaman Testi

Kısa DataFrame

Yukarıda tanımlanan birini kullanın

%timeit df.assign(**dict(zip('gh', df.col.str)))
%timeit df.assign(**dict(zip('gh', zip(*df.col))))
%timeit df.join(pd.DataFrame([*df.col], df.index, [*'gh']))

1.16 ms ± 21.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
635 µs ± 18.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
795 µs ± 42.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Uzun DataFrame

10 ^ 3 kat daha büyük

df = pd.concat([df] * 1000, ignore_index=True)

%timeit df.assign(**dict(zip('gh', df.col.str)))
%timeit df.assign(**dict(zip('gh', zip(*df.col))))
%timeit df.join(pd.DataFrame([*df.col], df.index, [*'gh']))

11.4 ms ± 1.53 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.1 ms ± 41.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.33 ms ± 35.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

2
TL eklemeyi düşünün; DR: df['a'], df['b'] = df.col.str:)
mirekphd

11

Bence daha basit bir yol:

>>> import pandas as pd
>>> df = pd.DataFrame({'a':[1,2], 'b':[(1,2), (3,4)]}) 
>>> df
   a       b
0  1  (1, 2)
1  2  (3, 4)
>>> df['b_a']=df['b'].str[0]
>>> df['b_b']=df['b'].str[1]
>>> df
   a       b  b_a  b_b
0  1  (1, 2)    1    2
1  2  (3, 4)    3    4

1
Bu çözümler gerçekten çok daha basit
ApplePie

@jinhuawang, görünen o ki bu strbir pd.Seriesnesnenin temsilinin üstünde bir hack . Bunun nasıl çalıştığını açıklayabilir misin ?!
denfromufa

Sanırım str nesnesi nasıl çalışıyor? dizi nesnesine str ile erişebilirsiniz
Jinhua Wang

Ya bazı satırlarda farklı sayıda değere sahip demetler varsa?
mammykins

Bunun kabul edilmesi gerektiğini düşünüyorum. Daha 'pandas-onik' ... eğer bu bir şeyse.
Natacha

8

Bunun bir süre öncesine ait olduğunu biliyorum, ancak ikinci çözümün bir uyarısı:

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

dizini açıkça atması ve varsayılan bir sıralı dizine eklemesi, oysa kabul edilen yanıt

apply(pd.Series)

başvurunun sonucu satır dizinini koruyacağından olmayacaktır. Sıralama başlangıçta orijinal diziden korunurken, pandalar iki veri çerçevesindeki göstergeleri eşleştirmeye çalışacaktır.

Satırları sayısal olarak dizinlenmiş bir diziye ayarlamaya çalışıyorsanız bu çok önemli olabilir ve pandalar otomatik olarak yeni dizinin dizinini eskiyle eşleştirmeye çalışır ve sıralamada bir miktar bozulmaya neden olur.

Daha iyi bir hibrit çözüm, orijinal veri çerçevesinin dizinini yeniye ayarlamak olacaktır.

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

Bu, sıralamanın ve indekslemenin sonuçta korunmasını sağlarken ikinci yöntemi kullanma hızını koruyacaktır.


Cevabımı indeksleme gözleminize göre düzenledim, teşekkürler!
denfromufa
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.