
本文介绍如何利用 pandas 将字典中定义的转换因子与 dataframe 中的数值列进行动态乘法运算,并为每行计算对应可转换项中的最小值,最终作为新列添加到原表中。
本文介绍如何利用 pandas 将字典中定义的转换因子与 dataframe 中的数值列进行动态乘法运算,并为每行计算对应可转换项中的最小值,最终作为新列添加到原表中。
在实际数据分析中,常需根据外部映射关系(如品类转换系数、单位换算因子等)对某列数值进行批量变换,并从中提取关键聚合指标(如最小值)。本文以一个典型场景为例:给定一个转换因子字典 data 和主数据表 df,目标是为 df 中每个 Item 计算其在字典中所有“可转换来源项”经乘法变换后的 Col1 最小值,并新增为 Minc_Col1 列。
✅ 核心逻辑解析
- 字典结构:data 是一个以目标项(如 'Item1')为列、可转换源项(如 'Item5')为索引的 DataFrame,值为乘数。
- 匹配机制:需将 df['Col0'](即 Item 名)与 data.index 对齐,获取对应 Col1 值作为被乘数。
- 广播计算:使用 DataFrame.mul(..., axis=0) 沿行方向将 data 的每一行乘以对应的 Col1 值。
- 按列取最小:min() 默认按列(即对每个目标项列)计算最小值,结果自动对齐到 data.columns(即 'Item1', 'Item2', 'Item4')。
? 实现代码(推荐写法)
import pandas as pd
# 转换因子字典 → DataFrame
data = pd.DataFrame({
'Item1': {'Item5': 10, 'Item6': 100, 'Item4': 1},
'Item2': {'Item5': 10, 'Item6': 100, 'Item4': 1},
'Item4': {'Item5': 10, 'Item6': 100, 'Item9': 1}
})
# 主数据表
df = pd.DataFrame({
'Col0': ['Item1', 'Item2', 'Item3', 'Item4', 'Item5', 'Item6'],
'Col1': [180, 250, 150, 205, 22, 2],
'Col2': [190, 150, 150, 200, 18, 2.5]
})
# 步骤 1:以 Col0 为索引,便于后续映射
result = df.set_index('Col0')
# 步骤 2:构建映射序列 —— data.index 中每个源项对应 result['Col1'] 的值
mapping_series = data.index.map(result['Col1']) # 如 Item5→22, Item6→2, Item4→205, Item9→NaN
# 步骤 3:广播乘法 + 按列取最小
min_values = data.mul(mapping_series, axis=0).min()
# 步骤 4:赋值新列并还原结构
result = (result
.assign(Minc_Col1=min_values)
.reset_index()
.rename(columns={'Col0': 'Item', 'Col1': 'Price1', 'Col2': 'Price2'}))
print(result)
输出结果:
Item Price1 Price2 Minc_Col1 0 Item1 180 190.0 200.0 1 Item2 250 150.0 200.0 2 Item3 150 150.0 NaN 3 Item4 205 200.0 200.0 4 Item5 22 18.0 NaN 5 Item6 2 2.5 NaN
⚠️ 注意事项与常见陷阱
- 索引对齐是关键:data.index.map(result['Col1']) 依赖 data.index(源项名)与 result.index(即 df['Col0'])的语义一致。若存在缺失项(如 Item3, Item9 不在 df['Col0'] 中),映射结果为 NaN,导致对应行乘积全为 NaN,min() 返回 NaN —— 这正是预期行为。
- 空值传播:只要某列中任一乘积为 NaN,且该列无有效数值,则 min() 返回 NaN。无需额外 skipna=False 设置(默认 skipna=True)。
- 列名一致性:data.columns 必须覆盖目标 Item(如 'Item1', 'Item2'),否则 assign 时会因索引不匹配而报错或填充 NaN。
- 性能提示:对大规模数据,避免循环;本方案全程向量化,效率高。
? 进阶:同时获取最小值来源项
若还需知道哪个源项(如 'Item6')贡献了最小值,可扩展为:
# 获取每列最小值对应的源项(首个)
min_idx = data.mul(mapping_series, axis=0).idxmin()
min_val = data.mul(mapping_series, axis=0).min()
# 合并到结果
aux = pd.DataFrame({'Source_Item': min_idx, 'Minc_Col1': min_val})
result = result.merge(aux, left_on='Item', right_index=True, how='left')
这样即可在结果中同时呈现最小值及其来源,增强分析可解释性。
掌握此模式后,你可轻松适配类似需求:如加权平均、阈值校验、多源比价等,核心始终是「映射 → 广播 → 聚合」三步向量化范式。











