การสร้างหมีแพนด้าแบบมีเงื่อนไขของคอลัมน์ series / dataframe


314

ฉันมีชื่อไฟล์ตามบรรทัดด้านล่าง:

    Type       Set
1    A          Z
2    B          Z           
3    B          X
4    C          Y

ฉันต้องการเพิ่มคอลัมน์อีกคอลัมน์หนึ่งลงใน dataframe (หรือสร้างชุดข้อมูล) ที่มีความยาวเท่ากับ dataframe (= จำนวนระเบียน / แถวเท่ากัน) ซึ่งตั้งค่าสีเขียวถ้า Set = 'Z' และ 'red' ถ้า Set = เป็นอย่างอื่น .

วิธีที่ดีที่สุดในการทำเช่นนี้คืออะไร?

คำตอบ:


711

หากคุณมีสองทางเลือกให้เลือกจาก:

df['color'] = np.where(df['Set']=='Z', 'green', 'red')

ตัวอย่างเช่น,

import pandas as pd
import numpy as np

df = pd.DataFrame({'Type':list('ABBC'), 'Set':list('ZZXY')})
df['color'] = np.where(df['Set']=='Z', 'green', 'red')
print(df)

อัตราผลตอบแทน

  Set Type  color
0   Z    A  green
1   Z    B  green
2   X    B    red
3   Y    C    red

np.selectหากคุณมีมากกว่าสองเงื่อนไขแล้วใช้ ตัวอย่างเช่นถ้าคุณต้องการcolorที่จะเป็น

  • yellow เมื่อไหร่ (df['Set'] == 'Z') & (df['Type'] == 'A')
  • เป็นอย่างอื่นblueเมื่อ(df['Set'] == 'Z') & (df['Type'] == 'B')
  • เป็นอย่างอื่นpurpleเมื่อ(df['Type'] == 'B')
  • มิฉะนั้นblack,

จากนั้นใช้

df = pd.DataFrame({'Type':list('ABBC'), 'Set':list('ZZXY')})
conditions = [
    (df['Set'] == 'Z') & (df['Type'] == 'A'),
    (df['Set'] == 'Z') & (df['Type'] == 'B'),
    (df['Type'] == 'B')]
choices = ['yellow', 'blue', 'purple']
df['color'] = np.select(conditions, choices, default='black')
print(df)

ซึ่งให้ผลผลิต

  Set Type   color
0   Z    A  yellow
1   Z    B    blue
2   X    B  purple
3   Y    C   black

1
ไม่ทำงานถ้าฉันใส่เงื่อนไขสองข้อไว้ข้างในที่ข้อด้วย
Amol Sharma

2
df ['color'] = รายการ (np.where (df ['Set'] == 'Z', 'green', 'red')) จะระงับคำเตือนของแพนด้า: ค่ากำลังพยายามตั้งค่าบนสำเนา ของส่วนหนึ่งจาก DataFrame ลองใช้. loc [row_indexer, col_indexer] = ค่าแทน
denson

3
'สีเขียว' และ 'สีแดง' สามารถแทนที่ด้วยเลขคณิตของคอลัมน์ได้ เช่น ,df['foo'] = np.where(df['Set']=='Z', df['Set'], df['Type'].shift(1))
Alejandro

np.where สร้างคอลัมน์ใหม่ได้อย่างไร ฉันใช้รหัสนี้และเมื่อฉันทำ df.color.head () ฉันจะได้รับ: วัตถุ 'numpy.ndarray' ไม่มีแอตทริบิวต์ 'หัว'
vvv

3
มันเป็นความอัปยศที่ฉันไม่สามารถลงคะแนนได้หลายครั้ง หนึ่ง upvote ดูเหมือนจะไม่เพียงพอ
ฮาร์เปอร์

120

