ทำไมฟังก์ชั่น 'ใช้' ของนุ่นถึงการอ้างอิงหลายคอลัมน์ทำงานไม่ได้ [ปิด]


239

ฉันมีปัญหาบางอย่างเกี่ยวกับฟังก์ชั่นการใช้หมีแพนด้าเมื่อใช้หลายคอลัมน์ด้วยดาต้าเฟรมต่อไปนี้

df = DataFrame ({'a' : np.random.randn(6),
                 'b' : ['foo', 'bar'] * 3,
                 'c' : np.random.randn(6)})

และฟังก์ชั่นดังต่อไปนี้

def my_test(a, b):
    return a % b

เมื่อฉันพยายามใช้ฟังก์ชั่นนี้กับ:

df['Value'] = df.apply(lambda row: my_test(row[a], row[c]), axis=1)

ฉันได้รับข้อความแสดงข้อผิดพลาด:

NameError: ("global name 'a' is not defined", u'occurred at index 0')

ฉันไม่เข้าใจข้อความนี้ฉันกำหนดชื่อไว้อย่างถูกต้อง

ฉันขอขอบคุณสำหรับความช่วยเหลือในเรื่องนี้

ปรับปรุง

ขอบคุณสำหรับความช่วยเหลือของคุณ. ฉันทำผิดพลาดทางไวยากรณ์บางอย่างกับรหัสดัชนีควรจะใส่ '' อย่างไรก็ตามฉันยังคงได้รับปัญหาเดียวกันโดยใช้ฟังก์ชั่นที่ซับซ้อนมากขึ้นเช่น:

def my_test(a):
    cum_diff = 0
    for ix in df.index():
        cum_diff = cum_diff + (a - df['a'][ix])
    return cum_diff 

1
หลีกเลี่ยงการใช้applyมากที่สุด หากคุณไม่แน่ใจว่าคุณต้องใช้มันคุณอาจจะไม่ ฉันแนะนำให้ดูที่เมื่อไหร่ที่ฉันควรจะใช้แพนด้าใช้ในรหัสของฉัน? .
cs95

