不使用 pandas 分组
Group by without using 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
有多种方法可以做到这一点。使用树或简单的字典。
此解决方案假定分组依据中的字段是相邻的。只需稍作更改,您就可以概括或探索基于树的方法以获得简洁的解决方案。
f = open('text.csv')
delim = "\t"
header = f.readline()
group_dict = {}
for l in f.readlines():
key = delim.join(l.split()[:2])
if key not in group_dict:
group_dict[key] = 0
group_dict[key] +=1
f2 = open('output.txt','w')
f2.write(header)
for k,v in group_dict.items():
f2.write(delim.join([k,str(v)])+'\n')```
您可以使用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()])
注:对于Python2,使用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 的答案来循环构建字典。
我有一个 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
有多种方法可以做到这一点。使用树或简单的字典。
此解决方案假定分组依据中的字段是相邻的。只需稍作更改,您就可以概括或探索基于树的方法以获得简洁的解决方案。
f = open('text.csv')
delim = "\t"
header = f.readline()
group_dict = {}
for l in f.readlines():
key = delim.join(l.split()[:2])
if key not in group_dict:
group_dict[key] = 0
group_dict[key] +=1
f2 = open('output.txt','w')
f2.write(header)
for k,v in group_dict.items():
f2.write(delim.join([k,str(v)])+'\n')```
您可以使用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()])
注:对于Python2,使用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 的答案来循环构建字典。