รายการความเข้าใจเป็นอีกวิธีหนึ่งในการสร้างคอลัมน์อื่นตามเงื่อนไข หากคุณกำลังทำงานกับวัตถุชนิดในคอลัมน์เช่นในตัวอย่างของคุณรายการความเข้าใจมักจะมีประสิทธิภาพสูงกว่าวิธีอื่น ๆ ส่วนใหญ่

รายการความเข้าใจตัวอย่าง:

df['color'] = ['red' if x == 'Z' else 'green' for x in df['Set']]

การทดสอบ timeit:

import pandas as pd
import numpy as np

df = pd.DataFrame({'Type':list('ABBC'), 'Set':list('ZZXY')})
%timeit df['color'] = ['red' if x == 'Z' else 'green' for x in df['Set']]
%timeit df['color'] = np.where(df['Set']=='Z', 'green', 'red')
%timeit df['color'] = df.Set.map( lambda x: 'red' if x == 'Z' else 'green')

1000 loops, best of 3: 239 µs per loop
1000 loops, best of 3: 523 µs per loop
1000 loops, best of 3: 263 µs per loop

4
โปรดทราบว่ามี dataframes ที่ใหญ่กว่ามาก (คิดว่า pd.DataFrame({'Type':list('ABBC')*100000, 'Set':list('ZZXY')*100000})ขนาด) จะnumpy.whereแซงmapหน้า แต่ความเข้าใจในรายการคือราชา (เร็วกว่าประมาณ 50% numpy.where)
blacksite

3
รายการวิธีการทำความเข้าใจสามารถนำมาใช้ถ้าเงื่อนไขต้องการข้อมูลจากหลายคอลัมน์? ฉันกำลังมองหาสิ่งนี้ (ไม่ทำงาน):df['color'] = ['red' if (x['Set'] == 'Z') & (x['Type'] == 'B') else 'green' for x in df]
Mappi

2
เพิ่ม iterrows ลงใน dataframe จากนั้นคุณสามารถเข้าถึงหลายคอลัมน์ผ่านแถว: ['red' if (แถว ['Set'] == 'Z') & (แถว ['Type'] == 'B') else 'green 'สำหรับดัชนี, เข้าแถวใน df.iterrows ()]
cheekybastard

1
โปรดสังเกตว่าโซลูชันที่ดีนี้จะไม่ทำงานหากคุณจำเป็นต้องใช้ค่าทดแทนจากชุดข้อมูลอื่นในกรอบข้อมูลเช่นdf['color_type'] = np.where(df['Set']=='Z', 'green', df['Type'])
Paul Rougieux

@cheekybastard หรือไม่เนื่องจาก.iterrows()มันมีชื่อเสียงอย่างเชื่องช้าและ DataFrame ไม่ควรทำการแก้ไขในขณะที่วนซ้ำ
บบส

21

อีกวิธีหนึ่งที่สามารถทำได้คือ

df['color'] = df.Set.map( lambda x: 'red' if x == 'Z' else 'green')

วิธีการที่ดีสามารถบันทึกได้เพื่อประสิทธิภาพที่รวดเร็วขึ้น (ในชุดข้อมูลขนาดใหญ่) แม้ว่าจะต้องมีขั้นตอนเพิ่มเติม
Yaakov Bressler

21

นี่เป็นอีกวิธีในการสกินแมวตัวนี้โดยใช้พจนานุกรมเพื่อแมปค่าใหม่ลงในคีย์ในรายการ:

def map_values(row, values_dict):
    return values_dict[row]

values_dict = {'A': 1, 'B': 2, 'C': 3, 'D': 4}

df = pd.DataFrame({'INDICATOR': ['A', 'B', 'C', 'D'], 'VALUE': [10, 9, 8, 7]})

df['NEW_VALUE'] = df['INDICATOR'].apply(map_values, args = (values_dict,))

มีลักษณะอย่างไร:

df
Out[2]: 
  INDICATOR  VALUE  NEW_VALUE
0         A     10          1
1         B      9          2
2         C      8          3
3         D      7          4

