Tại sao chức năng 'ứng dụng' của Pandas của tôi tham chiếu nhiều cột hoạt động? [đóng cửa]


239

Tôi có một số vấn đề với hàm áp dụng Pandas, khi sử dụng nhiều cột với khung dữ liệu sau

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

và các chức năng sau đây

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

Khi tôi cố gắng áp dụng chức năng này với:

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

Tôi nhận được thông báo lỗi:

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

Tôi không hiểu tin nhắn này, tôi đã xác định đúng tên.

Tôi đánh giá cao bất kỳ sự giúp đỡ nào về vấn đề này

Cập nhật

Cảm ơn bạn đã giúp đỡ. Tôi thực sự đã thực hiện một số lỗi cú pháp với mã, chỉ mục nên được đặt ''. Tuy nhiên tôi vẫn gặp vấn đề tương tự khi sử dụng một hàm phức tạp hơn, chẳng hạn như:

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

1
Tránh sử dụng applycàng nhiều càng tốt. Nếu bạn không chắc chắn bạn cần sử dụng nó, có lẽ bạn không nên. Tôi khuyên bạn nên xem khi nào tôi nên sử dụng gấu trúc áp dụng () trong mã của mình? .
cs95

Đây chỉ là về lỗi cú pháp tham chiếu cột cột dữ liệu và tại sao các hàm cần đối số. Đối với câu hỏi thứ hai của bạn, hàm my_test(a)không biết điều gì dfvì nó không được thông qua dưới dạng đối số (trừ khi dfđược cho là toàn cầu, đây sẽ là một thực tiễn khủng khiếp). Bạn cần chuyển tất cả các giá trị bạn sẽ cần bên trong một hàm dưới dạng đối số (tốt nhất là theo thứ tự), nếu không thì hàm sẽ biết dfnguồn gốc từ đâu? Ngoài ra, đó là cách thực hành tồi để lập trình trong một không gian tên chứa đầy các biến toàn cục, bạn sẽ không gặp phải các lỗi như thế này.
smci

Câu trả lời:


379

Có vẻ bạn đã quên ''chuỗi của bạn.

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, theo tôi, cách sau là thanh lịch hơn:

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

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

Cảm ơn, bạn nói đúng tôi đã quên ''. Tuy nhiên tôi vẫn có cùng một vấn đề với một chức năng phức tạp hơn. Tôi đánh giá cao sự giúp đỡ của bạn với điều đó. Cảm ơn
Andy

5
@Andy theo [53-54] cho phép bạn áp dụng các chức năng phức tạp hơn.
Andy Hayden

@Andy bạn có thể xác định chức năng phức tạp của mình như cách In [53].
Waitkuo

làm tất cả các chiến lược áp dụng thực hiện như nhau? Tôi mới làm quen với gấu trúc và luôn thấy áp dụng hơi khó hiểu nhưng chiến lược của bạn trong [53-54] rất dễ hiểu đối với tôi (và hy vọng là nhớ) ... trên một bàn lớn có nhanh như hình thức áp dụng khác không trình bày?
whytheq

Tại sao việc tạo ra một phương thức riêng biệt lại được coi là thanh lịch hơn - ngay cả đối với các phương thức nhỏ. Tôi đã thực hiện các dự án quan trọng trong python trong 7 năm nhưng có thể sẽ không bao giờ được coi là pythonistado một số quan điểm bao gồm cả quan điểm này.
javadba

33

Nếu bạn chỉ muốn tính toán (cột a)% (cột b), bạn không cần apply, chỉ cần thực hiện trực tiếp:

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
Tôi biết, đó chỉ là một ví dụ để chỉ ra vấn đề của tôi khi áp dụng một hàm cho nhiều cột
Andy

18

Giả sử chúng ta muốn áp dụng hàm add5 cho các cột 'a' và 'b' của DataFrame df

def add5(x):
    return x+5

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

Tôi đang gặp lỗi sau khi thử đoạn mã của bạn. LoạiError: ('phải là str, không phải int', 'xảy ra tại chỉ mục b') bạn có thể vui lòng xem xét điều đó không.
debaonline4u

Cột b của khung dữ liệu của bạn là cột kiểu chuỗi hoặc cột loại đối tượng, nó phải là cột số nguyên được thêm vào bằng một số.
Mir_Murtaza

Sẽ không thay đổi chỉ áp dụng sau khi chuyển nhượng?
S.aad

11

Tất cả các đề xuất ở trên đều hoạt động, nhưng nếu bạn muốn tính toán của mình hiệu quả hơn, bạn nên tận dụng các phép toán vectơ numpy (như được chỉ ra ở đây) .

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)})

Ví dụ 1: lặp với pandas.apply():

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

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

Chạy chậm nhất mất 7,49 lần so với nhanh nhất. Điều này có thể có nghĩa là một kết quả trung gian đang được lưu trữ. 1000 vòng lặp, tốt nhất trong 3: 480 lượt mỗi vòng

Ví dụ 2: vectorize bằng cách sử dụng pandas.apply():

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

Chạy chậm nhất mất 45,85 lần so với nhanh nhất. Điều này có thể có nghĩa là một kết quả trung gian đang được lưu trữ. 10000 vòng, tốt nhất là 3: 70,9 lượt mỗi vòng

Ví dụ 3: vectorize bằng cách sử dụng mảng numpy:

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

Chạy chậm nhất mất 7,98 lần so với nhanh nhất. Điều này có thể có nghĩa là một kết quả trung gian đang được lưu trữ. 100000 vòng, tốt nhất là 3: 6,39 lượt mỗi vòng

Vì vậy, vector hóa bằng cách sử dụng mảng numpy đã cải thiện tốc độ gần như hai bậc độ lớn.


Kết quả thậm chí còn thay đổi đáng kể hơn đối với các số lớn, ví dụ thay thế 6 bằng 10K, tôi nhận được lần lượt là 248 ms, 332 lượt, 263. Vì vậy, cả hai giải pháp vector hóa gần nhau hơn nhiều, nhưng giải pháp không vector hóa chậm hơn 1000 lần. (đã thử nghiệm trên python-3.7)
stason

3

Điều này giống như giải pháp trước đây nhưng tôi đã xác định hàm trong df.apply:

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

2

Tôi đã đưa ra so sánh của cả ba thảo luận ở trên.

Sử dụng các giá trị

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

139 Khen ± 1.91 Phát trên mỗi vòng lặp (trung bình ± std. Dev của 7 lần chạy, mỗi vòng 10000 vòng)

Không có giá trị

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

216 Vòng lặp ± 1,86 Vòng lặp trên mỗi vòng lặp (trung bình ± std. Dev của 7 lần chạy, mỗi vòng 1000 vòng)

Áp dụng chức năng

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

474 Nhận xét ± 5.07 Trao đổi trên mỗi vòng lặp (trung bình ± std. Dev của 7 lần chạy, mỗi vòng 1000 vòng)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.