NumPy高效处理分层库存分配与客户平均价格计算

NumPy高效处理分层库存分配与客户平均价格计算

本文介绍如何使用NumPy高效解决多价库存按先进先出原则分配给客户订单的问题,并计算每位客户的平均购买价格。通过利用np.repeat和np.add.reduceat等向量化操作,避免了创建大型中间数组,显著提升了处理大规模数据的性能和内存效率。

1. 问题描述

库存管理和订单处理场景中,我们经常会遇到需要将不同价格的商品分配给多个客户订单的情况。一个典型的场景是,商品以不同的批次或在不同时间点采购,导致其成本(或售价)存在差异。当客户下订单时,通常会遵循“先进先出”或“成本最低优先”的原则进行分配。我们的目标是,在满足客户订单需求的同时,计算出每位客户为其所购商品支付的平均价格。

假设我们有以下数据:

orders: 一个NumPy数组,表示每位客户的订单数量。例如 [21, 6, 3] 表示第一个客户需要21单位,第二个6单位,第三个3单位。quantity: 一个NumPy数组,表示在特定价格下可用的商品数量。例如 [16, 14] 表示有16单位商品以某个价格出售,另有14单位商品以另一个价格出售。price: 一个NumPy数组,与 quantity 对应,表示每批商品的单价。例如 [30.5, 35.5] 表示16单位商品单价为30.5,14单位商品单价为35.5。

关键约束和条件:

所有客户订单的总量 (np.sum(orders)) 始终等于所有可用商品的总量 (np.sum(quantity))。orders 数组通常按客户需求量降序排列(尽管这不是解决问题的严格要求,但反映了常见场景)。quantity 和 price 数组是关联的,且 price 数组按升序排列,这意味着我们总是优先分配价格最低的商品。

我们的任务是计算出每位客户的平均购买价格。

2. 低效的解决方案及其局限性

一种直观但低效的方法是创建一个巨大的数组,将所有商品的单价“展开”到这个数组中,然后根据客户订单的起始和结束索引来计算平均值。

import numpy as nporders = 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 = 0total_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 = idxprint("扁平化商品价格数组:", supply_prices_flat)# 步骤2: 根据客户订单计算平均价格fin_avg_prices = []current_pos = 0for order_size in orders:    idx = current_pos + order_size    fin_avg_prices.append(np.mean(supply_prices_flat[current_pos:idx]))    current_pos = idxprint("每位客户的平均价格 (低效方法):", 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 数组会变得极其庞大,导致严重的内存消耗和性能问题。这种方法在处理大规模数据集时是不可接受的。

3. 高效的NumPy解决方案

NumPy提供了强大的向量化操作,可以避免显式循环和创建大型中间数组。我们可以利用 np.repeat 和 np.add.reduceat 来高效地解决这个问题。

import numpy as nporders = 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 / ordersprint("每位客户的平均价格 (高效NumPy方法):", average_price_per_customer)

输出:

每位客户的平均价格 (高效NumPy方法): [31.69047619 35.5        35.5       ]

4. 核心NumPy函数详解

4.1 numpy.repeat(a, repeats)

此函数用于重复数组 a 中的元素。repeats 可以是一个整数(所有元素重复相同次数),也可以是一个与 a 形状相同的数组(每个元素重复不同次数)。在本例中,np.repeat(price, quantity) 的作用是根据 quantity 数组中每个对应的数量,将 price 数组中的价格值进行重复。这有效地模拟了将所有单独的商品单位及其价格平铺在一个数组中的过程,但它是通过NumPy的底层优化实现的,避免了显式创建巨大的中间列表。

4.2 numpy.add.reduceat(a, indices)

ufunc.reduceat 是一个非常强大的NumPy函数,它允许在指定索引处对数组进行“分段”操作。np.add.reduceat(array, indices) 的功能是:

在 indices 数组中指定的每个位置开始一个新的“段”。对每个段内的元素执行 add 操作(即求和)。返回一个数组,其中包含每个段的求和结果。

