Pandalar, liste sütununu birden çok sütuna böldü


135

Tek sütunlu pandalarım DataFrame var:

import pandas as pd

df = pd.DataFrame(
    data={
        "teams": [
            ["SF", "NYG"],
            ["SF", "NYG"],
            ["SF", "NYG"],
            ["SF", "NYG"],
            ["SF", "NYG"],
            ["SF", "NYG"],
            ["SF", "NYG"],
        ]
    }
)

print(df)

Çıktı:

       teams
0  [SF, NYG]
1  [SF, NYG]
2  [SF, NYG]
3  [SF, NYG]
4  [SF, NYG]
5  [SF, NYG]
6  [SF, NYG]

Bu liste sütununu 2 sütuna nasıl bölebilirim?

Yanıtlar:


243

Sen kullanabilirsiniz DataFrameile yapıcısı liststarafından oluşturulan to_list:

import pandas as pd

d1 = {'teams': [['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],
                ['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG']]}
df2 = pd.DataFrame(d1)
print (df2)
       teams
0  [SF, NYG]
1  [SF, NYG]
2  [SF, NYG]
3  [SF, NYG]
4  [SF, NYG]
5  [SF, NYG]
6  [SF, NYG]

df2[['team1','team2']] = pd.DataFrame(df2.teams.tolist(), index= df2.index)
print (df2)
       teams team1 team2
0  [SF, NYG]    SF   NYG
1  [SF, NYG]    SF   NYG
2  [SF, NYG]    SF   NYG
3  [SF, NYG]    SF   NYG
4  [SF, NYG]    SF   NYG
5  [SF, NYG]    SF   NYG
6  [SF, NYG]    SF   NYG

Ve yeni için DataFrame:

df3 = pd.DataFrame(df2['teams'].to_list(), columns=['team1','team2'])
print (df3)
  team1 team2
0    SF   NYG
1    SF   NYG
2    SF   NYG
3    SF   NYG
4    SF   NYG
5    SF   NYG
6    SF   NYG

İle çözüm apply(pd.Series)çok yavaş:

#7k rows
df2 = pd.concat([df2]*1000).reset_index(drop=True)

In [121]: %timeit df2['teams'].apply(pd.Series)
1.79 s ± 52.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [122]: %timeit pd.DataFrame(df2['teams'].to_list(), columns=['team1','team2'])
1.63 ms ± 54.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

4
Küçük uyarı, mevcut veri çerçevesi üzerinde kullanıyorsanız, dizini sıfırladığınızdan emin olun, aksi takdirde doğru şekilde atanmayacaktır.
user1700890

1
@ user1700890 - evet veya DataFrame yapıcısında dizini belirtindf2[['team1','team2']] = pd.DataFrame(df2.teams.values.tolist(), index= df2.index)
jezrael

1
@Catbuilts - evet, varsa vectorize çözümü en iyisi bundan kaçının.
jezrael

1
@Catbuilts - evet, tabii ki. Vectorized, genellikle döngü olmadığı anlamına gelir, bu nedenle uygulama yok, için hayır, liste anlamaları yok. Ama tam olarak neye ihtiyaç duyduğuna bağlı. Belki de yardımcı bu
Jezrael

2
@Catbuilts Indeed apply()daha yavaş olabilir, ancak giriş dizesi ve değerler orijinal Serinin satırları arasında eşit olmadığında başvurulacak yöntemdir!
CheTesta

52

Çok daha basit çözüm:

pd.DataFrame(df2["teams"].to_list(), columns=['team1', 'team2'])

Verim,

  team1 team2
-------------
0    SF   NYG
1    SF   NYG
2    SF   NYG
3    SF   NYG
4    SF   NYG
5    SF   NYG
6    SF   NYG
7    SF   NYG

Listeler yerine sınırlandırılmış dizelerden oluşan bir sütunu bölmek isterseniz, benzer şekilde şunları yapabilirsiniz:

pd.DataFrame(df["teams"].str.split('<delim>', expand=True).values,
             columns=['team1', 'team2'])

6
ya her listede eşit olmayan sayıda öğe varsa?
ikel

Listeler yerine sınırlandırılmış dizelerden oluşan bir sütunu bölmek isterseniz, benzer şekilde yapabilirsiniz: df["teams"].str.split('<delim>', expand=True) zaten bir DataFrame döndürür, bu nedenle sütunları yeniden adlandırmak muhtemelen daha kolay olacaktır.
AMC

26

Bu çözüm, df2aşağıdakileri kullanan herhangi bir çözümün aksine DataFrame dizinini korur tolist():

df3 = df2.teams.apply(pd.Series)
df3.columns = ['team1', 'team2']

İşte sonuç:

  team1 team2
0    SF   NYG
1    SF   NYG
2    SF   NYG
3    SF   NYG
4    SF   NYG
5    SF   NYG
6    SF   NYG

2
Ayrıca applypandalarda yapabileceğiniz en yavaş yöntemlerden biri . Bu yöntemden kaçınmalı ve kabul edilen cevabı kullanmalısınız. En iyi cevabın zamanlamasında, bu yöntem yaklaşık olarak 1400 xdaha yavaştır @rajan
Erfan

2
@Erfan Evet, ancak bazen kullanıcı bir işlemin 1sn mi 1ms mi sürdüğünü umursamıyor ve bunun yerine en çok en basit, en okunabilir kodu yazmayı önemsiyorlar! Okunabilirliğin / basitliğin öznel olduğunu kabul ediyorum, ancak benim açımdan, basitçe, hızın tüm kullanıcılar için her zaman bir öncelik olmadığıdır.
Kevin Markham

1
Ayrıca, applyyöntemin büyük veri kümelerinde büyük dizileri (1000'den fazla öğe) genişletmek için daha güvenilir çalıştığını öğrendim . tolist()Veri seti 500k satır aştı zaman yöntem benim sürecini öldürdü.
moritz

2
Bu harika bir çözüm çünkü farklı boyutlardaki listelerle iyi çalışıyor.
dasilvadaniel

@KevinMarkham onlar basit, en okunabilir kod yazmak için en önemli mi pd.DataFrame(df["teams"].to_list(), columns=["team_1", "team_2"])gerçekten çok daha karmaşık?
AMC

15

Sözdizimsel olarak daha basit ve bu nedenle önerilen çözümlerin aksine hatırlanması daha kolay bir yol var gibi görünüyor. Bir veri çerçevesi df'de sütunun 'meta' olarak adlandırıldığını varsayıyorum:

df2 = pd.DataFrame(df['meta'].str.split().values.tolist())

1
Bir hata aldım ancak str.split(). Bu çok daha basitti ve listenizdeki öğelerin sayısını bilmiyorsanız avantajı vardır.
otteheng

Sözdizimsel olarak daha basit ve bu nedenle önerilen çözümlerin aksine hatırlanması daha kolay bir yol var gibi görünüyor. Gerçekten mi? Çünkü bu, yıllar önce yayınlanan en iyi cevapla neredeyse aynı. Tek fark, bu özel soruyla ilgili olmayan kısımdır.
AMC

Benim için çalışıyor !!
EduardoUstarez

3

Önceki yanıtlara dayanarak, burada df2.teams.apply (pd.Series) ile aynı sonucu çok daha hızlı bir çalışma süresiyle döndüren başka bir çözüm var:

pd.DataFrame([{x: y for x, y in enumerate(item)} for item in df2['teams'].values.tolist()], index=df2.index)

Zamanlamaları:

In [1]:
import pandas as pd
d1 = {'teams': [['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],
                ['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG']]}
df2 = pd.DataFrame(d1)
df2 = pd.concat([df2]*1000).reset_index(drop=True)

In [2]: %timeit df2['teams'].apply(pd.Series)

8.27 s ± 2.73 s per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [3]: %timeit pd.DataFrame([{x: y for x, y in enumerate(item)} for item in df2['teams'].values.tolist()], index=df2.index)

35.4 ms ± 5.22 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

3

nanGözlemlerim olduğu için yukarıdaki çözümler benim için işe yaramadı dataframe. Benim durumumda df2[['team1','team2']] = pd.DataFrame(df2.teams.values.tolist(), index= df2.index)verir:

object of type 'float' has no len()

Bunu liste anlayışını kullanarak çözüyorum. İşte çoğaltılabilir örnek:

import pandas as pd
import numpy as np
d1 = {'teams': [['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],
            ['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG']]}
df2 = pd.DataFrame(d1)
df2.loc[2,'teams'] = np.nan
df2.loc[4,'teams'] = np.nan
df2

çıktı:

        teams
0   [SF, NYG]
1   [SF, NYG]
2   NaN
3   [SF, NYG]
4   NaN
5   [SF, NYG]
6   [SF, NYG]

df2['team1']=np.nan
df2['team2']=np.nan

liste anlayışı ile çözme:

for i in [0,1]:
    df2['team{}'.format(str(i+1))]=[k[i] if isinstance(k,list) else k for k in df2['teams']]

df2

verim:

    teams   team1   team2
0   [SF, NYG]   SF  NYG
1   [SF, NYG]   SF  NYG
2   NaN        NaN  NaN
3   [SF, NYG]   SF  NYG
4   NaN        NaN  NaN
5   [SF, NYG]   SF  NYG
6   [SF, NYG]   SF  NYG

1

liste anlama

liste anlama ile basit uygulama (favorim)

df = pd.DataFrame([pd.Series(x) for x in df.teams])
df.columns = ['team_{}'.format(x+1) for x in df.columns]

çıktıda zamanlama:

CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 2.71 ms

çıktı:

team_1  team_2
0   SF  NYG
1   SF  NYG
2   SF  NYG
3   SF  NYG
4   SF  NYG
5   SF  NYG
6   SF  NYG

Bu tür, farklı uzunluktaki listeleri ele alır - bu, diğer birçok cevaba göre bir gelişmedir, ancak öğelerin kendi sütunlarında olmamasına neden olur.
Isaac

0

İşte df.transformve kullanarak başka bir çözüm df.set_index:

>>> (df['teams']
       .transform([lambda x:x[0], lambda x:x[1]])
       .set_axis(['team1','team2'],
                  axis=1,
                  inplace=False)
    )

  team1 team2
0    SF   NYG
1    SF   NYG
2    SF   NYG
3    SF   NYG
4    SF   NYG
5    SF   NYG
6    SF   NYG
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.