Python字典更新:生成含多厂商列表的零件最优报价字典
问题描述
我有一个包含各类零件及厂商报价的DataFrame,约10000个零件、10个厂商,数据集最多含100000行,数据结构如下:
| 零件(Part) | 厂商(Maker) | 价格(Price) |
|---|---|---|
| 1 | Alpha | 1.00 |
| 2 | Alpha | 1.30 |
| 3 | Alpha | 1.25 |
| 1 | Bravo | 1.10 |
| 2 | Bravo | 1.02 |
| 3 | Bravo | 1.15 |
| 4 | Bravo | 1.19 |
| 1 | Charlie | 0.99 |
| 2 | Charlie | 1.10 |
| 3 | Charlie | 1.12 |
| 4 | Charlie | 1.19 |
我希望基于最优价格生成两个字典:
- 零件-价格字典:每个零件对应最低报价
- 零件-厂商字典:每个零件对应报价最低的厂商,若多个厂商报价相同则存为列表
期望输出:
- 零件-价格字典:
{1:0.99, 2:1.1, 3:1.02, 4:1.19} - 零件-厂商字典:
{1:'Charlie', 2:'Charlie', 3:'Bravo', 4:['Bravo', 'Charlie']}
第一个字典实现无难度,但第二个字典处理多厂商同价时出错。最初代码:
winning_price_dict={} winning_mfg_dict={} for index, row in quote_df.iterrows(): if row['Part'] not in winning_price_dict: winning_price_dict[row['Part']] = row['Proposed Quote'] winning_mfg_dict[row['Part']] = list(row['Maker']) if winning_price_dict[row['Part']]>row['Proposed Quote']: winning_price_dict[row['Part']] = row['Proposed Quote'] winning_mfg_dict[row['Part']] = row['Maker'] if winning_price_dict[row['Part']]==row['Proposed Quote']: winning_price_dict[row['Part']] = row['Proposed Quote'] winning_mfg_dict[row['Part']] = winning_mfg_dict[row['Part']].append(row['Maker']) # 此处报错
运行提示'str'对象无append属性,修改后代码:
for index, row in quote_df.iterrows(): if row['Part'] not in winning_price_dict: winning_mfg_dict[row['Part']] = list(row['Mfg']) if winning_price_dict[row['Part']]>row['Proposed Quote']: winning_mfg_dict[row['Part']] = list(row[['Mfg']]) if winning_price_dict[row['Part']]==row['Proposed Quote']: winning_mfg_dict[row['Part']] = list(winning_mfg_dict[row['Part']]).append(row['Mfg'])
此时winning_mfg_dict全部为None,求修正方案。
解决方案
错误原因
- 最初代码中,遇到更低价格时把
winning_mfg_dict的值设为字符串,后续执行append时自然报错——字符串没有append方法。 - 修改后的代码里,
list.append()是原地修改列表,返回值为None,直接赋值会导致字典值变成None。
修正代码(循环版)
核心思路:始终让winning_mfg_dict的值保持为列表,最后按需将单元素列表转为字符串:
winning_price_dict = {} winning_mfg_dict = {} for index, row in quote_df.iterrows(): part = row['Part'] price = row['Price'] # 原代码里的'Proposed Quote'对应数据集的'Price' maker = row['Maker'] if part not in winning_price_dict: # 首次记录零件,初始化价格和厂商列表 winning_price_dict[part] = price winning_mfg_dict[part] = [maker] else: current_min = winning_price_dict[part] if price < current_min: # 找到更低价格,更新价格并重置厂商列表 winning_price_dict[part] = price winning_mfg_dict[part] = [maker] elif price == current_min: # 同价厂商追加到列表,加去重判断避免重复 if maker not in winning_mfg_dict[part]: winning_mfg_dict[part].append(maker) # 把单元素列表转为字符串,匹配期望输出格式 for part in winning_mfg_dict: if len(winning_mfg_dict[part]) == 1: winning_mfg_dict[part] = winning_mfg_dict[part][0]
优化方案(大数据量适配)
针对10万行的数据集,iterrows()效率较低,推荐用Pandas分组聚合实现,性能更优:
# 先按零件分组,获取每个零件的最低价格字典 min_prices = quote_df.groupby('Part')['Price'].min().to_dict() # 筛选出所有报价等于最低价格的行,按零件分组收集厂商 winning_makers = quote_df[quote_df.apply(lambda x: x['Price'] == min_prices[x['Part']], axis=1)]\ .groupby('Part')['Maker'].agg(list).to_dict() # 处理单元素列表转字符串 for part in winning_makers: if len(winning_makers[part]) == 1: winning_makers[part] = winning_makers[part][0]
内容的提问来源于stack exchange,提问作者Stephen Juza
相关产品推荐
相关产品推荐

