2016-07-06 17 views
2

pandas apply/mapとなり、小規模なデータセットでさえ、辛抱強く遅くなる可能性があります。以下は速度の差が3桁近くある非常に単純な例です。以下では、100万の値を持つSeriesを作成し、0.5以上の値を「はい」に、0.5未満の値を「いいえ」にマップしたいと考えています。これをベクトル化するか、それを大幅に高速化するにはどうすればよいですか?非常に単純なパンダラムダ関数をベクトル化すると、

ser = pd.Series(np.random.rand(1000000)) 

# vectorized and fast 
%%timeit 
ser > .5 

千ループ、3の最もよい:ループ当たり477マイクロ秒

%%timeit 
ser.map(lambda x: 'Yes' if x > .5 else 'No') 

1ループ、3の最もよい:ループ

答えて

6

np.where(cond, A, B)当たり255ミリ秒A if cond else Bのベクトルと等価である:

import numpy as np 
import pandas as pd 
ser = pd.Series(np.random.rand(1000000)) 
mask = ser > 0.5 
result = pd.Series(np.where(mask, 'Yes', 'No')) 
expected = ser.map(lambda x: 'Yes' if x > .5 else 'No') 
assert result.equals(expected) 

In [77]: %timeit mask = ser > 0.5 
1000 loops, best of 3: 1.44 ms per loop 

In [76]: %timeit np.where(mask, 'Yes', 'No') 
100 loops, best of 3: 14.8 ms per loop 

In [73]: %timeit pd.Series(np.where(mask, 'Yes', 'No')) 
10 loops, best of 3: 86.5 ms per loop 

In [74]: %timeit ser.map(lambda x: 'Yes' if x > .5 else 'No') 
1 loop, best of 3: 223 ms per loop 

このシリーズは2つのだけの値を持っているので、あなたが代わりにCategoricalを使用して検討するかもしれない:

In [94]: cat = pd.Categorical.from_codes(codes=mask.astype(int), categories=['Yes', 'No']); cat 
Out[94]: 
[No, Yes, No, Yes, Yes, ..., Yes, No, Yes, Yes, No] 
Length: 1000000 
Categories (2, object): [Yes, No] 

In [95]: %timeit pd.Categorical.from_codes(codes=mask.astype(int), categories=['Yes', 'No']); cat 
100 loops, best of 3: 6.26 ms per loop 

だけでなく、この高速です、それは文字列の配列を作成回避するので、それはより多くのメモリ効率的です。カテゴリコードは、カテゴリにマップされるintの配列です。

In [96]: cat.codes 
Out[96]: array([1, 0, 1, ..., 0, 0, 1], dtype=int8) 

In [97]: cat.categories 
Out[99]: Index(['Yes', 'No'], dtype='object') 
+0

ありがとうございました。これは非常によく見えます。約40倍のスピードアップですが、まっすぐなベクトル化されたブール比較よりも約1桁遅いです。 –

関連する問題