เปรียบเทียบสองคอลัมน์โดยใช้แพนด้า


110

โดยใช้สิ่งนี้เป็นจุดเริ่มต้น:

a = [['10', '1.2', '4.2'], ['15', '70', '0.03'], ['8', '5', '0']]
df = pd.DataFrame(a, columns=['one', 'two', 'three'])

Out[8]: 
  one  two three
0   10  1.2   4.2
1   15  70   0.03
2    8   5     0

ฉันต้องการใช้ifคำสั่งในแพนด้า

if df['one'] >= df['two'] and df['one'] <= df['three']:
    df['que'] = df['one']

โดยทั่วไปตรวจสอบแต่ละแถวผ่านifคำสั่งสร้างคอลัมน์ใหม่

เอกสารบอกใช้.allแต่ไม่มีตัวอย่าง ...


ค่าควรifเป็นเท่าFalseไหร่ถ้าคำสั่งคืออะไร?
Alex Riley

3
@ เมอร์ลิน: หากคุณมีข้อมูลตัวเลขในคอลัมน์ไม่ควรผสมกับสตริง การทำเช่นนี้การเปลี่ยนแปลง dtype objectของคอลัมน์เพื่อ สิ่งนี้ช่วยให้สามารถจัดเก็บวัตถุ Python ได้ตามอำเภอใจในคอลัมน์ แต่ต้องเสียค่าใช้จ่ายในการคำนวณตัวเลขที่ช้าลง ดังนั้นหากคอลัมน์กำลังจัดเก็บข้อมูลที่เป็นตัวเลขควรใช้ NaN สำหรับ non-a-numbers
unutbu

1
มีจำนวนเต็มเป็นสตริงและพยายามที่จะทำเมื่อเทียบกับพวกเขาดูแปลก ๆ a = [['10', '1.2', '4.2'], ['15', '70', '0.03'], ['8', '5', '0']]: สิ่งนี้สร้างผลลัพธ์ที่สับสนด้วยรหัส "ถูกต้อง": df['que'] = df['one'][(df['one'] >= df['two']) & (df['one'] <= df['three'])] ให้ผล10สำหรับบรรทัดแรกในขณะที่ควรให้ผลลัพธ์NaNหากอินพุตเป็นจำนวนเต็ม
Primer

คำตอบ:


153

คุณสามารถใช้np.where ถ้าcondเป็นอาร์เรย์บูลีนและAและBเป็นอาร์เรย์ดังนั้น

C = np.where(cond, A, B)

กำหนดให้ C เท่ากับAที่condเป็นจริงและเท็จอยู่Bที่ไหนcond

import numpy as np
import pandas as pd

a = [['10', '1.2', '4.2'], ['15', '70', '0.03'], ['8', '5', '0']]
df = pd.DataFrame(a, columns=['one', 'two', 'three'])

df['que'] = np.where((df['one'] >= df['two']) & (df['one'] <= df['three'])
                     , df['one'], np.nan)

ผลตอบแทน

  one  two three  que
0  10  1.2   4.2   10
1  15   70  0.03  NaN
2   8    5     0  NaN

หากคุณมีเงื่อนไขมากกว่าหนึ่งเงื่อนไขคุณสามารถใช้np.selectแทนได้ ตัวอย่างเช่นหากคุณต้องการที่df['que']จะเท่ากันdf['two']เมื่อdf['one'] < df['two']นั้น

conditions = [
    (df['one'] >= df['two']) & (df['one'] <= df['three']), 
    df['one'] < df['two']]

choices = [df['one'], df['two']]

df['que'] = np.select(conditions, choices, default=np.nan)

ผลตอบแทน

  one  two three  que
0  10  1.2   4.2   10
1  15   70  0.03   70
2   8    5     0  NaN

หากเราสามารถสรุปได้ว่าdf['one'] >= df['two']เมื่อใดที่df['one'] < df['two']เป็นเท็จเงื่อนไขและทางเลือกต่างๆก็สามารถทำให้ง่ายขึ้นได้

conditions = [
    df['one'] < df['two'],
    df['one'] <= df['three']]

choices = [df['two'], df['one']]

(สมมติฐานอาจไม่เป็นจริงหากมีdf['one']หรือdf['two']มี NaN)


โปรดทราบว่า

a = [['10', '1.2', '4.2'], ['15', '70', '0.03'], ['8', '5', '0']]
df = pd.DataFrame(a, columns=['one', 'two', 'three'])

กำหนด DataFrame ด้วยค่าสตริง เนื่องจากมันดูเป็นตัวเลขคุณอาจจะดีกว่าในการแปลงสตริงเหล่านั้นให้เป็นลอย:

df2 = df.astype(float)

สิ่งนี้จะเปลี่ยนผลลัพธ์เนื่องจากสตริงเปรียบเทียบอักขระทีละอักขระในขณะที่การลอยจะถูกเปรียบเทียบเป็นตัวเลข

In [61]: '10' <= '4.2'
Out[61]: True

In [62]: 10 <= 4.2
Out[62]: False

78

คุณสามารถใช้.equalsสำหรับคอลัมน์หรือทั้งดาต้าเฟรม

df['col1'].equals(df['col2'])

หากพวกเขากำลังเท่ากับคำสั่งที่จะกลับอื่นTrueFalse


