web-dev-qa-db-ja.com

pandas dataframeの条件付き代入をベクトル化する

dfのデータフレームxがあり、これを疑似コードで使用してyの値に基づいて列xを作成する場合:

 if df['x'] <-2 then df['y'] = 1 
 else if df['x'] > 2 then df['y']= -1 
 else df['y'] = 0

どうすればこれを達成できますか?私が想定し np.whereがこれを行う最良の方法ですが、正しくコーディングする方法がわかりません。

26
azuric

1つの簡単な方法は、最初にデフォルト値を割り当ててから、2つのloc呼び出しを実行することです。

In [66]:

df = pd.DataFrame({'x':[0,-3,5,-1,1]})
df
Out[66]:
   x
0  0
1 -3
2  5
3 -1
4  1

In [69]:

df['y'] = 0
df.loc[df['x'] < -2, 'y'] = 1
df.loc[df['x'] > 2, 'y'] = -1
df
Out[69]:
   x  y
0  0  0
1 -3  1
2  5 -1
3 -1  0
4  1  0

np.whereを使用する場合は、ネストされたnp.whereを使用できます。

In [77]:

df['y'] = np.where(df['x'] < -2 , 1, np.where(df['x'] > 2, -1, 0))
df
Out[77]:
   x  y
0  0  0
1 -3  1
2  5 -1
3 -1  0
4  1  0

したがって、ここでは、xが-2より小さい場合の最初の条件を定義し、1を返します。次に、xが2より大きく、-1を返す他の条件をテストする別のnp.whereがあります。それ以外の場合は0を返します。

タイミング

In [79]:

%timeit df['y'] = np.where(df['x'] < -2 , 1, np.where(df['x'] > 2, -1, 0))

1000 loops, best of 3: 1.79 ms per loop

In [81]:

%%timeit
df['y'] = 0
df.loc[df['x'] < -2, 'y'] = 1
df.loc[df['x'] > 2, 'y'] = -1

100 loops, best of 3: 3.27 ms per loop

したがって、このサンプルデータセットの場合、np.whereメソッドは2倍高速です。

26
EdChum

これはpd.cutの良い使用例で、範囲を定義し、それらに基づいてrangesを割り当てることができますlabels

df['y'] = pd.cut(df['x'], [-np.inf, -2, 2, np.inf], labels=[1, 0, -1], right=False)

出力

   x  y
0  0  0
1 -3  1
2  5 -1
3 -1  0
4  1  0
1
Erfan