2017-07-01 5 views
0

私はこれをいつか行っていて、うまくいかないようです。私は、次のような2つのレベルのマルチインデックスデータフレームを扱っています:マルチインデックスデータフレーム内で連続したイベントをカウントするパンダ

def data(): 
    data = {'date': pd.Series(['2016-1-1', '2016-1-1', '2016-1-1', 
           '2016-1-2', '2016-1-2', '2016-1-2', 
           '2016-1-3', '2016-1-3', '2016-1-3', 
           '2016-1-4', '2016-1-4', '2016-1-4', 
           '2016-1-5', '2016-1-5', '2016-1-5']), 
      'group': pd.Series(['groupA', 'groupB', 'groupC', 
           'groupA', 'groupB', 'groupC', 
           'groupA', 'groupB', 'groupC', 
           'groupA', 'groupB', 'groupC', 
           'groupA', 'groupB', 'groupC']), 
      'series1': pd.Series([1, 2, 3, 
            1, 2, 3, 
            1, 2, 3, 
            1, 3, 4, 
            2, 3, 4]), 
      'series2': pd.Series([1, 3, 4, 
           2, 3, 3, 
           2, 4, 2, 
           1, 2, 3, 
           1, 2, 3])} 
    df = pd.DataFrame(data) 
    df['date'] = pd.to_datetime(df['date']) 
    df.set_index(['date', 'group'], inplace=True) 
return df 

私は3つの条件の1つを指定する列を持っています。コードのこの部分を書くためのより簡潔な方法があるかもしれませんが、これは私の問題ではありません。

def add_cond(df): 
    df['1minus2'] = df['series1'] - df['series2'] 
    # first condition 
    mask1 = df['series1'] < df['series2'] 
    df.loc[mask1, 'result'] = 'less' 
    # second condition 
    mask2 = df['series1'] > df['series2'] 
    df.loc[mask2, 'result'] = 'greater' 
    # third condition 
    mask3 = df['series1'] == df['series2'] 
    df.loc[mask3, 'result'] = 'equal' 
return df 

私の問題は、毎日の連続条件の数をカウントする列を追加したいということです。私はgroupbycumcountのいくつかの異なる実装を試して、私はすべての条件の累積カウントを得ることができますが、私はそれらが日付インデックスが連続していないときにリセットしたい。

以下、私が試したいくつかの関連記事をリストアップしました。私はPandas: conditional rolling countの2番目の答えは動作すると思ったが、複数の列があるのでここでは動作しないようなtransformメソッドを使用する。

ポストFinding consecutive segments in a pandas data frameに概略が記載されている戦略に従って、私はのnumpy arraysを作成し、日付とグループのインデックス値と「結果」列のデータを含むコードを作成しました。私はこのような方法でこのdfをスライスして、連続する各グループを数え、その結果を元のdfにマージすることができると考えています。

df1 = df.reset_index(level=['date','group']).groupby(['result']).apply(np.array) 

出力は次のようになります。

1 
1 
1 
1 
2 
1 
2 
3 
1 
1 
1 
2 
1 
2 
3 

それは、累積の連続した条件は、階層DF構造で満たされているかどうかを確認するために少し難しいですが、私はDFスタックを解除場合、それは私が達成しようとしているものを見るためにはるかに簡単です。おそらく、unstackを使用して、私が探している結果を与えるような方法でデータを方向付ける方法がありますか?

df['result'].groupby(['date','group']).head().unstack() 

Out[9]: 
group  groupA groupB groupC 
date         
2016-01-01 equal  less  less 
2016-01-02  less  less equal 
2016-01-03  less  less greater 
2016-01-04 equal greater greater 
2016-01-05 greater greater greater 
+0

私はあなたが探している正確な力学に関する多くの明確にすることができると思います。 'date'カラムと何が関係しているのかは分かりません(関連性がありますか)。また、 'np.sign(series1 - series2)'が 'add_cond()'を行う良い方法であることに注意してください。 –

+0

ありがとう@ジョン・ツィンク私はどのように明らかにするかを見ていきます。元のコードではnp.signを使用していましたが、ゼロが記号の変化としてどのように評価され、ラムダ内で使用したときに、私が望むように動作させることができなかったのが好きではありませんでした。 – Greg

答えて

2

のはgroupbycumcountで、このアプローチを使用してみましょう:

df = data() 
df1 = add_con(df) 
df1['Consec'] = df1[['result']].groupby(['group','result']).cumcount() + 1 

は出力:

    series1 series2 1minus2 result Consec 
date  group            
2016-01-01 groupA  1  1  0 equal  1 
      groupB  2  3  -1  less  1 
      groupC  3  4  -1  less  1 
2016-01-02 groupA  1  2  -1  less  1 
      groupB  2  3  -1  less  2 
      groupC  3  3  0 equal  1 
2016-01-03 groupA  1  2  -1  less  2 
      groupB  2  4  -2  less  3 
      groupC  3  2  1 greater  1 
2016-01-04 groupA  1  1  0 equal  2 
      groupB  3  2  1 greater  1 
      groupC  4  3  1 greater  2 
2016-01-05 groupA  2  1  1 greater  1 
      groupB  3  2  1 greater  2 
      groupC  4  3  1 greater  3 
+0

なぜ 'df1 ['Consec'] = df1 [['result']]。groupby ...'? 'assign'の必要はありません。コードをより冗長で効率的にしません。 –

+0

@ScottBostonありがとうございます。私が書いたとおりに実行すると、私は 'KeyError:group'エラーを受け取ります。私はそれをちょっと並べ替えて... 'groupby(level = 'group')['result']' ...を実行すると実行されますが、結果が間違っています。何か案が? – Greg

+0

さて、私のバージョンをアップグレードします。ちょうどチェックして、私は0.18.1です。ご協力いただきありがとうございます! – Greg

関連する問題