24
หมายเหตุ: จะเปรียบเทียบทั้งคอลัมน์กับคอลัมน์อื่นเท่านั้น นี่ไม่ได้เปรียบเทียบองค์ประกอบ columsn wise
guerda

1
ถ้าคุณต้องการดูว่าคอลัมน์หนึ่งมีค่า "มากกว่า" หรือ "น้อยกว่า" คอลัมน์อื่น ๆ เสมอหรือไม่?
rrlamichhane

28

คุณสามารถใช้ apply () และทำสิ่งนี้ได้

df['que'] = df.apply(lambda x : x['one'] if x['one'] >= x['two'] and x['one'] <= x['three'] else "", axis=1)

หรือหากคุณไม่ต้องการใช้แลมด้า

def que(x):
    if x['one'] >= x['two'] and x['one'] <= x['three']:
        return x['one']
    return ''
df['que'] = df.apply(que, axis=1)

2
ฉันสงสัยว่านี่อาจจะช้ากว่าวิธีอื่น ๆ ที่โพสต์ไว้เล็กน้อยเนื่องจากไม่ได้ใช้ประโยชน์จากการดำเนินการแบบเวกเตอร์ที่แพนด้าอนุญาต
Marius

@ BobHaffner: lambda ไม่สามารถอ่านได้เมื่อใช้คำสั่ง if / then / else ที่ซับซ้อน
Merlin

@Merlin คุณสามารถเพิ่ม elseif และฉันจะเห็นด้วยกับคุณเกี่ยวกับ lambdas และเงื่อนไขหลายประการ
Bob Haffner

มีวิธีในการสรุปฟังก์ชันที่ไม่ใช่แลมบ์ดาเพื่อให้คุณสามารถส่งผ่านคอลัมน์ dataframe และไม่เปลี่ยนชื่อได้หรือไม่?
AZhao

@AZhao คุณสามารถสรุปด้วย iloc เช่นนี้ df ['que'] = df.apply (แลมบ์ดา x: x.iloc [0] ถ้า x.iloc [0]> = x.iloc [1] และ x.iloc [0 ] <= x.iloc [2] else "", axis = 1) นั่นคือสิ่งที่คุณหมายถึง? เห็นได้ชัด. ลำดับคอลัมน์ของคุณมีความสำคัญ
Bob Haffner

9

df['one']วิธีหนึ่งคือการใช้ชุดบูลีนเพื่อจัดทำดัชนีคอลัมน์ นี้จะช่วยให้คุณคอลัมน์ใหม่ที่Trueรายการมีค่าเช่นเดียวกับแถวเดียวกับdf['one']และมีค่าFalseNaN

ชุดบูลีนได้รับจากifคำสั่งของคุณ(แม้ว่าจำเป็นต้องใช้&แทนand):

>>> df['que'] = df['one'][(df['one'] >= df['two']) & (df['one'] <= df['three'])]
>>> df
    one two three   que
0   10  1.2 4.2      10
1   15  70  0.03    NaN
2   8   5   0       NaN

ถ้าคุณต้องการให้NaNค่าที่จะถูกแทนที่ด้วยค่าอื่น ๆ ที่คุณสามารถใช้วิธีการในคอลัมน์ใหม่fillna queฉันใช้0แทนสตริงว่างที่นี่:

>>> df['que'] = df['que'].fillna(0)
>>> df
    one two three   que
0   10  1.2   4.2    10
1   15   70  0.03     0
2    8    5     0     0

5

รวมแต่ละเงื่อนไขไว้ในวงเล็บจากนั้นใช้ตัว&ดำเนินการเพื่อรวมเงื่อนไข:

df.loc[(df['one'] >= df['two']) & (df['one'] <= df['three']), 'que'] = df['one']

คุณสามารถเติมแถวที่ไม่ตรงกันได้โดยใช้~(ตัวดำเนินการ "not") เพื่อกลับรายการที่ตรงกัน:

df.loc[~ ((df['one'] >= df['two']) & (df['one'] <= df['three'])), 'que'] = ''

คุณจำเป็นต้องใช้&และ~มากกว่าandและnotเนื่องจาก&และ~ตัวดำเนินการทำงานแบบองค์ประกอบต่อองค์ประกอบ

ผลลัพธ์สุดท้าย:

df
Out[8]: 
  one  two three que
0  10  1.2   4.2  10
1  15   70  0.03    
2   8    5     0  

1

ใช้np.selectถ้าคุณมีเงื่อนไขหลายเงื่อนไขที่ต้องตรวจสอบจากดาต้าเฟรมและแสดงผลตัวเลือกเฉพาะในคอลัมน์อื่น

conditions=[(condition1),(condition2)]
choices=["choice1","chocie2"]

df["new column"]=np.select=(condtion,choice,default=)

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


0

ฉันคิดว่าสิ่งที่ใกล้เคียงที่สุดกับสัญชาตญาณของ OP คือคำสั่ง inline if:

df['que'] = (df['one'] if ((df['one'] >= df['two']) and (df['one'] <= df['three'])) 

รหัสของคุณทำให้ฉันมีข้อผิดพลาดdf['que'] = (df['one'] if ((df['one'] >= df['two']) and (df['one'] <= df['three'])) ^ SyntaxError: unexpected EOF while parsing
vasili111

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