例如,如果 repeated_prices 是 [P1, P1, P1, P2, P2, P2] 且 indices 是 [0, 3]:

第一个段从索引0开始,到索引3之前结束:[P1, P1, P1],求和为 3*P1。第二个段从索引3开始,到数组末尾结束:[P2, P2, P2],求和为 3*P2。结果将是 [3*P1, 3*P2]。

在我们的解决方案中,indices 数组 np.r_[0, np.cumsum(orders)][:-1] 精确地标记了每个客户订单在 repeated_prices 数组中的起始位置。np.add.reduceat 随后对每个客户所购买的商品价格进行求和,直接得到每个客户的总成本。

5. 浮点数精度问题考量

在进行浮点数计算时,精度问题是普遍存在的。NumPy在内部使用IEEE 754标准来表示浮点数,这在大多数科学和工程计算中是足够的。对于本例中的平均价格计算:mean_prices * quantity == original_prices * quantities

由于浮点数的特性,直接比较两个浮点数是否“相等”通常是不可靠的。更好的做法是比较它们之间的绝对差是否小于一个很小的容忍值(epsilon)。

# 示例:验证总成本的准确性# 计算高效方法得到的总成本calculated_total_costs = average_price_per_customer * ordersprint("高效方法计算的总成本:", 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精度已足够。

6. 总结与注意事项

通过利用NumPy的np.repeat和np.add.reduceat函数,我们能够以高度优化的方式解决多价库存分配和客户平均价格计算问题。这种方法具有以下显著优点:

内存效率高: 避免了创建可能非常庞大的中间数组,显著降低了内存消耗。计算速度快: 利用NumPy底层C语言实现,通过向量化操作极大地提升了计算速度,尤其适用于大规模数据集。代码简洁: 相比于基于循环的实现,代码更加紧凑和易读。

注意事项:

数据预处理: 确保 price 数组与 quantity 数组严格对应,并且 price 数组已按升序排列,以保证“最低价优先”的分配原则。总量匹配: 务必确认 np.sum(orders) 和 np.sum(quantity) 相等,否则分配逻辑会出错。浮点数精度: 虽然NumPy通常表现良好,但在对结果进行精确比较或在金融等对精度要求极高的领域使用时,应注意浮点数的固有特性,并考虑使用适当的容忍值进行比较。

这种高效的NumPy方法是处理类似库存分配和成本计算问题的推荐实践,它充分体现了NumPy在数据处理方面的强大能力。

以上就是NumPy高效处理分层库存分配与客户平均价格计算的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1369419.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月14日 09:39:06
下一篇 2025年12月14日 09:39:21

