2017-05-09 12 views
0

私は、コレクションをループしてpandasに変換し、条件付き合計と実行中の合計に基づいて各値を更新します。この関数は基本的にこのパンダは2番目の列に積算合計で適用されます

def calculate_value(): 
    cumulative_amount = 0 

    for row in rows: 
     if row['amount'] < 0: 
      return 0 

     amount = 0 

     if row['kind'] == 'A': 
      amount = row['amount'] * row['input_amount'] 
     elif row['kind'] == 'B': 
      amount = row['input_amount'] - cumulative_amount 
     elif row['kind'] == 'C': 
      amount = row['amount'] 

     cumulative_amount += amount 
     row['result'] = amount 

     if row['kind'] == 'B': 
      break 

    return rows 

、すべての行をループのように見える、とresult値を追加します。しかし、このresultは、累積稼働合計によって異なる場合があります。さらに、特定の値(row['kind'] == 'B')に達した場合、新しい行の処理を中断して停止する必要があります。

これをパンダに変換すると、applyを使用しているようです。これまでのところ、私はのコードをとしていますが、cumulative_amountshift(-1)としてみると、それはいつもnanに戻ります。

パンダでこれを行うにはどうすればよいですか?私はこれを正しく理解していれば

def calculate_value(row: Series): 
    if row['amount'] < 0 or row.shift(-1)['kind'] == 'B': 
     row['cumulative_amount'] = 0 
     row['result'] = 0 
     return row 

    amount = 0 

    if np.isnan(row.shift(-1)['cumulative_amount']): 
     cumulative_amount = 0 
    else: 
     cumulative_amount = row.shift(-1)['cumulative_amount'] 

    if row['kind'] == 'A': 
     amount = row['amount'] * row['input_amount'] 
    elif row['kind'] == 'B': 
     amount = row['input_amount'] - cumulative_amount 
    elif row['kind'] == 'C': 
     amount = row['amount'] 

    row['cumulative_amount'] = amount + cumulative_amount 
    row['result'] = amount 
    return row 

df['cumulative_amount'] = 0 
new_df = df.apply(lambda x: calculate_value(x), axis=1) 

入力し、所望の出力の例は

df = pd.DataFrame({ 
    'kind': {1: 'C', 2: 'E', 3: 'A', 4: 'A', 5: 'B', 6: 'C'}, 
    'amount': {1: -800, 2: 100, 3: 0.5, 4: 0.5, 5: 0, 6: 200}, 
    'input_amount': {1: 800, 2: 800, 3: 800, 4: 800, 5: 800, 6: 800} 
}) 

    amount input_amount kind cumulative_amount result 
1 -800.0   800 C    0.0  0.0 
2 100.0   800 E    0.0  0.0 
3  0.5   800 A    400.0 400.0 
4  0.5   800 A    800.0 400.0 
5  0.0   800 B    800.0  0.0 
6 200.0   800 C    800.0  0.0 
+0

同じ入力データフレームと予想される出力を提供できますか? –

+0

@ScottBostonが完了しました。 –

+0

'apply'は、行ごとに動作し、計算中にデータフレームの他の行にアクセスすることは期待されないので、ここでの良いアプローチのようには見えません。あなたの最初の解決策は私にとっては絶対に素晴らしいと思われます。 –

答えて

1

あり、唯一result種類'B'ためには、他の行に依存します。だから、最初に他のすべての操作を実行して起動することができます。

df['result'] = 0. 

a = (df.kind == 'A') & (df.amount >= 0) 
c = (df.kind == 'C') & (df.amount >= 0) 

df.loc[a, 'result'] = df.loc[a, 'amount'] * df.loc[a, 'input_amount'] 
df.loc[c, 'result'] = df.loc[c, 'amount'] 

はCUMSUMを行います

df['cumulative_amount'] = df.result.cumsum() 

'cumulative_amount'(タイプ'B'のためのすべての出現)の値を修正:

df.loc[(df.kind == 'B'), 'result'] = df.loc[(df.kind == 'B'), 'input_amount'].values - df.loc[(df.kind.shift(-1) == 'B'), 'cumulative_amount'].values 

が最初に出現した後に'result''cumulative_amount'の値を修正してください:

df.loc[(df.kind == 'B').cumsum().shift() > 0, 'result'] = 0 
# (df.kind == 'B').cumsum().shift() is a running count of the number of B's encountered prior to the row index, 
# so you want to 'stop' once this number is no longer zero 
# You could of course do this more simply by figuring out which position in the index has the first B, 
# then using .ix or .iloc, but it's actually longer to type out. 

df['cumulative_amount'] = df.result.cumsum() # Once more, because we've changed the value of results below B. 
+0

これは素晴らしい、ありがとう。 –

関連する問題