2016-09-09 31 views
3

移動距離のデータフレーム(df)があり、特定の条件に基づいてラベルを割り当てました。Pythonのループのために最適化

distance=[0,0.0001,0.20,1.23,4.0] 
df = pd.DataFrame(distance,columns=["distance"]) 
df['label']=0 
for i in range(0, len(df['distance'])): 
     if (df['distance'].values[i])<=0.10: 
      df['label'][i]=1 
     elif (df['distance'].values[i])<=0.50: 
      df['label'][i]=2 
     elif (df['distance'].values[i])>0.50: 
      df['label'][i]=3 

これは正常です。しかし、私は距離が100万を超えるレコードを持っていますが、このforループは予想よりも長い時間がかかります。実行時間を短縮するためにこのコードを最適化できますか?

+2

...'おそらく 'else:' – depperm

+0

となりました。おそらく、2番目のelifはb '0.10 Andrew

+0

2つの方法:das ['label'] [i] = 1'はエラーを作成しません'df ['label']'を '0'に設定しますか?そして:あなたがpython2かpython3を使っているのかどうかわかりませんが、python2は 'range'を' xrange'で置き換えます – kratenko

答えて

3

一般に、絶対に必要でない限り、DataFramesをループしないでください。すでに最適化されている組み込みのPandas関数を使用するか、ベクトル化された手法を使用して、より良いパフォーマンスを得ることができます。

このケースでは、割り当てを行うにはlocBoolean indexingを使用することができます。

# Initialize as 1 (eliminate need to check the first condition). 
df['label'] = 1 

# Case 1: Between 0.1 and 0.5 
df.loc[(df['distance'] > 0.1) & (df['distance'] <= 0.5), 'label'] = 2 

# Case 2: Greater than 0.5 
df.loc[df['distance'] > 0.5, 'label'] = 3 

別のオプションはpd.cutを使用することです。これは、問題の例題に少しだけ特化した方法です。ブール索引付けはより一般的な方法です。

# Get the low and high bins. 
low, high = df['distance'].min()-1, df['distance'].max()+1 

# Perform the cut. Add one since the labels start at zero by default. 
df['label'] = pd.cut(df['distance'], bins=[low, 0.1, 0.5, high], labels=False) + 1 

また、上記のコードでlabels=[1,2,3]を使用して、結果に1を追加できませんでした。これは、整数dtypeの代わりにdf['labels']categorical dtypeを与えるでしょう。あなたのユースケースに応じて、これは重要かもしれません。

いずれかの方法の結果の出力:

distance label 
0 0.0000  1 
1 0.0001  1 
2 0.2000  2 
3 1.2300  3 
4 4.0000  3 
ビンにラベルを割り当てることによって
0

スライスのコピーに値を設定する旨の警告が表示されますが、誰かがよりクリーンな方法を提案する可能性がありますか?

距離に基づいてサブアレイを取得して、それから必要な値を書き込むためのファンシーインデックスに基づいています。

df.loc[:, "label"][df.loc[:, "distance"] <= 0.1] = 1 
df.loc[:, "label"][(0.1 < df.loc[:, "distance"]) & (df.loc[:, "distance"] <= 0.5)] = 2 
df.loc[:, "label"][df.loc[:, "distance"] > 0.5] = 3 

EDIT:連鎖インデックスなしで新しく改良されました。

1

使用cut:私はあなたがあれば、最後の `のelifマイクロ秒をオフに剃ることができると思い

pd.cut(df.distance, [-np.inf, 0.1, 0.5, np.inf], labels=[1,2,3]) 

0 1 
1 1 
2 2 
3 3 
4 3