แพนด้าแยกคอลัมน์ของรายการออกเป็นหลายคอลัมน์


136

ฉันมี 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 คอลัมน์ได้อย่างไร

คำตอบ:


244

คุณสามารถใช้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
ข้อแม้เล็กน้อยหากคุณใช้งานบนดาต้าเฟรมที่มีอยู่ตรวจสอบให้แน่ใจว่าได้รีเซ็ตดัชนีมิฉะนั้นจะกำหนดไม่ถูกต้อง
user1700890

1
@ user1700890 - ใช่หรือระบุดัชนีในตัวสร้างdf2[['team1','team2']] = pd.DataFrame(df2.teams.values.tolist(), index= df2.index)
DataFrame

1
@Catbuilts - ใช่หากมีโซลูชันแบบเวกเตอร์สิ่งที่ดีที่สุดคือหลีกเลี่ยง
jezrael

1
@Catbuilts - ใช่แน่นอน Vectorized หมายถึงโดยทั่วไปไม่มีการวนซ้ำดังนั้นไม่ใช้ไม่สำหรับไม่มีความเข้าใจในรายการ แต่ขึ้นอยู่กับสิ่งที่ต้องการ อาจช่วยสิ่งนี้ด้วย
jezrael

2
@Catbuilts อันที่จริงapply()อาจจะช้ากว่า แต่เป็นวิธีการไปที่เมื่อสตริงอินพุตและค่าไม่เท่ากันในแถวของซีรี่ส์ดั้งเดิม!
CheTesta

53

วิธีแก้ปัญหาที่ง่ายกว่ามาก:

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
Erfan

2
@ Erfan ใช่ แต่บางครั้งผู้ใช้ไม่สนใจว่าการดำเนินการจะใช้เวลา 1 วินาทีหรือ 1 มิลลิวินาที แต่พวกเขาสนใจมากที่สุดเกี่ยวกับการเขียนโค้ดที่ง่ายและอ่านง่ายที่สุด! ฉันรับทราบว่าความสามารถในการอ่าน / ความเรียบง่ายเป็นเรื่องส่วนตัว แต่ประเด็นของฉันก็คือความเร็วไม่ใช่สิ่งสำคัญสำหรับผู้ใช้ทุกคนตลอดเวลา
Kevin Markham

1
นอกจากนี้ฉันพบว่าapplyวิธีนี้ทำงานได้อย่างน่าเชื่อถือมากขึ้นสำหรับการขยายอาร์เรย์ขนาดใหญ่ (มากกว่า 1,000 รายการ) บนชุดข้อมูลขนาดใหญ่ tolist()วิธีการฆ่ากระบวนการของฉันเมื่อชุดข้อมูลเกิน 500 กิโลแถว
moritz

2
นี่เป็นวิธีแก้ปัญหาที่ยอดเยี่ยมเนื่องจากใช้งานได้ดีกับรายการขนาดต่างๆ
dasilvadaniel

@KevinMarkham พวกเขาสนใจมากที่สุดเกี่ยวกับการเขียนง่ายรหัสที่อ่านได้มากที่สุดคือpd.DataFrame(df["teams"].to_list(), columns=["team_1", "team_2"])ความซับซ้อนจริงๆมากขึ้น?
AMC

15

ดูเหมือนว่าจะมีวิธีที่ง่ายกว่าทางวากยสัมพันธ์และง่ายต่อการจดจำเมื่อเทียบกับวิธีแก้ปัญหาที่เสนอ ฉันสมมติว่าคอลัมน์นี้เรียกว่า 'meta' ใน dataframe 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

การจัดการประเภทนี้จะแสดงรายการที่มีความยาวต่างกันซึ่งเป็นการปรับปรุงคำตอบอื่น ๆ อีกมากมาย แต่ส่งผลให้รายการไม่อยู่ในคอลัมน์ของตนเอง
Isaac

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.