让我们假设一个非常简单的数据结构。在下面的示例中,ID是唯一的。 “date”和“id”是字符串,“amount”是整数。
data = [[date1, id1, amount1], [date2, id2, amount2], etc.]
如果date1 == date2
和id1 == id2
,我想将这两个条目合并为一个,基本上将amount1和amount2相加,以便数据变为:
data = [[date1, id1, amount1 + amount2], etc.]
有许多重复。
由于数据非常大(超过100,000个条目),我希望尽可能高效地完成这项工作。我所做的是创建了一个新的“常用”字段,基本上将date + id组合成一个带有元数据的字符串,允许我稍后将其拆分(date + id + "_" + str(len(date)
)。
就复杂性而言,我有四个循环:
我不关心这里的记忆,我只关心速度。我可以做一个嵌套循环并避免步骤2,3和4,但这将是一个时间复杂性的灾难(O(n²))。
最快的方法是什么?
答案 0 :(得分:3)
考虑使用defaultdict
按唯一键聚合数据:
<强>鉴于强>
一些随机数据
import random
import collections as ct
random.seed(123)
# Random data
dates = ["2018-04-24", "2018-05-04", "2018-07-06"]
ids = "A B C D".split()
amounts = lambda: random.randrange(1, 100)
ch = random.choice
data = [[ch(dates), ch(ids), amounts()] for _ in range(10)]
data
输出
[['2018-04-24', 'C', 12],
['2018-05-04', 'C', 14],
['2018-04-24', 'D', 69],
['2018-07-06', 'C', 44],
['2018-04-24', 'B', 18],
['2018-05-04', 'C', 90],
['2018-04-24', 'B', 1],
['2018-05-04', 'A', 77],
['2018-05-04', 'A', 1],
['2018-05-04', 'D', 14]]
<强>代码强>
dd = ct.defaultdict(int)
for date, id_, amt in data:
key = "{}{}_{}".format(date, id_, len(date))
dd[key] += amt
dd
输出
defaultdict(int,
{'2018-04-24B_10': 19,
'2018-04-24C_10': 12,
'2018-04-24D_10': 69,
'2018-05-04A_10': 78,
'2018-05-04C_10': 104,
'2018-05-04D_10': 14,
'2018-07-06C_10': 44})
<强>详情
defaultdict
是一个字典,可以为任何缺失的键调用default factory(指定的函数)。在这种情况下,每个date
+ id
组合都会唯一地添加到dict中。如果找到现有密钥,则会将amounts
添加到值中。否则,整数(0
)初始化dict的新条目。
为了便于说明,您可以使用list
作为默认工厂来显示聚合值。
dd = ct.defaultdict(list)
for date, id_, val in data:
key = "{}{}_{}".format(date, id_, len(date))
dd[key].append(val)
dd
输出
defaultdict(list,
{'2018-04-24B_10': [18, 1],
'2018-04-24C_10': [12],
'2018-04-24D_10': [69],
'2018-05-04A_10': [77, 1],
'2018-05-04C_10': [14, 90],
'2018-05-04D_10': [14],
'2018-07-06C_10': [44]})
我们看到三次出现重复键,其值正确相加。关于效率,请注意:
format()
创建的,字符串连接和调用str()
答案 1 :(得分:1)
使用pandas
使这非常简单:
import pandas as pd
df = pd.DataFrame(data, columns=['date', 'id', 'amount'])
df.groupby(['date','id']).sum().reset_index()
要获得更多控制权,您可以使用agg
代替sum()
:
df.groupby(['date','id']).agg({'amount':'sum'})
根据您对数据的处理方式,这样做可能更容易/更快,因为大量的pandas都是基于编译的C扩展和优化的例程构建的,这使得转换和操作非常容易。
答案 2 :(得分:0)
您可以将数据导入到防止重复的结构中,然后将其转换为列表。
data = {
date1: {
id1: amount1,
id2: amount2,
},
date2: {
id3: amount3,
id4: amount4,
....
}
该计划的骨架:
ddata = collections.defaultdict(dict)
for date, id, amount in DATASOURCE:
ddata[date][id] = amount
data = [[d, i, a] for d, subd in ddata.items() for i, a in subd.items()]