使用Pandas基于其他行计算成本时遇重复引用首行数据问题
嘿,我明白你遇到的问题了——这通常是因为你在查找原材料成本的时候,没有针对每一行的Material去匹配对应的价格,而是不小心固定取了首行的结果对吧?别担心,咱们用Pandas很容易解决这个问题,核心思路是先做一个「原材料价格查找表」,让每一行都能精准匹配到对应原材料的成本。
问题根源分析
你之前的代码之所以总是引用首行数据,大概率是因为你在获取原材料价格时,没有做行级别的匹配——比如用了iloc[0]固定取第一个结果,或者直接用整个Series做匹配,导致所有行都复用了首行的原材料价格。
解决步骤
1. 先构建原材料价格的映射字典
首先把DataFrame里所有原材料(也就是Price不为空的Item)的价格提取出来,做成一个字典,这样就能快速通过原材料名称查到对应的成本:
import pandas as pd # 假设你的DataFrame名为df # 把Item作为键,Price作为值,只保留Price非空的条目(也就是原材料) price_lookup = df.set_index('Item')['Price'].dropna().to_dict()
2. 逐行计算原材料成本
根据你的DataFrame结构,分两种情况处理:
情况一:每行对应产品的单个原材料需求
如果你的DataFrame里,每一行是某产品对一个原材料的需求,直接用apply逐行计算:
# 对每一行,用MaterialSum × 对应原材料的价格 df['RawMaterialCost'] = df.apply( lambda row: row['MaterialSum'] * price_lookup.get(row['Material'], 0) if pd.notna(row['Material']) else None, # 跳过没有原材料的行(比如原材料本身) axis=1 )
这里用price_lookup.get()是为了防止出现不存在的原材料,默认返回0,你可以根据实际业务调整这个默认值。
情况二:一个产品对应多个原材料(多行数据)
如果同一个产品的多个原材料需求分散在不同行,我们可以先计算每个原材料的成本,再按产品分组求和得到总成本:
# 先计算单个原材料的成本 df['SingleMaterialCost'] = df.apply( lambda row: row['MaterialSum'] * price_lookup.get(row['Material'], 0) if pd.notna(row['Material']) else None, axis=1 ) # 按Item分组,求和得到每个产品的总成本 df['TotalProductCost'] = df.groupby('Item')['SingleMaterialCost'].transform('sum')
测试示例
我给你写了个测试用例,你可以直接运行验证效果:
# 构造测试数据 data = { 'Item': ['ProductX', 'MaterialA', 'ProductX', 'MaterialB', 'ProductY'], 'Price': [None, 5.0, None, 3.0, None], 'Material': ['MaterialA', None, 'MaterialB', None, 'MaterialA'], 'MaterialSum': [2, None, 4, None, 3] } df = pd.DataFrame(data) # 创建价格映射 price_lookup = df.set_index('Item')['Price'].dropna().to_dict() # 计算单个原材料成本 df['SingleMaterialCost'] = df.apply( lambda row: row['MaterialSum'] * price_lookup.get(row['Material'], 0) if pd.notna(row['Material']) else None, axis=1 ) # 计算产品总成本 df['TotalCost'] = df.groupby('Item')['SingleMaterialCost'].transform('sum') print(df)
运行后会得到这样的结果:
Item Price Material MaterialSum SingleMaterialCost TotalCost 0 ProductX NaN MaterialA 2.0 10.0 22.0 1 MaterialA 5.0 NaN NaN NaN NaN 2 ProductX NaN MaterialB 4.0 12.0 22.0 3 MaterialB 3.0 NaN NaN NaN NaN 4 ProductY NaN MaterialA 3.0 15.0 15.0
内容的提问来源于stack exchange,提问作者Richard Lucky
相关产品推荐
相关产品推荐

