
在库存管理和订单处理场景中,我们经常会遇到需要将不同价格的商品分配给多个客户订单的情况。一个典型的场景是,商品以不同的批次或在不同时间点采购,导致其成本(或售价)存在差异。当客户下订单时,通常会遵循“先进先出”或“成本最低优先”的原则进行分配。我们的目标是,在满足客户订单需求的同时,计算出每位客户为其所购商品支付的平均价格。
假设我们有以下数据:
关键约束和条件:
我们的任务是计算出每位客户的平均购买价格。
一种直观但低效的方法是创建一个巨大的数组,将所有商品的单价“展开”到这个数组中,然后根据客户订单的起始和结束索引来计算平均值。
import numpy as np
orders = np.array([21, 6, 3], dtype=np.int64)
quantity = np.array([16, 14], dtype=np.int64)
price = np.array([30.5, 35.5], dtype=np.double)
# 步骤1: 创建一个包含所有商品单价的“扁平化”数组
start = 0
total_supply_units = np.sum(quantity)
supply_prices_flat = np.zeros(total_supply_units, dtype=np.double)
for i, quant in enumerate(quantity):
idx = start + quant
supply_prices_flat[start:idx] = price[i]
start = idx
print("扁平化商品价格数组:", supply_prices_flat)
# 步骤2: 根据客户订单计算平均价格
fin_avg_prices = []
current_pos = 0
for order_size in orders:
idx = current_pos + order_size
fin_avg_prices.append(np.mean(supply_prices_flat[current_pos:idx]))
current_pos = idx
print("每位客户的平均价格 (低效方法):", fin_avg_prices)输出示例:
扁平化商品价格数组: [30.5 30.5 30.5 30.5 30.5 30.5 30.5 30.5 30.5 30.5 30.5 30.5 30.5 30.5 30.5 30.5 35.5 35.5 35.5 35.5 35.5 35.5 35.5 35.5 35.5 35.5 35.5 35.5 35.5 35.5] 每位客户的平均价格 (低效方法): [31.69047619047619, 35.5, 35.5]
局限性: 当商品总数量 np.sum(quantity) 非常大时,supply_prices_flat 数组会变得极其庞大,导致严重的内存消耗和性能问题。这种方法在处理大规模数据集时是不可接受的。
NumPy提供了强大的向量化操作,可以避免显式循环和创建大型中间数组。我们可以利用 np.repeat 和 np.add.reduceat 来高效地解决这个问题。
import numpy as np
orders = np.array([21, 6, 3], dtype=np.int64)
quantity = np.array([16, 14], dtype=np.int64)
price = np.array([30.5, 35.5], dtype=np.double)
# 步骤1: 使用 np.repeat 展开价格
# np.repeat(price, quantity) 会根据 quantity 中指定的次数重复 price 中的每个元素。
# 例如,如果 price=[P1, P2] 和 quantity=[Q1, Q2],结果将是 [P1, ..., P1 (Q1次), P2, ..., P2 (Q2次)]
repeated_prices = np.repeat(price, quantity)
# 结果: [30.5, ..., 30.5 (16次), 35.5, ..., 35.5 (14次)]
# 步骤2: 计算 reduceat 的索引
# np.cumsum(orders) 计算订单数量的累积和,用于确定每个客户订单在 repeated_prices 中的结束位置。
# np.r_[0, ...] 会在累积和数组前添加一个0,表示第一个客户订单的起始位置。
# [:-1] 移除最后一个元素,因为 reduceat 的索引是每个段的起始位置。
# 例如,orders=[21, 6, 3],cumsum=[21, 27, 30],indices=[0, 21, 27]
indices = np.r_[0, np.cumsum(orders)][:-1]
# 步骤3: 使用 np.add.reduceat 计算每个客户订单的总成本
# np.add.reduceat(array, indices) 会在指定索引处“切分” array,并对每个切分段进行求和。
# 这将直接计算出每个客户订单的总成本。
total_cost_per_customer = np.add.reduceat(repeated_prices, indices)
# 步骤4: 计算平均价格
# 将每个客户的总成本除以其订单数量,得到平均价格。
average_price_per_customer = total_cost_per_customer / orders
print("每位客户的平均价格 (高效NumPy方法):", average_price_per_customer)输出:
每位客户的平均价格 (高效NumPy方法): [31.69047619 35.5 35.5 ]
此函数用于重复数组 a 中的元素。repeats 可以是一个整数(所有元素重复相同次数),也可以是一个与 a 形状相同的数组(每个元素重复不同次数)。 在本例中,np.repeat(price, quantity) 的作用是根据 quantity 数组中每个对应的数量,将 price 数组中的价格值进行重复。这有效地模拟了将所有单独的商品单位及其价格平铺在一个数组中的过程,但它是通过NumPy的底层优化实现的,避免了显式创建巨大的中间列表。
ufunc.reduceat 是一个非常强大的NumPy函数,它允许在指定索引处对数组进行“分段”操作。np.add.reduceat(array, indices) 的功能是:
例如,如果 repeated_prices 是 [P1, P1, P1, P2, P2, P2] 且 indices 是 [0, 3]:
在我们的解决方案中,indices 数组 np.r_[0, np.cumsum(orders)][:-1] 精确地标记了每个客户订单在 repeated_prices 数组中的起始位置。np.add.reduceat 随后对每个客户所购买的商品价格进行求和,直接得到每个客户的总成本。
在进行浮点数计算时,精度问题是普遍存在的。NumPy在内部使用IEEE 754标准来表示浮点数,这在大多数科学和工程计算中是足够的。对于本例中的平均价格计算: mean_prices * quantity == original_prices * quantities
由于浮点数的特性,直接比较两个浮点数是否“相等”通常是不可靠的。更好的做法是比较它们之间的绝对差是否小于一个很小的容忍值(epsilon)。
# 示例:验证总成本的准确性
# 计算高效方法得到的总成本
calculated_total_costs = average_price_per_customer * orders
print("高效方法计算的总成本:", calculated_total_costs)
# 原始的总供应成本
original_total_supply_cost = np.sum(price * quantity)
print("原始总供应成本:", original_total_supply_cost)
# 高效方法计算的所有客户总成本之和
sum_calculated_total_costs = np.sum(calculated_total_costs)
print("所有客户总成本之和:", sum_calculated_total_costs)
# 比较(考虑浮点精度)
tolerance = 1e-9 # 设置一个小的容忍值
if np.abs(sum_calculated_total_costs - original_total_supply_cost) < tolerance:
print("总成本在浮点精度范围内一致。")
else:
print("总成本存在显著差异。")输出示例:
高效方法计算的总成本: [665.5 213. 106.5] 原始总供应成本: 985.0 所有客户总成本之和: 985.0 总成本在浮点精度范围内一致。
可以看到,在合理的浮点精度范围内,总成本是匹配的。对于极度严格的金融计算,可能需要考虑使用decimal模块或专门的定点数库,但对于大多数业务场景,NumPy的float64精度已足够。
通过利用NumPy的np.repeat和np.add.reduceat函数,我们能够以高度优化的方式解决多价库存分配和客户平均价格计算问题。这种方法具有以下显著优点:
注意事项:
这种高效的NumPy方法是处理类似库存分配和成本计算问题的推荐实践,它充分体现了NumPy在数据处理方面的强大能力。
以上就是NumPy高效处理分层库存分配与客户平均价格计算的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号