2017-01-11 15 views
7

Xem xét việc này gấu trúc ví dụ nơi tôi đang tính toán cột C bằng cách nhân A với Bfloat nếu một điều kiện nhất định được đáp ứng bằng apply với một chức năng lambda:Pandas: Làm thế nào để áp dụng trên dataframe nhanh hơn?

import pandas as pd 
df = pd.DataFrame({'A':[1,2,3,4,5,6,7,8,9],'B':[9,8,7,6,5,4,3,2,1]}) 

df['C'] = df.apply(lambda x: x.A if x.B > 5 else 0.1*x.A*x.B, axis=1) 

Kết quả dự kiến ​​sẽ là:

A B C 
0 1 9 1.0 
1 2 8 2.0 
2 3 7 3.0 
3 4 6 4.0 
4 5 5 2.5 
5 6 4 2.4 
6 7 3 2.1 
7 8 2 1.6 
8 9 1 0.9 

Vấn đề là mã này chậm và tôi cần thực hiện thao tác này trên một khung dữ liệu với khoảng 56 triệu hàng.

Các %timeit -result của hoạt động lambda trên là:

1000 loops, best of 3: 1.63 ms per loop 

Đi từ thời gian tính toán và cũng sử dụng bộ nhớ khi làm điều này trên dataframe lớn của tôi, tôi đoán hoạt động này sử dụng hàng loạt trung gian trong khi làm các tính toán .

Tôi đã cố gắng xây dựng nó theo nhiều cách khác nhau bao gồm sử dụng các cột tạm thời, nhưng mọi giải pháp thay thế mà tôi đưa ra thậm chí còn chậm hơn.

Có cách nào để có được kết quả tôi cần theo cách khác và nhanh hơn, ví dụ: bằng cách sử dụng numpy?

+0

Bạn nên xem xét 'numpy.where'. – IanS

Trả lời

6

Đối với hiệu suất, bạn có thể được tốt hơn làm việc với mảng NumPy và sử dụng np.where -

a = df.values # Assuming you have two columns A and B 
df['C'] = np.where(a[:,1]>5,a[:,0],0.1*a[:,0]*a[:,1]) 

Runtime kiểm tra

def numpy_based(df): 
    a = df.values # Assuming you have two columns A and B 
    df['C'] = np.where(a[:,1]>5,a[:,0],0.1*a[:,0]*a[:,1]) 

Thời gian -

In [271]: df = pd.DataFrame(np.random.randint(0,9,(10000,2)),columns=[['A','B']]) 

In [272]: %timeit numpy_based(df) 
1000 loops, best of 3: 380 µs per loop 

In [273]: df = pd.DataFrame(np.random.randint(0,9,(10000,2)),columns=[['A','B']]) 

In [274]: %timeit df['C'] = df.A.where(df.B.gt(5), df[['A', 'B']].prod(1).mul(.1)) 
100 loops, best of 3: 3.39 ms per loop 

In [275]: df = pd.DataFrame(np.random.randint(0,9,(10000,2)),columns=[['A','B']]) 

In [276]: %timeit df['C'] = np.where(df['B'] > 5, df['A'], 0.1 * df['A'] * df['B']) 
1000 loops, best of 3: 1.12 ms per loop 

In [277]: df = pd.DataFrame(np.random.randint(0,9,(10000,2)),columns=[['A','B']]) 

In [278]: %timeit df['C'] = np.where(df.B > 5, df.A, df.A.mul(df.B).mul(.1)) 
1000 loops, best of 3: 1.19 ms per loop 

nhìn Closer

Chúng ta hãy xem xét kỹ hơn ở vị trí thứ NumPy của crunching khả năng và so sánh với gấu trúc vào trộn -

# Extract out as array (its a view, so not really expensive 
# .. as compared to the later computations themselves) 

In [291]: a = df.values 

In [296]: %timeit df.values 
10000 loops, best of 3: 107 µs per loop 

Case # 1: Làm việc với mảng NumPy và sử dụng NumPy.nơi:

In [292]: %timeit np.where(a[:,1]>5,a[:,0],0.1*a[:,0]*a[:,1]) 
10000 loops, best of 3: 86.5 µs per loop 

Một lần nữa, gán vào một cột mới: df['C'] sẽ không thể rất đắt tiền, hoặc -

In [300]: %timeit df['C'] = np.where(a[:,1]>5,a[:,0],0.1*a[:,0]*a[:,1]) 
1000 loops, best of 3: 323 µs per loop 

Case # 2: Làm việc với gấu trúc dataframe và sử dụng phương pháp .where của nó (không NumPy)

In [293]: %timeit df.A.where(df.B.gt(5), df[['A', 'B']].prod(1).mul(.1)) 
100 loops, best of 3: 3.4 ms per loop 

Case # 3: Làm việc với gấu trúc dataframe (không mảng NumPy), nhưng sử dụng numpy.where -

In [294]: %timeit np.where(df['B'] > 5, df['A'], 0.1 * df['A'] * df['B']) 
1000 loops, best of 3: 764 µs per loop 

Case # 4: Làm việc với gấu trúc dataframe một lần nữa (không có mảng NumPy), nhưng sử dụng numpy.where -

In [295]: %timeit np.where(df.B > 5, df.A, df.A.mul(df.B).mul(.1)) 
1000 loops, best of 3: 830 µs per loop 
+0

Bạn đánh tôi với nó, nhưng 'numpy.where' chơi tốt với loạt gấu trúc, và tôi tin rằng phiên bản của tôi dễ đọc hơn;) – IanS

+1

@IanS OP yêu cầu nhanh hơn. Điều này mang lại cho tất cả mọi thứ vào numpy cho phép hiệu quả hơn. – piRSquared

+0

@IanS NumPy chơi tốt với số crunching và chắc chắn với dataframes, ít nhất là tôi biết! ;) – Divakar

3

Sử dụng numpy.where:

df['C'] = numpy.where(df['B'] > 5, df['A'], 0.1 * df['A'] * df['B']) 
2

Sử dụng:

df['C'] = np.where(df.B > 5, df.A, df.A.mul(df.B).mul(.1)) 
print (df) 
    A B C 
0 1 9 1.0 
1 2 8 2.0 
2 3 7 3.0 
3 4 6 4.0 
4 5 5 2.5 
5 6 4 2.4 
6 7 3 2.1 
7 8 2 1.6 
8 9 1 0.9 
+0

'mul' không khác lắm' * ', phải không? ;) – IanS

+1

Tôi làm một số nghiên cứu và có vẻ như nếu sử dụng 'df.A * df.B' và' df.A.mul (df.B) 'thì' mul' nhanh hơn. Nhưng nếu nhiều bởi hằng số, là như nhau. – jezrael

+1

@IanS cũng thuận tiện cho việc ghép chuỗi – piRSquared

4

tinh khiết pandas
sử dụng pd.Series.where

df['C'] = df.A.where(df.B.gt(5), df[['A', 'B']].prod(1).mul(.1)) 

    A B C 
0 1 9 1.0 
1 2 8 2.0 
2 3 7 3.0 
3 4 6 4.0 
4 5 5 2.5 
5 6 4 2.4 
6 7 3 2.1 
7 8 2 1.6 
8 9 1 0.9 
+0

tốt đẹp, sản phẩm nhanh hơn như mul? – jezrael

+0

có thể ... hầu như không – piRSquared

+0

Tôi tự hỏi tại sao tốc độ này chậm hơn 3 lần so với các câu trả lời khác ... – IanS

Các vấn đề liên quan