【问题标题】:Why does pandas groupby().transform() require a unique index?为什么 pandas groupby().transform() 需要唯一索引?
【发布时间】:2025-12-03 16:50:02
【问题描述】:

我想使用 groupby().transform() 对(排序的)数据集中的每个记录块进行自定义(累积)转换。除非我确保我有一个唯一的密钥,否则它不起作用。为什么?

这是一个玩具示例:

df = pd.DataFrame([[1,1],
                  [1,2],
                  [2,3],
                  [3,4],
                  [3,5]], 
                  columns='a b'.split())
df['partials'] = df.groupby('a')['b'].transform(np.cumsum)
df

给出预期:

     a   b   partials
0    1   1   1
1    1   2   3
2    2   3   3
3    3   4   4
4    3   5   9

但如果 'a' 是一个键,那么一切都会出错:

df = df.set_index('a')
df['partials'] = df.groupby(level=0)['b'].transform(np.cumsum)
df

---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-146-d0c35a4ba053> in <module>()
      3 
      4 df = df.set_index('a')
----> 5 df.groupby(level=0)['b'].transform(np.cumsum)

/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pandas/core/groupby.pyc in transform(self, func, *args, **kwargs)
   1542             res = wrapper(group)
   1543             # result[group.index] = res
-> 1544             indexer = self.obj.index.get_indexer(group.index)
   1545             np.put(result, indexer, res)
   1546 

/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pandas/core/index.pyc in get_indexer(self, target, method, limit)
    847 
    848         if not self.is_unique:
--> 849             raise Exception('Reindexing only valid with uniquely valued Index '
    850                             'objects')
    851 

Exception: Reindexing only valid with uniquely valued Index objects

如果您在分组之前选择列“b”也会出现同样的错误,即。

df['b'].groupby(level=0).transform(np.cumsum)

但如果你转换整个数据框,你可以让它工作,比如:

df.groupby(level=0).transform(np.cumsum)

甚至是单列数据框(而不是系列):

df.groupby(level=0)[['b']].transform(np.cumsum)

我觉得GroupBy-fu 的某些深层部分我仍然缺少。谁能直截了当?

【问题讨论】:

  • 是的,这就是我想要的——“a”组中“b”的部分总和。我澄清了上面的插图。在我的实际示例中,'a' 是时间戳,b 是其他一些键,因此我的数据集实际上是不同长度的时间序列的集合(它们在时间上重叠并包含组内和组间的重复时间戳)。我正在使用 transform() 对每个时间序列段进行累积操作,例如移动平均线等。

标签: python pandas


【解决方案1】:

这是一个错误,因为已在 pandas 中修复(当然在 0.15.2 中,IIRC 已在 0.14 中修复),所以您应该不再看到此异常。


作为一种解决方法,在早期的 pandas 中,您可以使用 apply

In [10]: g = df.groupby(level=0)['b']

In [11]: g.apply(np.cumsum)
Out[11]:
a
1    1
1    3
2    3
3    4
3    9
dtype: int64

您可以将其分配给 df 中的列

In [12]: df['partial'] = g.apply(np.cumsum)

【讨论】:

  • 酷,谢谢 - 我想我不明白 apply() 和 transform() 之间的区别。变换是否在某种程度上更具限制性??
  • @patricksurry 我想知道这是否是一个错误,它看起来确实应该适合转换类别...
  • @patricksurry tranform 期望组中的所有事物都有一个结果,而 apply 期望组中的每一行都有一个值。虽然这两个组的行为(子 DataFrames)所以有点令人困惑。
  • 这是有道理的,但似乎没有很清楚地记录在案。例如here,它首先将 transform 描述为 apply 的一种形式,后来使它们听起来几乎等价:“...对于这些,请使用 apply 函数,它可以在许多标准用例中替代聚合和转换. 但是,apply 可以处理一些特殊的用例,例如..."