如何获取itertools._grouper对象中各组的实例数量?
问题描述
我有如下DataFrame:
from itertools import groupby import pandas as pd idx1 = pd.date_range('2019-01-01',periods=5) idx2 = pd.date_range('2020-06-01',periods=5) idx3 = pd.date_range('2021-08-15',periods=5) idx4 = pd.date_range('2022-03-20',periods=5) idx = idx1.union(idx2).union(idx3).union(idx4) l = [1,-1,-4,2,-3,4,5,1,-3,-4,-5,-3,-4,2,3,-1,-2,3,2,3] df = pd.DataFrame(l, index=idx, columns=['a']) df
输出结果:
a 2019-01-01 1 2019-01-02 -1 2019-01-03 -4 2019-01-04 2 2019-01-05 -3 2020-06-01 4 2020-06-02 5 2020-06-03 1 2020-06-04 -3 2020-06-05 -4 2021-08-15 -5 2021-08-16 -3 2021-08-17 -4 2021-08-18 2 2021-08-19 3 2022-03-20 -1 2022-03-21 -2 2022-03-22 3 2022-03-23 2 2022-03-24 3
用itertools.groupby按值是否小于0分组求和可以正常运行:
for k,g in groupby(df['a'], lambda x: x<0): print(k, sum(g))
输出:
False 1 True -5 False 2 True -3 False 10 True -19 False 5 True -3 False 8
但尝试用len()获取每个分组的实例数量时,出现了错误:
for k,g in groupby(df['a'], lambda x: x<0): print(k,len(g))
报错信息:
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Input In [241], in <cell line: 1>() 1 for k,g in groupby(df['a'], lambda x: x<0): ----> 2 print(k,len(g)) TypeError: object of type 'itertools._grouper' has no len()
解决方案
itertools.groupby返回的_grouper对象是迭代器,不是可直接获取长度的序列,因此不能直接用len()。可以通过以下两种方式解决:
方法1:将迭代器转为列表后取长度
把分组迭代器转换成列表,再用len()统计元素数量:
for k,g in groupby(df['a'], lambda x: x<0): group_items = list(g) print(k, len(group_items))
输出:
False 1 True 2 False 1 True 1 False 3 True 3 False 2 True 2 False 3
方法2:用生成器表达式计数
通过生成器表达式遍历迭代器并计数,避免额外创建列表:
for k,g in groupby(df['a'], lambda x: x<0): count = sum(1 for _ in g) print(k, count)
输出结果和方法1完全一致。
更贴合Pandas的实现方式
既然已经使用Pandas,推荐直接用Pandas的分组功能来实现,更高效且符合Pandas的使用逻辑(注意要模拟itertools.groupby的连续相同分组逻辑):
# 创建是否为负数的标识列 df['is_negative'] = df['a'] < 0 # 生成连续分组的唯一ID(当分组标识变化时,ID自增) df['group_id'] = (df['is_negative'] != df['is_negative'].shift()).cumsum() # 按分组ID和标识统计数量 result = df.groupby(['group_id', 'is_negative'])['a'].count().reset_index() print(result[['is_negative', 'a']])
输出:
is_negative a 0 False 1 1 True 2 2 False 1 3 True 1 4 False 3 5 True 3 6 False 2 7 True 2 8 False 3
内容的提问来源于stack exchange,提问作者jgg
相关产品推荐
相关产品推荐

