Tôi đang sử dụng khung dữ liệu Pandas và muốn tạo một cột mới làm chức năng của các cột hiện có. Tôi đã không thấy một cuộc thảo luận tốt về sự khác biệt tốc độ giữa df.apply()
và np.vectorize()
, vì vậy tôi nghĩ tôi sẽ hỏi ở đây.
apply()
Chức năng Pandas chậm. Từ những gì tôi đo được (hiển thị bên dưới trong một số thử nghiệm), việc sử dụng np.vectorize()
nhanh hơn 25 lần (hoặc hơn) so với sử dụng chức năng DataFrame apply()
, ít nhất là trên MacBook Pro 2016 của tôi. Đây có phải là một kết quả mong đợi, và tại sao?
Ví dụ: giả sử tôi có khung dữ liệu sau với N
các hàng:
N = 10
A_list = np.random.randint(1, 100, N)
B_list = np.random.randint(1, 100, N)
df = pd.DataFrame({'A': A_list, 'B': B_list})
df.head()
# A B
# 0 78 50
# 1 23 91
# 2 55 62
# 3 82 64
# 4 99 80
Giả sử thêm rằng tôi muốn tạo một cột mới dưới dạng một hàm của hai cột A
và B
. Trong ví dụ dưới đây, tôi sẽ sử dụng một hàm đơn giản divide()
. Để áp dụng chức năng, tôi có thể sử dụng df.apply()
hoặc np.vectorize()
:
def divide(a, b):
if b == 0:
return 0.0
return float(a)/b
df['result'] = df.apply(lambda row: divide(row['A'], row['B']), axis=1)
df['result2'] = np.vectorize(divide)(df['A'], df['B'])
df.head()
# A B result result2
# 0 78 50 1.560000 1.560000
# 1 23 91 0.252747 0.252747
# 2 55 62 0.887097 0.887097
# 3 82 64 1.281250 1.281250
# 4 99 80 1.237500 1.237500
Nếu tôi tăng lên N
kích thước trong thế giới thực như 1 triệu hoặc hơn, thì tôi quan sát thấy con số đó np.vectorize()
nhanh hơn 25 lần hoặc hơn df.apply()
.
Dưới đây là một số mã điểm chuẩn hoàn chỉnh:
import pandas as pd
import numpy as np
import time
def divide(a, b):
if b == 0:
return 0.0
return float(a)/b
for N in [1000, 10000, 100000, 1000000, 10000000]:
print ''
A_list = np.random.randint(1, 100, N)
B_list = np.random.randint(1, 100, N)
df = pd.DataFrame({'A': A_list, 'B': B_list})
start_epoch_sec = int(time.time())
df['result'] = df.apply(lambda row: divide(row['A'], row['B']), axis=1)
end_epoch_sec = int(time.time())
result_apply = end_epoch_sec - start_epoch_sec
start_epoch_sec = int(time.time())
df['result2'] = np.vectorize(divide)(df['A'], df['B'])
end_epoch_sec = int(time.time())
result_vectorize = end_epoch_sec - start_epoch_sec
print 'N=%d, df.apply: %d sec, np.vectorize: %d sec' % \
(N, result_apply, result_vectorize)
# Make sure results from df.apply and np.vectorize match.
assert(df['result'].equals(df['result2']))
Các kết quả được hiển thị dưới đây:
N=1000, df.apply: 0 sec, np.vectorize: 0 sec
N=10000, df.apply: 1 sec, np.vectorize: 0 sec
N=100000, df.apply: 2 sec, np.vectorize: 0 sec
N=1000000, df.apply: 24 sec, np.vectorize: 1 sec
N=10000000, df.apply: 262 sec, np.vectorize: 4 sec
Nếu np.vectorize()
nói chung luôn luôn nhanh hơn df.apply()
, thì tại sao np.vectorize()
không được đề cập nhiều hơn? Tôi chỉ thấy các bài đăng trên StackOverflow liên quan đến df.apply()
, chẳng hạn như:
gấu trúc tạo cột mới dựa trên các giá trị từ các cột khác
Làm cách nào để sử dụng chức năng 'áp dụng' của Pandas cho nhiều cột?
np.vectorize
về cơ bản là một con trănfor
vòng lặp (đó là một phương pháp tiện lợi) vàapply
với một lambda cũng là trong thời gian trăn