Câu trả lời hàng đầu là thiếu sót theo ý kiến của tôi. Hy vọng rằng không ai nhập hàng loạt tất cả gấu trúc vào không gian tên của chúng với from pandas import *
. Ngoài ra, map
phương thức nên được dành riêng cho những thời điểm khi chuyển nó vào từ điển hoặc Chuỗi. Nó có thể có một chức năng nhưng đây là những gì apply
được sử dụng.
Vì vậy, nếu bạn phải sử dụng cách tiếp cận trên, tôi sẽ viết nó như thế này
df["A1"], df["A2"] = zip(*df["a"].apply(calculate))
Thực ra không có lý do gì để sử dụng zip ở đây. Bạn chỉ có thể làm điều này:
df["A1"], df["A2"] = calculate(df['a'])
Phương pháp thứ hai này cũng nhanh hơn nhiều trên DataFrames lớn hơn
df = pd.DataFrame({'a': [1,2,3] * 100000, 'b': [2,3,4] * 100000})
DataFrame được tạo với 300.000 hàng
%timeit df["A1"], df["A2"] = calculate(df['a'])
2.65 ms ± 92.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit df["A1"], df["A2"] = zip(*df["a"].apply(calculate))
159 ms ± 5.24 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Nhanh hơn 60 lần so với zip
Nói chung, tránh sử dụng apply
Áp dụng thường không nhanh hơn nhiều so với việc lặp qua danh sách Python. Hãy kiểm tra hiệu suất của vòng lặp for để làm điều tương tự như trên
%%timeit
A1, A2 = [], []
for val in df['a']:
A1.append(val**2)
A2.append(val**3)
df['A1'] = A1
df['A2'] = A2
298 ms ± 7.14 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Vì vậy, tốc độ này chậm gấp đôi, đây không phải là một hồi quy hiệu suất khủng khiếp, nhưng nếu chúng ta điều khiển mạng ở trên, chúng ta sẽ có được hiệu suất tốt hơn nhiều. Giả sử, bạn đang sử dụng ipython:
%load_ext cython
%%cython
cpdef power(vals):
A1, A2 = [], []
cdef double val
for val in vals:
A1.append(val**2)
A2.append(val**3)
return A1, A2
%timeit df['A1'], df['A2'] = power(df['a'])
72.7 ms ± 2.16 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Chỉ định trực tiếp mà không cần áp dụng
Bạn có thể nhận được những cải tiến tốc độ thậm chí lớn hơn nếu bạn sử dụng các hoạt động vector trực tiếp.
%timeit df['A1'], df['A2'] = df['a'] ** 2, df['a'] ** 3
5.13 ms ± 320 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Điều này tận dụng các hoạt động vector hóa cực kỳ nhanh của NumPy thay vì các vòng lặp của chúng tôi. Bây giờ chúng tôi có tốc độ tăng gấp 30 lần so với ban đầu.
Kiểm tra tốc độ đơn giản nhất với apply
Ví dụ trên sẽ cho thấy rõ mức độ chậm apply
có thể xảy ra, nhưng để nó rõ ràng hơn, hãy xem ví dụ cơ bản nhất. Hãy bình phương một Chuỗi 10 triệu số có và không áp dụng
s = pd.Series(np.random.rand(10000000))
%timeit s.apply(calc)
3.3 s ± 57.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Không áp dụng nhanh hơn 50 lần
%timeit s ** 2
66 ms ± 2 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)