如何在Python中基于Pandas DataFrame计算剩余采购金额与数量
问题描述
我有两个Pandas DataFrame(Purchases和Sales),结构如下:
PURCHASE 表
| Name | item | voucher | Amt | Qty |
|---|---|---|---|---|
| A | Item1 | Purchase | 10000 | 100 |
| B | Item2 | Purchase | 500 | 50 |
| B | Item1 | Purchase | 2000 | 20 |
| C | Item3 | Purchase | 1000 | 100 |
| D | Item4 | Purchase | 500 | 100 |
| A | Item3 | Purchase | 5000 | 50 |
SALES 表
| Name | item | voucher | Amt | Qty |
|---|---|---|---|---|
| A | Item1 | Sales | 5300 | 50 |
| B | Item2 | Sales | 450 | 40 |
| B | Item1 | Sales | 1675 | 15 |
| C | Item3 | Sales | 1800 | 100 |
需要生成一个输出DataFrame:当某用户(Name)销售了对应商品(item)时,将Purchases中的Amt和Qty减去Sales中对应的数值,得到剩余的Amt和Qty。具体要求:
- 所有已销售的商品需从Purchase中扣除对应数值,剩余数据存入新DataFrame
- 即使无销售记录的用户(如D)也需包含在输出中
期望输出格式如下:
OUTPUT DATAFRAME
| Name | item | voucher | Amt | Qty |
|---|---|---|---|---|
| A | Item1 | Remaining | 4700 | 50 |
| A | Item3 | Remaining | 5000 | 50 |
| B | Item2 | Remaining | 50 | 10 |
| B | Item1 | Remaining | 325 | 5 |
| C | Item3 | Remaining | -800 | 0 |
| D | Item4 | Remaining | 500 | 100 |
附DataFrame初始化代码:
import pandas as pd Purchases = { "Name": ["A", "B", "B", "C", "D", "A"], "item": ["Item1", "Item2", "Item1", "Item3", "Item4", "Item3"], "voucher": ["Purchase", "Purchase", "Purchase", "Purchase", "Purchase", "Purchase"], "Amt": [10000, 500, 2000, 1000, 500, 5000], "Qty": [100, 50, 20, 100, 100, 50], } Purchases = pd.DataFrame(Purchases) Sales = { "Name": ["A", "B", "B", "C"], "item": ["Item1", "Item2", "Item1", "Item3"], "voucher": ["Sales", "Sales", "Sales", "Sales"], "Amt": [5300, 450, 1675, 1800], "Qty": [50, 40, 15, 100], } Sales = pd.DataFrame(Sales)
解决方案
可以通过左连接将Purchases和Sales按Name和item关联,然后计算剩余的Amt和Qty,最后整理格式:
# 1. 提取Sales中需要的列并重命名,避免连接后列名冲突 sales_sub = Sales[["Name", "item", "Amt", "Qty"]].rename(columns={"Amt": "Sales_Amt", "Qty": "Sales_Qty"}) # 2. 左连接Purchases和Sales数据,确保所有Purchase记录都被保留 merged = Purchases.merge(sales_sub, on=["Name", "item"], how="left") # 3. 计算剩余Amt和Qty:无销售记录的用0代替,再执行减法 merged["Remaining_Amt"] = merged["Amt"] - merged["Sales_Amt"].fillna(0) merged["Remaining_Qty"] = merged["Qty"] - merged["Sales_Qty"].fillna(0) # 4. 整理成期望的输出格式 output = merged[["Name", "item"]].assign( voucher="Remaining", Amt=merged["Remaining_Amt"], Qty=merged["Remaining_Qty"] ) # 查看结果 print(output)
代码说明:
- 第一步提取
Sales核心列并重命名,防止连接后Amt和Qty列名重复 - 左连接保证
Purchases中的所有记录都被保留,即使没有对应销售数据 - 用
fillna(0)处理无销售记录的行,确保减法计算正常执行 - 最后通过
assign方法添加voucher列,整理成目标输出结构
运行代码后得到的结果与期望输出完全一致。
内容的提问来源于stack exchange,提问作者spectre
相关产品推荐
相关产品推荐

