【问题标题】:Aggregate list of dictionary in bins by applying weighted average in Python通过在 Python 中应用加权平均来聚合 bin 中的字典列表
【发布时间】:2019-02-03 11:41:58
【问题描述】:

我有一个字典列表,如下所示:

_input = [{'cumulated_quantity': 30, 'price': 7000, 'quantity': 30},
         {'cumulated_quantity': 80, 'price': 7002, 'quantity': 50},
         {'cumulated_quantity': 130, 'price': 7010, 'quantity': 50},
         {'cumulated_quantity': 330, 'price': 7050, 'quantity': 200},
         {'cumulated_quantity': 400, 'price': 7065, 'quantity': 70}]

我想将字典分组到数量为 100 的箱中,其中价格计算为加权平均值。结果应如下所示:

result = [{'cumulated_quantity': 100, 'price': 7003, 'quantity': 100},
          {'cumulated_quantity': 200, 'price': 7038, 'quantity': 100},
          {'cumulated_quantity': 300, 'price': 7050, 'quantity': 100},
          {'cumulated_quantity': 400, 'price': 7060.5, 'quantity': 100}]

结果字典中的加权平均值计算如下:

7003 = (30*7000+50*7002+20*7010)/100 
7038 = (30*7010+70*7050)/100
7050 = 100*7050/100
7060.5 = (30*7050+70*7065)/100

通过使用 pandas 数据帧,我设法收到了结果,但是它们的性能太慢了(大约 0.5 秒)。在python中有没有快速的方法来做到这一点?

【问题讨论】:

  • 如何定义垃圾箱?垃圾箱 'cumulated_quantity': 100 是为 'cumulated_quantity'<=100 设计的吗?
  • bin 大小是任意选择的,它将是一个变量。如果 cumulated_quantity

标签: python list dictionary weighted-average


【解决方案1】:

不使用 pandas,自己动手几乎是瞬间完成的:

result = []
cumulative_quantity = 0
bucket = {'price': 0.0, 'quantity': 0}
for dct in lst:
    dct_quantity = dct['quantity']  # enables non-destructive decrementing
    while dct_quantity > 0:
        if bucket['quantity'] == 100:
            bucket['cumulative_quantity'] = cumulative_quantity
            result.append(bucket)
            bucket = {'price': 0.0, 'quantity': 0}
        added_quantity = min([dct_quantity, 100 - bucket['quantity']])
        bucket['price'] = (bucket['price'] * bucket['quantity'] + dct['price'] * added_quantity) / (bucket['quantity'] + added_quantity)
        dct_quantity -= added_quantity
        bucket['quantity'] += added_quantity
        cumulative_quantity += added_quantity
if bucket['quantity'] != 0:
    bucket['cumulative_quantity'] = cumulative_quantity
    result.append(bucket)

给予

>>> result
[{'cumulative_quantity': 100, 'price': 7003.0, 'quantity': 100}, 
 {'cumulative_quantity': 200, 'price': 7038.0, 'quantity': 100}, 
 {'cumulative_quantity': 300, 'price': 7050.0, 'quantity': 100}, 
 {'cumulative_quantity': 400, 'price': 7060.5, 'quantity': 100}]

这可以线性完成,如 O(p),其中 p 是部分数(相当于 O(n * k),其中 k 是每个 dict 必须分成的平均片段数(在您的示例中为 k = 1.6))。

【讨论】:

  • 我最初的 pandas 解决方案与此相比太慢了,很好的回复,谢谢。
【解决方案2】:
BIN_SIZE = 100

cum_quantity = 0
value = 0.
bin_quantity = 0
bin_value = 0
results = []

for record in _input:
    price, quantity = record['price'], record['quantity']
    while quantity:
        prior_quantity = bin_quantity
        bin_quantity = min(BIN_SIZE, bin_quantity + quantity)
        quantity_delta = bin_quantity - prior_quantity
        bin_value += quantity_delta * price
        quantity -= quantity_delta
        if bin_quantity == BIN_SIZE:
            avg_price = bin_value / float(BIN_SIZE)
            cum_quantity += BIN_SIZE
            bin_quantity = bin_value = 0  # Reset bin values.
            results.append({'cumulated_quantity': cum_quantity,
                            'price': avg_price,
                            'quantity': BIN_SIZE})


# Add stub for anything left in remaining bin (optional).
if bin_quantity:
    results.append({'cumulated_quantity': cum_quantity + bin_quantity,
                    'price': bin_value / float(bin_quantity),
                    'quantity': bin_quantity})

>>> results
[{'cumulated_quantity': 100, 'price': 7003.0, 'quantity': 100},
 {'cumulated_quantity': 200, 'price': 7038.0, 'quantity': 100},
 {'cumulated_quantity': 300, 'price': 7050.0, 'quantity': 100},
 {'cumulated_quantity': 400, 'price': 7060.5, 'quantity': 100}]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-04
    • 2021-08-31
    • 1970-01-01
    相关资源
    最近更新 更多