วิธีการนี้จะมีประสิทธิภาพมากเมื่อคุณมีจำนวนมาก ifelseคำสั่ง -typeจะสร้าง (เช่นค่าที่ไม่ซ้ำจำนวนมากที่จะแทนที่)

และแน่นอนคุณสามารถทำสิ่งนี้ได้เสมอ:

df['NEW_VALUE'] = df['INDICATOR'].map(values_dict)

แต่วิธีการนั้นช้ากว่าสามเท่า applyวิธีบนเครื่องของฉัน

และคุณสามารถทำได้โดยใช้dict.get:

df['NEW_VALUE'] = [values_dict.get(v, None) for v in df['INDICATOR']]

ฉันชอบคำตอบนี้เพราะมันแสดงให้เห็นถึงวิธีการทำแทนค่าหลายอย่าง
Monica Heddneck

แต่วิธีการนั้นช้ากว่าวิธีการใช้บนเครื่องของฉันมากกว่าสามเท่า คุณวัดมาตรฐานเหล่านี้ได้อย่างไร จากการวัดอย่างรวดเร็วของฉันที่.map()การแก้ปัญหาคือ ~ 10 .apply()ครั้งเร็วกว่า
AMC

อัพเดท: บน 100,000,000 แถว 52 ค่าสตริง.apply()ใช้เวลา 47 วินาทีเมื่อเทียบกับเพียง 5.91 .map()วินาที
AMC

19

ต่อไปนี้ช้ากว่าวิธีที่กำหนดเวลาที่นี่แต่เราสามารถคำนวณคอลัมน์เพิ่มเติมตามเนื้อหาของคอลัมน์มากกว่าหนึ่งคอลัมน์และสามารถคำนวณค่ามากกว่าสองค่าสำหรับคอลัมน์พิเศษได้

ตัวอย่างง่ายๆโดยใช้เพียงคอลัมน์ "ตั้งค่า":

def set_color(row):
    if row["Set"] == "Z":
        return "red"
    else:
        return "green"

df = df.assign(color=df.apply(set_color, axis=1))

print(df)
  Set Type  color
0   Z    A    red
1   Z    B    red
2   X    B  green
3   Y    C  green

ตัวอย่างที่มีสีมากขึ้นและคอลัมน์ที่นำมาพิจารณามากขึ้น:

def set_color(row):
    if row["Set"] == "Z":
        return "red"
    elif row["Type"] == "C":
        return "blue"
    else:
        return "green"

df = df.assign(color=df.apply(set_color, axis=1))

print(df)
  Set Type  color
0   Z    A    red
1   Z    B    red
2   X    B  green
3   Y    C   blue

แก้ไข (21/06/2019): การใช้ plydata

นอกจากนี้ยังเป็นไปได้ที่จะใช้plydataเพื่อทำสิ่งนี้ (ดูเหมือนว่าจะช้ากว่าการใช้assignและapplyแม้ว่า)

from plydata import define, if_else

ง่าย ๆif_else:

df = define(df, color=if_else('Set=="Z"', '"red"', '"green"'))

print(df)
  Set Type  color
0   Z    A    red
1   Z    B    red
2   X    B  green
3   Y    C  green

ซ้อนกันif_else:

df = define(df, color=if_else(
    'Set=="Z"',
    '"red"',
    if_else('Type=="C"', '"green"', '"blue"')))

print(df)                            
  Set Type  color
0   Z    A    red
1   Z    B    red
2   X    B   blue
3   Y    C  green

10

บางทีนี่อาจเป็นไปได้ด้วยการอัพเดทใหม่ของนุ่น แต่ฉันคิดว่าต่อไปนี้เป็นคำตอบที่สั้นที่สุดและดีที่สุดสำหรับคำถามจนถึงตอนนี้ คุณสามารถใช้.locวิธีการและใช้เงื่อนไขหนึ่งหรือหลายเงื่อนไขขึ้นอยู่กับความต้องการของคุณ

สรุปรหัส:

df=pd.DataFrame(dict(Type='A B B C'.split(), Set='Z Z X Y'.split()))
df['Color'] = "red"
df.loc[(df['Set']=="Z"), 'Color'] = "green"

#practice!
df.loc[(df['Set']=="Z")&(df['Type']=="B")|(df['Type']=="C"), 'Color'] = "purple"

คำอธิบาย:

df=pd.DataFrame(dict(Type='A B B C'.split(), Set='Z Z X Y'.split()))

# df so far: 
  Type Set  
0    A   Z 
1    B   Z 
2    B   X 
3    C   Y

เพิ่มคอลัมน์ 'สี' และตั้งค่าทั้งหมดเป็น "สีแดง"

df['Color'] = "red"

ใช้เงื่อนไขเดียวของคุณ:

df.loc[(df['Set']=="Z"), 'Color'] = "green"


# df: 
  Type Set  Color
0    A   Z  green
1    B   Z  green
2    B   X    red
3    C   Y    red

หรือหลายเงื่อนไขหากคุณต้องการ:

df.loc[(df['Set']=="Z")&(df['Type']=="B")|(df['Type']=="C"), 'Color'] = "purple"

คุณสามารถอ่านตัวดำเนินการเชิงตรรกะของ Pandas และการเลือกตามเงื่อนไขได้ที่นี่: ตัวดำเนินการเชิงตรรกะสำหรับการทำดัชนีบูลีนใน Pandas


2
หนึ่งที่ดีที่สุดจนถึง คุณอาจเพิ่มเงื่อนไขเพิ่มเติมเพื่อให้เป็นรหัสได้df.loc[(df['Set']=="Z") & (df['Type']=="A"), 'Color'] = "green"
Salvador Vigo

2
นี่ควรเป็นคำตอบที่ยอมรับได้ จริงสำนวนและยืดออกได้
AMC

1

ซับหนึ่งด้วย.apply()วิธีการดังต่อไปนี้:

df['color'] = df['Set'].apply(lambda set_: 'green' if set_=='Z' else 'red')

หลังจากนั้นdfกรอบข้อมูลจะมีลักษณะดังนี้:

>>> print(df)
  Type Set  color
0    A   Z  green
1    B   Z  green
2    B   X    red
3    C   Y    red

0

หากคุณกำลังทำงานกับข้อมูลจำนวนมากวิธีการที่บันทึกความจำจะดีที่สุด

# First create a dictionary of manually stored values
color_dict = {'Z':'red'}

# Second, build a dictionary of "other" values
color_dict_other = {x:'green' for x in df['Set'].unique() if x not in color_dict.keys()}

# Next, merge the two
color_dict.update(color_dict_other)

# Finally, map it to your column
df['color'] = df['Set'].map(color_dict)

วิธีนี้จะเร็วที่สุดเมื่อคุณมีค่าซ้ำหลายครั้ง กฎทั่วไปของฉันคือการจดจำเมื่อ: data_size> 10**4& n_distinct<data_size/4

ยกตัวอย่างเช่นในกรณีที่ 10,000 แถวที่มี 2,500 หรือน้อยกว่าค่าที่แตกต่าง


เอาล่ะมีเพียง 2 ค่าที่แตกต่างในการแมป 100,000,000 แถวใช้เวลา 6.67 วินาทีในการรันโดยไม่มี "การจำ" และ 9.86 วินาทีด้วย
AMC

100,000,000 แถว, 52 ค่าที่แตกต่างกันโดยที่ 1 ในแผนที่เหล่านั้นกับค่าเอาต์พุตแรกและอีก 51 ค่าสอดคล้องกับค่าอื่น ๆ : 7.99 วินาทีโดยไม่มีการบันทึกข้อมูล, 11.1 วินาทีด้วย
AMC

คุณค่าของคุณเป็นแบบสุ่มหรือไม่? หรือพวกเขากลับไปกลับมา? แพนด้าความเร็วสูงอาจเกิดจากการแคช @AMC
Yaakov Bressler

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