如何用Python提取DataFrame同行单元格多值并匹配生成新DataFrame
Pandas DataFrame多值匹配拆分解决方案
源数据
每月会收到固定格式的DataFrame,示例如下:
import pandas as pd data = { 'C1': ['Alpha, Charlie, Bravo','Beta, Gamma','Foxtrot, Delta'], 'C2': [ 'Alpha, San Francisco, US ; Charlie, New York, US ; Bravo, London, UK', 'Beta, Singapore, Singapore ; Gamma, Tokyo, Japan', '[Foxtrot; Delta], Seoul, South Korea' ] } df = pd.DataFrame(data)
对应的表格:
| C1 | C2 |
|---|---|
| Alpha, Charlie, Bravo | Alpha, San Francisco, US ; Charlie, New York, US ; Bravo, London, UK |
| Beta, Gamma | Beta, Singapore, Singapore ; Gamma, Tokyo, Japan |
| Foxtrot, Delta | [Foxtrot; Delta], Seoul, South Korea |
预期结果
需要生成新的DataFrame,将C1中的每个值与C2中对应的信息匹配,特殊情况(如第三行)下C1的多个值对应同一个C2内容:
data2 = { 'N1': ['Alpha', 'Charlie', 'Bravo','Beta', 'Gamma','Foxtrot', 'Delta'], 'N2': [ 'Alpha, San Francisco, US', 'Charlie, New York, US', 'Bravo, London, UK', 'Beta, Singapore, Singapore', 'Gamma, Tokyo, Japan', '[Foxtrot; Delta], Seoul, South Korea', '[Foxtrot; Delta], Seoul, South Korea' ] } new_df = pd.DataFrame(data2)
对应的表格:
| N1 | N2 |
|---|---|
| Alpha | Alpha, San Francisco, US |
| Charlie | Charlie, New York, US |
| Bravo | Bravo, London, UK |
| Beta | Beta, Singapore, Singapore |
| Gamma | Gamma, Tokyo, Japan |
| Foxtrot | [Foxtrot; Delta], Seoul, South Korea |
| Delta | [Foxtrot; Delta], Seoul, South Korea |
失败尝试
之前用嵌套循环实现,得到了错误的笛卡尔积结果,脚本如下:
new_list = [] for idx, vals in enumerate(df['C1']): vals = vals.split('; ') # 拆分符错误,原C1是逗号分隔 locs = (df['C2'].values[idx]).split(' ; ') for val in vals: for loc in locs: new_list.append((val.strip(), loc.strip())) result_df = pd.DataFrame(data=new_list, columns=['N1', 'N2'])
错误结果是每个C1元素都和所有C2拆分元素配对,比如Alpha对应了三个C2值,不符合需求。
问题分析
- 原脚本拆分C1时用错了分隔符:C1的元素是逗号加空格分隔,不是分号
- 嵌套循环导致了笛卡尔积,而正确逻辑是:
- 当C2拆分后的元素数量和C1拆分后的数量一致时,一对一配对
- 当C2无法拆分成对应数量的元素时(如第三行),将C2的整个内容对应每个C1元素
解决方案
逐行处理DataFrame,根据每行的情况匹配对应值:
import pandas as pd # 初始化结果列表 result = [] for _, row in df.iterrows(): # 拆分C1:按逗号加空格分隔,去除每个元素的前后空格 c1_items = [item.strip() for item in row['C1'].split(', ')] # 尝试拆分C2:按" ; "分隔 c2_split = [item.strip() for item in row['C2'].split(' ; ')] # 判断拆分后的C2元素数量是否和C1一致 if len(c2_split) == len(c1_items): # 一对一配对 for c1, c2 in zip(c1_items, c2_split): result.append({'N1': c1, 'N2': c2}) else: # C2为整体,每个C1元素对应同一个C2值 c2_full = row['C2'].strip() for c1 in c1_items: result.append({'N1': c1, 'N2': c2_full}) # 生成新DataFrame new_df = pd.DataFrame(result) print(new_df)
运行后得到的结果完全符合预期,同时兼容两种格式的行数据。
内容的提问来源于stack exchange,提问作者ChillCode
相关产品推荐
相关产品推荐

