Панди розділяють стовпці списків на кілька стовпців


135

У мене панди DataFrame з одним стовпцем:

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)

Вихід:

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

Як можна розділити цей стовпець списків на 2 стовпці?

Відповіді:


243

Ви можете використовувати DataFrameконструктор, listsстворений 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

І для нового 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

Рішення з apply(pd.Series)дуже повільним:

#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
Незначний застереження, якщо ви використовуєте його на існуючому фреймі даних, переконайтеся, що індекс не скидається, інакше він не буде призначений правильно.
користувач1700890

1
@ user1700890 - так, або вкажіть індекс у конструкторі df2[['team1','team2']] = pd.DataFrame(df2.teams.values.tolist(), index= df2.index)
DataFrame

1
@Catbuilts - так, якщо існує векторний розчин, найкраще цього уникати.
jezrael

1
@Catbuilts - так, очевидно. Векторизовані засоби, як правило, не містять циклів, тому не застосовуються, не застосовуються, не розуміються списки. Але залежить, що саме потрібно. Можливо, також допоможе в цьому
jezrael

2
@Catbuilts Дійсно apply()може бути повільнішим, але це метод переходу, коли рядок введення та значення не рівні в рядках оригінальної серії!
CheTesta

52

Набагато простіше рішення:

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

Урожайність,

  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

Якщо ви хочете розділити стовпчик з обмеженими рядками, а не списками, ви можете зробити так само:

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

6
що робити, якщо кожен список містить неоднакову кількість елементів?
ikel

Якщо ви хочете розділити стовпчик з обмеженими рядками, а не списками, ви могли б зробити так само: df["teams"].str.split('<delim>', expand=True) вже повертає DataFrame, тому, мабуть, було б простіше просто перейменувати стовпці.
AMC

26

Це рішення зберігає індекс df2DataFrame, на відміну від будь-якого рішення, яке використовує tolist():

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

Ось результат:

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

2
Також один із найповільніших, applyщо можна зробити у пандах. Вам слід уникати цього методу і використовувати прийняту відповідь. У 1400 xчасі головної відповіді цей метод є приблизно повільнішим @rajan
Ерфан

2
@Erfan Так, але іноді користувачеві не важливо, чи займає операція 1s або 1ms, і натомість вони найбільше піклуються про написання найпростішого, найчитабельнішого коду! Я визнаю, що читабельність / простота є суб’єктивною, але я мою думку просто, що швидкість не є пріоритетним для всіх користувачів в усі часи.
Кевін Маркхем

1
Крім того, я з’ясував, що applyметод працює надійніше для розширення великих масивів (1000+ елементів) на великих наборах даних. tolist()Метод вбив мій процес , коли набір даних перевищив 500K рядків.
moritz

2
Це чудове рішення, оскільки воно добре працює зі списками різних розмірів.
dasilvadaniel

@KevinMarkham вони найбільше піклуються про написання найпростішого, найчитабельнішого коду Чи pd.DataFrame(df["teams"].to_list(), columns=["team_1", "team_2"])справді набагато складніше?
AMC

15

Здається, є синтаксично простіший спосіб, і тому його легше запам’ятати, на відміну від запропонованих рішень. Я припускаю, що стовпець називається 'meta' у кадрі df:

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

1
Я отримав помилку, але вирішив її, видаливши str.split(). Це було набагато простіше і має перевагу, якщо ви не знаєте кількість елементів у своєму списку.
otteheng

Здається, є синтаксично простіший спосіб, і тому його легше запам’ятати, на відміну від запропонованих рішень. Дійсно? Тому що це практично ідентично верхній відповіді, який був опублікований роками раніше. Єдина відмінність - частина, яка не пов'язана з цим конкретним питанням.
AMC

Це працює на мене !!
EduardoUstarez

3

На основі попередніх відповідей, ось ще одне рішення, яке повертає той же результат, що і df2.teams.apply (pd.Series) із значно швидшим часом роботи:

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

Терміни:

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

Вищезазначені рішення не спрацювали для мене, оскільки я маю свої nanспостереження dataframe. У моєму випадку df2[['team1','team2']] = pd.DataFrame(df2.teams.values.tolist(), index= df2.index)врожайність:

object of type 'float' has no len()

Я вирішую це за допомогою розуміння списку. Ось приклад, що повторюється:

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

вихід:

        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

рішення з розумінням списку:

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

врожайність:

    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

осмислення списку

проста реалізація з розумінням списку (мій улюблений)

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

Час виходу:

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

вихід:

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

Цей вид обробляє списки різної довжини - що є вдосконаленням порівняно з багатьма іншими відповідями, але призводить до того, що елементи не знаходяться у власних стовпцях.
Ісаак

0

Ось ще одне рішення з використанням df.transformта 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.