Áp dụng hàm với nhiều đối số để tạo cột gấu trúc mới


165

Tôi muốn tạo một cột mới trong pandaskhung dữ liệu bằng cách áp dụng một hàm cho hai cột hiện có. Theo câu trả lời này, tôi đã có thể tạo một cột mới khi tôi chỉ cần một cột làm đối số:

import pandas as pd
df = pd.DataFrame({"A": [10,20,30], "B": [20, 30, 10]})

def fx(x):
    return x * x

print(df)
df['newcolumn'] = df.A.apply(fx)
print(df)

Tuy nhiên, tôi không thể tìm ra cách làm điều tương tự khi hàm yêu cầu nhiều đối số. Ví dụ: làm cách nào để tạo cột mới bằng cách chuyển cột A và cột B sang hàm bên dưới?

def fxy(x, y):
    return x * y

Câu trả lời:


136

Ngoài ra, bạn có thể sử dụng chức năng cơ bản numpy:

>>> import numpy as np
>>> df = pd.DataFrame({"A": [10,20,30], "B": [20, 30, 10]})
>>> df['new_column'] = np.multiply(df['A'], df['B'])
>>> df
    A   B  new_column
0  10  20         200
1  20  30         600
2  30  10         300

hoặc vector hóa hàm tùy ý trong trường hợp chung:

>>> def fx(x, y):
...     return x*y
...
>>> df['new_column'] = np.vectorize(fx)(df['A'], df['B'])
>>> df
    A   B  new_column
0  10  20         200
1  20  30         600
2  30  10         300

2
Cảm ơn câu trả lời! Tôi tò mò, đây có phải là giải pháp nhanh nhất?
MV23

6
Phiên bản vector hóa sử dụng np.vectorize()là nhanh đáng kinh ngạc. Cảm ơn bạn.
stackoverflowuser2010

Đây là một giải pháp hữu ích. Nếu kích thước của các đối số đầu vào của hàm x và y không bằng nhau, bạn sẽ gặp lỗi. Trong trường hợp đó, giải pháp @RomanPekar hoạt động mà không gặp vấn đề gì. Tôi đã không so sánh hiệu suất.
Ehsan Sadr

Tôi biết đây là một câu trả lời cũ, nhưng: Tôi có một trường hợp cạnh, trong đó np.vectorizekhông hoạt động. Lý do là, một trong những cột thuộc loại pandas._libs.tslibs.timestamps.Timestamp, được biến thành loại numpy.datetime64bằng cách vector hóa. Hai loại không thể thay thế cho nhau, khiến chức năng hoạt động kém. Bất kỳ đề nghị về điều này? (Khác với .applyđiều này rõ ràng là cần tránh)
ElRudi

Giải pháp tuyệt vời! trong trường hợp bất cứ ai đang tự hỏi vectorize hoạt động tốt và siêu nhanh cho các chức năng so sánh chuỗi là tốt.
infiniteloop

227

Bạn có thể đi với ví dụ @greenAfrican, nếu bạn có thể viết lại chức năng của mình. Nhưng nếu bạn không muốn viết lại chức năng của mình, bạn có thể gói nó thành chức năng ẩn danh bên trong ứng dụng, như thế này:

>>> def fxy(x, y):
...     return x * y

>>> df['newcolumn'] = df.apply(lambda x: fxy(x['A'], x['B']), axis=1)
>>> df
    A   B  newcolumn
0  10  20        200
1  20  30        600
2  30  10        300

4
Đây là một mẹo tuyệt vời và nó để lại các tham chiếu cột gần lệnh gọi áp dụng (thực tế trong đó). Tôi đã sử dụng mẹo này và mẹo đầu ra nhiều cột @toto_tico được cung cấp để tạo hàm 3 cột trong, 4 cột ra! Hoạt động tuyệt vời!
RufusVS

7
Ồ, có vẻ như bạn là người duy nhất không tập trung vào ví dụ tối thiểu của OP nhưng giải quyết toàn bộ vấn đề, cảm ơn, chính xác là những gì tôi cần! :)
Matt

38

Điều này giải quyết vấn đề:

df['newcolumn'] = df.A * df.B

Bạn cũng có thể làm:

def fab(row):
  return row['A'] * row['B']

df['newcolumn'] = df.apply(fab, axis=1)

10
Câu trả lời này giải quyết ví dụ đồ chơi này và sẽ đủ để tôi viết lại chức năng thực tế của mình, nhưng nó không giải quyết làm thế nào để áp dụng một chức năng được xác định trước đó mà không viết lại nó vào các cột tham chiếu.
Michael

23

Nếu bạn cần tạo nhiều cột cùng một lúc :

  1. Tạo khung dữ liệu:

    import pandas as pd
    df = pd.DataFrame({"A": [10,20,30], "B": [20, 30, 10]})
  2. Tạo chức năng:

    def fab(row):                                                  
        return row['A'] * row['B'], row['A'] + row['B']
  3. Chỉ định các cột mới:

    df['newcolumn'], df['newcolumn2'] = zip(*df.apply(fab, axis=1))

1
Tôi đã tự hỏi làm thế nào tôi có thể tạo nhiều cột với một lần áp dụng! Tôi đã sử dụng điều này với câu trả lời của @Roman Pekar để tạo hàm 3 cột trong, 4 cột ra! Hoạt động tuyệt vời!
RufusVS

15

Thêm một cú pháp kiểu dict:

df["new_column"] = df.apply(lambda x: x["A"] * x["B"], axis = 1)

hoặc là,

df["new_column"] = df["A"] * df["B"]
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.