3

2 要素の階層インデックス ("month" と "item_id") を持つ pandas データフレームがあります。各行は特定の月の特定のアイテムを表し、いくつかの関心のある数値メジャーの列があります。詳細は関係ないので、ここでは目的のために列 X があるとだけ言います。

私の問題は、アイテムが観察された月によって、連続している場合もそうでない場合もあるという事実に起因しています。そのアイテムの観測がある 1、2、...、n 番目の月について、すべてのアイテムにわたって X の平均を計算する必要があります。

言い換えれば、私の結果の最初の行は、各アイテムのデータフレームの最初の行のすべてのアイテムの平均である必要があり、2 番目の結果行は、そのアイテムの 2 番目の観測のすべてのアイテムの平均である必要があります。 .

別の言い方をすれば、各アイテムの日付順に並べられたすべての行を取得し、i=1,2,...,n からそれらにインデックスを付ける場合、行 1,2 の値のすべてのアイテムの平均が必要です。 ...、ん。つまり、すべての項目にわたる各項目の最初の観測値の平均、すべての項目にわたる 2 番目の観測値の平均などを求めます。

どうすればこれを達成できますか?既存の日付インデックスを使用できないので、データフレームに別のインデックスを追加する必要がありますか (前の段落で説明したようなもの)、または各項目の行を反復処理して実行平均を維持する唯一の方法です? これは機能しますが、パンダの力をまったく活用していません。


サンプルデータの追加:

  item_id  date          X       DUMMY_ROWS
  20       2010-11-01    16759   0  
           2010-12-01    16961   1
           2011-01-01    17126   2
           2011-02-01    17255   3
           2011-03-01    17400   4
           2011-04-01    17551   5
  21       2007-09-01        4   6
           2007-10-01        5   7
           2007-11-01        6   8
           2007-12-01       10   9
  22       2006-05-01       10   10
           2006-07-01       13   11
  23       2006-05-01        2   12
  24       2008-01-01        2   13
           2008-02-01        9   14
           2008-03-01       18   15
           2008-04-01       19   16
           2008-05-01       23   17
           2008-06-01       32   18

説明のために、データに存在しないダミーの行列を追加しました。私が説明している操作は、行 0、6、10、12、および 13 (各項目の最初の観察) の平均を効果的に与え、次に行 1、7、11、および 15 (項目の 2 番目の観察) の平均を与えます。オブザベーションが 1 つしかないため、アイテム 23 を除く)、など。

4

2 に答える 2

3

1 つのオプションは、インデックスをリセットしてから ID でグループ化することです。

df_new = df.reset_index()
df_new.groupby(['item_id']).X.agg(np.mean) 

これにより、元の df はそのまま残り、各アイテム ID のすべての月の平均が得られます。

あなたの更新された質問(ちなみに素晴らしい例)については、同様のデータを持つパスでこれを行った「item_sequence_id」を追加することがアプローチになると思います。

df.sort(['item_id', 'date'], inplace = True)

def sequence_id(item):
    item['seq_id'] = range(0,len(item)-1,1)
    return item

df_with_seq_id = df.groupby(['item_id']).apply(sequence_id)
df_with_seq_id.groupby(['seq_id']).agg(np.mean)

ここでの考え方は、 一意ではない値を項目に割り当てることseq_idでデータ ポイントの位置を特定できるようにすることで、複数の項目をグループ化できるようにすることです。以前にこれを使用したコンテキストは、ユーザーがセッションで最初に何かを行うことに関連しています。この ID 構造を使用すると、絶対時間とユーザー ID に関係なく、ユーザーが実行した 1 回目、2 回目、3 回目などのすべてのアクションを識別できます。item_idseq_id

うまくいけば、これはあなたが望むもの以上のものです.

于 2013-10-21T03:29:58.897 に答える
0

これは、私が最終的に考え出した代替方法です (これは、平均を計算する目的で実際の日付を気にしないことを前提としています)。@cwharland によって提案された方法を思い出してください。

def sequence_id(item):
    item['seq'] = range(0,len(item),1)
    return item

shrinkWithSeqID_old = df.groupby(level='item_id').apply(sequence_id)

データ フレームの 10,000 行のサブセットでこれをテストします。

%timeit -n10 dfWithSeqID_old = shrink.groupby(level='item_id').apply(sequence_id)
10 loops, best of 3: 301 ms per loop

pandas のデフォルトの動作 (つまり、インデックス列を指定しない場合) は、0 から n (フレーム内の行数) までの番号が付けられたデータフレームの数値インデックスを生成することを覚えておくことで、物事を単純化できることがわかります。これを次のように活用できます。

dfWithSeqID_new = df.groupby(level='item_id').apply(lambda x: x.reset_index(drop=True))

出力の唯一の違いは、前の回答で使用された「seq」列と同じ内容の新しいラベルのない数値インデックスがあることですが、ほぼ 4 倍高速です (完全な 13 のメソッドを比較することはできません)。 100 万行のデータフレーム (最初の方法ではメモリ エラーが発生していたため):

%timeit -n10 dfWithSeqID_new = df.groupby(level='item_id').apply(lambda x: x.reset_index(drop=True))
10 loops, best of 3: 77.2 ms per loop

私の元の質問のように平均を計算することは、わずかに異なるだけです。元の方法は次のとおりです。

dfWithSeqID_old.groupby('seq').agg(np.mean).head()

しかし今は、「seq」列の代わりに新しいラベルなしインデックスを使用しているという事実を説明する必要があります。

dfWithSeqID_new.mean(level=1).head()

結果は同じです。

于 2013-10-31T22:37:03.040 に答える