3

我有一个带有两元素分层索引(“月”和“item_id”)的熊猫数据框。每行代表特定月份的特定项目,并具有用于几个感兴趣的数字度量的列。细节无关紧要,所以我们只是说我们在这里有 X 列。

我的问题源于这样一个事实,即项目在他们观察到的月份中会有所不同,这可能是连续的,也可能不是连续的。我需要计算所有项目中 X 的平均值,在第 1 个月、第 2 个月、...、第 n 个月中,有该项目的观察值。

换句话说,我的结果中的第一行应该是每个项目的数据框中第一行的所有项目的平均值,第二个结果行应该是该项目的第二个观察的所有项目的平均值,依此类推.

换句话说,如果我们要为每个项目获取所有按日期排序的行并从 i=1,2,...,n 索引它们,我需要所有项目的平均值为第 1,2 行的值, ...,n。也就是说,我想要所有项目中每个项目的第一次观察的平均值,所有项目的第二次观察的平均值,依此类推。

我怎样才能最好地做到这一点?我不能使用现有的日期索引,所以我需要向数据框添加另一个索引(就像我在上一段中描述的那样),还是我唯一的办法是遍历每个项目的行并保持运行平均值? 这会起作用,但没有利用 pandas 的任何力量。


添加一些示例数据:

  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 行的平均值(第二次观察每个项目,不包括项目 23,因为它只有一个观察值),依此类推。

4

2 回答 2

3

一种选择是重置索引,然后按 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。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百万行数据帧,因为第一种方法导致内存错误):

%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 回答