首页 > 解决方案 > 不使用 pandas 分组

问题描述

我有一个 csv 文件,样本看起来像,

year   product   country
2018    food       us
2018    drink      uk
2019    food       uk
2019    car      japan
2018    food     japan

我可以在不使用 pandas 或 numpy 等软件包的情况下按年份对信息进行分组吗?我知道我们可以先使用标准包读取输入csv

f = open('text.csv')
csv_f = csv.reader(f)

for row in csv_f:
  ////////

我的预期输出是,

year   product    product_sum
2018    food         2
2018    drink        1
2019    food         1
2019    car          1

标签: pythoncsvdictionarytextreduce

解决方案


您可以使用collections.Counter来计算出现次数。

f = open('text.csv')
csv_f = csv.reader(f)
next(csv_f, None)  # Ignore header row

c = collections.Counter((year, product) for year, product, country in csv_f)
print(c)
# Output: Counter({('2018', 'food'): 2, ('2018', 'drink'): 1, ('2019', 'food'): 1, ('2019', 'car'): 1})

要将其写回 CSV 文件,您可以使用.items()和列表推导将其转换回平面列表并使用writerows.

with open('output.csv', 'w') as csvfile:
  writer = csv.writer(csvfile)
  writer.writerow(('year', 'product', 'product_sum'))
  writer.writerows([(key[0], key[1], value) for key, value in c.items()])

注意:对于 Python 2,使用iteritems()而不是items().


你可以使用reduce这个问题,但我个人觉得这不是很自然也不是很 Pythonic。但无论如何,这就是它的完成方式。

def reduce_func(acc, update):
  year, product, country = update
  acc[(year, product)] += 1
  return acc

resultdict = reduce(reduce_func,
                    csv_f,
                    collections.defaultdict(lambda: 0))

print(resultdict)
# Output: defaultdict(<function <lambda> at 0x1007042f0>, {('2018', 'food'): 2, ('2018', 'drink'): 1, ('2019', 'food'): 1, ('2019', 'car'): 1})

如果您出于某种原因不想/不能使用collections.Counter,我建议您使用 Amal TS 的答案来循环构建字典。


推荐阅读