2017-10-20 13 views
0

私はかなり具体的なアルゴリズムを持っています。次のようにpandasデータフレームの値を行と列の条件に基づいて設定する

基本的に私は、データフレームを持っている:

 month taken score 
1  1  2  23 
2  1  1  34 
3  1  2  12 
4  1  2  59 
5  2  1  12 
6  2  2  23 
7  2  1  43 
8  2  2  45 
9  3  1  43 
10  3  2  43 
11  4  1  23 
12  4  2  94 

は、私が「スコア」カラムは、その月の終わりまで連続== 2を撮影した日に100に変更されるように、それを作りたいです。その月の間に、次のいずれかの日に撮影した== 1

を持っているのであれば、撮影した== 2のないすべての出現は、そのスコアが100に設定されている、だから私はしたいと思う結果は次のとおりです。

 month taken score 
1  1  2  23 
2  1  1  34 
3  1  2  100 
4  1  2  100 
5  2  1  12 
6  2  2  23 
7  2  1  43 
8  2  2  100 
9  3  1  43 
10  3  2  43 
11  3  1  23 
12  3  2  100 
13  4  1  32 
14  4  2  100 

私はそれを行う必要があると感じ、このコードを書いている:

#iterate through months 
for month in range(12): 
    #iterate through scores 
    for score in range(len(df_report.loc[df_report['month'] == month+1])): 
     #starting from the bottom, of that month, if 'taken' == 2... 
     if df_report.loc[df_report.month==month+1, 'taken'].iloc[-score-1] == 2: 
      #then set the score to 100 
      df_report.loc[df_report.month==month+1, 'score'].iloc[-score-2] = 100 
     #if you run into a 'taken' == 1, move on to next month 
     else: break 

ただし、これはエラーを投げていないにも関わらず...それはまた、私にエラーを与えるものではありません、任意の値を変更するには表示されません。コピーされたデータフレームに値を設定すること。

私が間違っていることを誰でも説明できますか?原稿が触れないように

+0

が、それはあなたがしていることだろう勝者は@coldspeedですコピーのコピーを新しい値で設定します。 * locコールを連鎖させるのはベスト・アイデアではありません。 –

+0

あなたは正しいと思いますが、これをどのように解決できますか?また、.locがコピーでなく、.ilocがコピーでない場合、.locの.ilocがコピーになるのはなぜですか? – James

答えて

2

あなたの値が更新されていない理由はilocへの割り当てでは、前のloc呼び出しによって返さコピーを更新します。


これにはどのように対処しますか。まず、関数fooを定義します。今

def foo(df): 
    for i in reversed(df.index): 
     if df.loc[i, 'taken'] != 2: 
      break 
     df.loc[i, 'score'] = 100 
     i -= 1 
    return df 

groupby monthと呼ん foo

明らか
df = df.groupby('month').apply(foo) 
print(df) 
    month taken score 
1  1  2  23 
2  1  1  34 
3  1  2 100 
4  1  2 100 
5  2  1  12 
6  2  2  23 
7  2  1  43 
8  2  2 100 
9  3  1  43 
10  3  2 100 
11  4  1  23 
12  4  2 100 

applyは、その欠点を持っていますが、私はこの問題へのベクトル化のアプローチを考えることはできません。

+0

私も。私はforループを取り除くことができますが、groupbyに適用するアプローチではありません – Dark

+0

ありがとう、これは完全に動作します – James

2

あなたが行うことができます

import numpy as np 
def get_value(x): 
    s = x['taken'] 
    # Get a mask of duplicate sequeence and change values using np.where 
    mask = s.ne(s.shift()).cumsum().duplicated(keep=False) 
    news = np.where(mask,100,x['score']) 

    # if last number is 2 then change the news value to 100 
    if s[s.idxmax()] == 2: news[-1] = 100 
    return pd.Series(news) 

df['score'] = df.groupby('month').apply(get_value).values 

出力:

 
    month taken score 
1  1  2  23 
2  1  1  34 
3  1  2 100 
4  1  2 100 
5  2  1  12 
6  2  2  23 
7  2  1  43 
8  2  2 100 
9  3  1  43 
10  3  2 100 
11  4  1  23 
12  4  2 100 

ほぼ同じ速さが、私は推測していた場合

ndf = pd.concat([df]*10000).reset_index(drop=True) 

%%timeit 
ndf['score'] = ndf.groupby('month').apply(foo) 
10 loops, best of 3: 40.8 ms per loop 


%%timeit 
ndf['score'] = ndf.groupby('month').apply(get_value).values 
10 loops, best of 3: 42.6 ms per loop 
+1

これは単純な繰り返しよりも優れていますか? –

+0

私はスピードを確認する必要はありません – Dark

+0

@cᴏʟᴅsᴘᴇᴇᴅ非常に非常にwierd。私のPCでデータフレームがどのくらい大きくなっても、その差は2ミリ秒です。 – Dark

関連する問題