นี่เป็นเพียงข้อผิดพลาดทางไวยากรณ์ที่อ้างอิงถึงคอลัมน์ dataframe และทำไมฟังก์ชันจึงจำเป็นต้องมีอาร์กิวเมนต์ สำหรับคำถามที่สองของคุณฟังก์ชั่นmy_test(a)ไม่ทราบว่าเกิดอะไรขึ้นdfเพราะมันไม่ได้ผ่านการโต้เถียง (เว้นแต่dfว่าควรจะเป็นโลก คุณต้องส่งค่าทั้งหมดที่คุณต้องการภายในฟังก์ชันเป็นอาร์กิวเมนต์ (ควรเรียงตามลำดับ) มิฉะนั้นฟังก์ชันจะรู้ได้อย่างไรว่าdfมาจากไหน นอกจากนี้การใช้โปรแกรมในเนมสเปซที่ทิ้งกระจุยกระจายกับตัวแปรทั่วโลกเป็นเรื่องที่ไม่ถูกต้องคุณจะไม่พบข้อผิดพลาดเช่นนี้
smci

คำตอบ:


379

ดูเหมือนว่าคุณลืม''สตริงของคุณ

In [43]: df['Value'] = df.apply(lambda row: my_test(row['a'], row['c']), axis=1)

In [44]: df
Out[44]:
                    a    b         c     Value
          0 -1.674308  foo  0.343801  0.044698
          1 -2.163236  bar -2.046438 -0.116798
          2 -0.199115  foo -0.458050 -0.199115
          3  0.918646  bar -0.007185 -0.001006
          4  1.336830  foo  0.534292  0.268245
          5  0.976844  bar -0.773630 -0.570417

BTW ในความคิดของฉันวิธีต่อไปนี้จะสวยงามมากขึ้น:

In [53]: def my_test2(row):
....:     return row['a'] % row['c']
....:     

In [54]: df['Value'] = df.apply(my_test2, axis=1)

ขอบคุณคุณถูกต้องฉันลืม '' อย่างไรก็ตามฉันยังคงมีปัญหาเดียวกันกับฟังก์ชั่นที่ซับซ้อนมากขึ้น ฉันขอขอบคุณที่คุณช่วย ขอบคุณ
Andy

5
@ ติดตามต่อไปนี้ [53-54] อนุญาตให้คุณใช้ฟังก์ชันที่ซับซ้อนมากขึ้น
Andy Hayden

@Andy คุณสามารถกำหนดฟังก์ชั่นที่ซับซ้อนเช่น In [53]
awakuo

กลยุทธ์การประยุกต์ใช้ทั้งหมดมีประสิทธิภาพเท่ากันหรือไม่ ฉันเป็นคนใหม่สำหรับแพนด้าและพบว่าใช้เป็นปริศนาเล็กน้อย แต่กลยุทธ์ของคุณใน [53-54] นั้นง่ายสำหรับฉันที่จะเข้าใจ (และหวังว่าจะจำได้) ... บนโต๊ะขนาดใหญ่มันรวดเร็วเหมือนรูปแบบการสมัครอื่น ๆ นำเสนอ?
ทำไม

ทำไมการสร้างวิธีการที่แยกต่างหากจึงถือได้ว่ามีความสง่างามยิ่งขึ้น - แม้แต่สำหรับวิธีเล็ก ๆ ฉันได้ทำโครงการที่สำคัญในไพ ธ อนเป็นเวลา 7 ปีแล้ว แต่อาจจะไม่เคยได้รับการพิจารณาpythonistaเนื่องจากมุมมองบางอย่างรวมถึงโครงการนี้
javadba

33

หากคุณต้องการคำนวณ (คอลัมน์ a)% (คอลัมน์ b) คุณไม่จำเป็นต้องapplyทำโดยตรง

In [7]: df['a'] % df['c']                                                                                                                                                        
Out[7]: 
0   -1.132022                                                                                                                                                                    
1   -0.939493                                                                                                                                                                    
2    0.201931                                                                                                                                                                    
3    0.511374                                                                                                                                                                    
4   -0.694647                                                                                                                                                                    
5   -0.023486                                                                                                                                                                    
Name: a

16
ฉันรู้ว่ามันเป็นเพียงตัวอย่างเพื่อแสดงปัญหาของฉันในการใช้ฟังก์ชั่นกับหลายคอลัมน์
Andy

18

สมมติว่าเราต้องการใช้ฟังก์ชั่น add5 กับคอลัมน์ 'a' และ 'b' ของ DataFrame df

def add5(x):
    return x+5

df[['a', 'b']].apply(add5)

ฉันได้รับข้อผิดพลาดในการติดตามในขณะที่ลองใช้ข้อมูลโค้ดของคุณ TypeError: ('ต้องเป็น STR ไม่ใช่ int', 'เกิดขึ้นที่ดัชนี b') คุณช่วยกรุณาดูที่
debaonline4u

คอลัมน์ b ของ dataframe ของคุณคือประเภทสตริงหรือคอลัมน์ประเภทวัตถุควรเป็นคอลัมน์จำนวนเต็มที่จะเพิ่มด้วยตัวเลข
Mir_Murtaza

การเปลี่ยนแปลงจะใช้ไม่ได้หลังจากการมอบหมายเท่านั้น
S.aad

11

ทุกคำแนะนำข้างต้นการทำงาน แต่ถ้าคุณต้องการการคำนวณของคุณไปโดยมีประสิทธิภาพมากขึ้นคุณควรใช้ประโยชน์ของการดำเนินงานเวกเตอร์ numpy (ตามที่ชี้ให้เห็นที่นี่)

import pandas as pd
import numpy as np


df = pd.DataFrame ({'a' : np.random.randn(6),
             'b' : ['foo', 'bar'] * 3,
             'c' : np.random.randn(6)})

ตัวอย่างที่ 1: วนลูปด้วยpandas.apply():

%%timeit
def my_test2(row):
    return row['a'] % row['c']

df['Value'] = df.apply(my_test2, axis=1)

การวิ่งที่ช้าที่สุดนั้นใช้เวลานานกว่าการวิ่งที่เร็วที่สุดถึง 7.49 เท่า นี่อาจหมายความว่าผลลัพธ์ระหว่างกลางถูกแคช 1,000 ลูปดีที่สุด 3: 481 pers ต่อลูป

ตัวอย่างที่ 2: ใช้ vectorize โดยpandas.apply():

%%timeit
df['a'] % df['c']

การวิ่งที่ช้าที่สุดนั้นใช้เวลานานกว่าการวิ่งที่เร็วที่สุดถึง 458.85 เท่า นี่อาจหมายความว่าผลลัพธ์ระหว่างกลางถูกแคช 10000 ลูปดีที่สุด 3: 70.9 ไมโครกรัมต่อวง

ตัวอย่างที่ 3: vectorize โดยใช้อาร์เรย์ numpy:

%%timeit
df['a'].values % df['c'].values

การวิ่งที่ช้าที่สุดนั้นใช้เวลานานกว่าการวิ่งที่เร็วที่สุด 7.98 เท่า นี่อาจหมายความว่าผลลัพธ์ระหว่างกลางถูกแคช 100,000 ลูป, ดีที่สุดคือ 3: 6.39 pers ต่อลูป

ดังนั้นการใช้เวกเตอร์ด้วย numpy arrays จึงเพิ่มความเร็วได้เกือบสองออเดอร์


ผลลัพธ์เปลี่ยนไปมากขึ้นอย่างมากสำหรับคนจำนวนมากเช่นการแทนที่ 6 ด้วย 10K ฉันได้ 248 ms, 332 ,s, 263 respectivelys ตามลำดับ ดังนั้นโซลูชันเวกเตอร์ทั้งสองอยู่ใกล้กันมากขึ้น แต่โซลูชันที่ไม่ใช่เวกเตอร์นั้นช้ากว่า 1000 เท่า (ทดสอบกับ python-3.7)
stason

3

นี่เป็นวิธีเดียวกับโซลูชันก่อนหน้า แต่ฉันได้กำหนดฟังก์ชันใน df.apply แล้ว:

df['Value'] = df.apply(lambda row: row['a']%row['c'], axis=1)

2

ฉันได้ให้การเปรียบเทียบของทั้งสามที่กล่าวถึงข้างต้น

ใช้ค่านิยม

% timeit df ['value'] = df ['a']. ค่า% df ['c']. ค่า

139 ±s± 1.91 µs ต่อลูป (หมายถึง± std. dev จากการวิ่ง 7 ครั้งแต่ละลูป 10,000 ครั้ง)

โดยไม่มีค่า

% timeit df ['value'] = df ['a']% df ['c'] 

216 ±s± 1.86 pers ต่อลูป (หมายถึง± std. dev จากการวิ่ง 7 ครั้งแต่ละลูป 1,000 ครั้ง)

ใช้ฟังก์ชั่น

% timeit df ['Value'] = df.apply (แถวแลมบ์ดา: แถว ['a']% แถว ['c'], แกน = 1)

474 ±s± 5.07 pers ต่อลูป (หมายถึง± std. dev จากการวิ่ง 7 ครั้งแต่ละลูป 1,000 ครั้ง)

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