相关推荐

  • 使用 NumPy 高效计算不同价格商品的客户平均购买价格

    引言 本文介绍如何使用 NumPy 解决一个常见的分配问题:根据商品的不同价格和库存数量,以及客户的订单数量,计算每个客户的平均购买价格。重点在于利用 NumPy 的 repeat 和 add.reduceat 函数,避免创建大型中间数组,从而提高计算效率。同时,也讨论了处理浮点数精度问题的一种方法…

    好文分享 2025年12月14日
    000
  • Python Behave自动化测试集成Allure报告生成指南

    本教程详细介绍了如何在Python的Behave自动化测试框架中集成Allure报告,实现测试结果的可视化。通过配置behave.ini文件或使用命令行参数,利用allure-behave插件的格式化器,无需复杂的代码即可自动生成高质量的Allure测试报告,有效解决传统手动生成或文档缺失的问题,提…

    2025年12月14日
    000
  • Dropbox Python API:团队与个人文件访问策略详解

    本教程详细阐述了如何使用Dropbox Python API正确访问Dropbox Business团队环境下的个人和团队文件。针对不同需求,文章提供了两种核心策略:通过精简API权限直接访问特定用户文件,以及利用团队范围和 as_user 方法以管理员身份管理团队成员文件,并辅以代码示例和关键注意…

    2025年12月14日
    000
  • 优化Dropbox Python API访问:正确管理个人与团队文件权限

    本教程详细阐述如何使用Dropbox Python API有效访问个人和团队文件。核心在于根据所需访问级别(个人用户或团队管理)正确配置OAuth作用域。通过选择合适的权限,开发者可以避免常见的认证错误,实现对特定用户文件或整个团队资源的精确控制。 在使用dropbox python api与dro…

    2025年12月14日
    000
  • # 使用 PyMuPDF 按页码范围分割 PDF 并保留目录

    本文档介绍如何使用 PyMuPDF 库,根据指定的页码范围分割 PDF 文件,并在分割后的 PDF 文件中保留对应的目录 (Table of Contents)。我们将详细讲解如何提取、修改和应用目录,以确保分割后的文档具有完整的导航功能。同时,也会针对目录结构的特殊规则进行说明,并提供相应的解决方…

    2025年12月14日
    000
  • 高效拆分PDF并精确保留目录结构(PyMuPDF教程)

    本教程详细介绍了如何使用PyMuPDF库(fitz)高效地将大型PDF文档按指定页面范围拆分为多个独立文件,并确保每个拆分后的PDF都能正确地包含其对应的、且符合PyMuPDF规范的目录(Table of Contents, TOC)。文章深入探讨了PyMuPDF的TOC结构规则,提供了修正不规范T…

    2025年12月14日
    000
  • 使用 Pydantic 精确描述 Python 复杂字典结构

    在Python中,对复杂嵌套的字典结构进行精确的类型描述和验证是一个常见挑战。传统的Dict[str, Any]无法提供细粒度的类型检查。本教程将介绍如何利用Pydantic库,通过定义BaseModel类来精确地映射和验证复杂字典的结构,实现类似Go语言中结构体的强类型特性,从而提升代码的健壮性和…

    2025年12月14日
    000
  • VSCode Python 配置项变迁与查找策略

    本教程旨在解决VSCode中Python及相关扩展配置项难以查找的问题,特别是面对配置变更时。文章将详细介绍通过查阅扩展文档、Marketplace配置部分以及利用VSCode内置设置UI的“在settings.json中打开”功能,快速准确地定位所需配置键值的方法,帮助开发者有效管理和更新其开发环…

    2025年12月14日
    000
  • VS Code Python 配置迷失?掌握查找最新设置键的两种方法

    本文针对VS Code Python开发环境中,用户在查找和配置最新设置键时遇到的常见困惑,特别是由于扩展API变更导致的配置项迁移问题,提供了两种高效的解决方案。我们将详细介绍如何利用VS Code的设置UI直接获取配置键名,以及如何通过查阅扩展的官方文档和Marketplace页面来定位所需设置…

    2025年12月14日
    000
  • 如何使用Dropbox Python API访问团队和个人文件:认证与授权策略

    本教程详细阐述了如何通过Dropbox Python API访问Dropbox Business团队和个人文件。它区分了个人账户授权与团队账户授权的机制,解释了在使用团队范围令牌时为何需要指定用户,并提供了解决“需要选择用户”错误的具体方法。文章强调根据实际需求选择合适的API权限范围,以实现高效且…

    2025年12月14日
    000
  • 深入理解Dropbox Python API:团队与个人文件访问策略

    本教程深入探讨Dropbox Python API中访问团队和个人文件的策略。核心在于理解个人账户令牌与团队令牌的区别及其适用场景。我们将指导开发者如何根据需求选择合适的OAuth授权范围,以避免常见的“团队令牌用于单用户操作”错误,并提供通过as_user方法切换用户上下文以及获取团队成员ID的实…

    2025年12月14日
    000
  • VSCode Python 配置管理:解决“未知配置设置”与查找最新配置项

    本文旨在解决VSCode中Python扩展配置项显示“未知配置设置”的问题,并提供两种核心方法来查找和管理当前有效的配置。通过查阅扩展的配置文档或利用VSCode内置的设置UI,用户可以高效地识别和应用最新的配置项,从而避免因配置变更导致的开发环境问题。 理解VSCode配置变更与“未知配置设置” …

    2025年12月14日
    000
  • Dropbox Python API:深入理解团队与用户文件访问权限管理

    本文详细阐述了如何使用Dropbox Python API访问团队和个人文件。核心在于正确配置OAuth作用域:若仅需访问特定用户(即使是团队成员)的文件,应避免包含团队管理相关作用域以获取用户级令牌;若需以团队管理员身份管理其他成员文件,则需包含团队作用域并结合as_user方法。理解这两种模式是…

    2025年12月14日
    000
  • JavaScript前端录制视频并上传至Django后端存储的教程

    本教程详细介绍了如何将通过JavaScript在浏览器中录制的视频文件,通过Fetch API异步上传至Django后端。内容涵盖了客户端JavaScript如何处理视频Blob、构建FormData并携带CSRF令牌发送请求,以及Django后端如何接收文件、保存至数据库并返回JSON响应。旨在提…

    2025年12月14日
    000
  • 使用 JavaScript 和 Django 将录制的视频文件保存到文件系统

    本文档旨在指导开发者如何使用 JavaScript 录制视频,并通过 Django 后端将其保存到服务器的文件系统中。我们将利用 Fetch API 从前端上传视频文件,并在 Django 视图中处理文件存储,同时解决常见的浏览器兼容性问题。 前端:使用 JavaScript 录制和上传视频 首先,…

    2025年12月14日
    000
  • Django 文件上传与处理:获取文件路径的正确实践

    本文详细阐述了在 Django 应用中正确处理文件上传、保存并获取其存储路径的方法。通过分析常见错误,提供优化的代码示例,指导开发者如何安全、高效地接收用户上传的文件,利用 default_storage 进行存储,并将生成的存储路径传递给后续的文件处理函数,确保数据流的准确性和程序的健壮性。 Dj…

    2025年12月14日
    000
  • Django 文件上传与路径管理:确保数据处理的正确路径

    本教程详细阐述了在Django应用中处理文件上传的最佳实践,特别是如何从HTTP请求中正确获取上传文件、将其安全地保存到存储系统,并获取其存储路径。我们将重点讲解request.FILES的使用、default_storage.save()的返回值,以及如何将正确的文件路径传递给后续的文件处理函数,…

    2025年12月14日
    000
  • Python字典美化输出:实现键值对的整齐对齐

    本教程旨在解决Python字典在打印时键值对不对齐的问题。通过利用F-string的格式化能力,结合计算最长键的长度,我们可以实现字典输出的整齐对齐,使数据展示更加清晰和专业。文章将详细介绍如何计算最大键长并运用左对齐格式化输出,确保冒号和值在垂直方向上保持一致。 在python开发中,我们经常需要…

    2025年12月14日
    000
  • 使用 Python 格式化字符串对齐字典输出

    本文介绍了如何使用 Python 格式化字符串的方法,解决字典键值对输出时,由于键的长度不一致导致对齐混乱的问题。通过计算最长键的长度,并利用 f-string 的格式化功能,可以轻松实现美观、整齐的字典输出效果,提高代码的可读性。 在 Python 中,字典是一种非常常用的数据结构。当我们需要将字…

    2025年12月14日
    000
  • Python字典数据美观输出:实现键值对的对齐显示

    本教程旨在解决Python字典在打印输出时,由于键(key)长度不一导致显示不整齐的问题。通过利用Python的f-string格式化功能,结合动态计算最长键的长度,我们可以实现键值对的冒号对齐,从而生成结构清晰、易于阅读的表格化输出,提升数据展示的专业性和美观度。 在数据处理和展示中,我们经常需要…

    2025年12月14日
    000

发表回复

登录后才能评论
关注微信