Pandas数据处理:去引号、匹配查询结果并实现行内去重
问题需求
我有一个大型Pandas DataFrame,其中names列的值被双引号包裹,部分行包含逗号分隔的多值。需要完成以下操作:
- 移除
names列的引号 - 将每个名称的查询结果按原行对应放入新列
query_result_fav_color,多值用逗号分隔 - 每行的查询结果需去重
无需协助实现查询逻辑,仅解决引号去除、结果正确映射及行内去重问题
简化原始数据集
ID1 ID2 names 01 01 "John" 01 02 "Kate, Ashten" 01 03 01 04 "Emily, Cathy, Joy"
期望数据集
ID1 ID2 names query_result_fav_color 01 01 "John" "pink" 01 02 "Kate, Ashten" "blue" 01 03 01 04 "Emily, Cathy, Joy" "red, green, blue"
已尝试的方法
values=original_df['names'] # series values=values.to_frame() values = values.apply(lambda x: x.str.replace('"','')) # 执行查询(得到'results'列表) results= ["pink", "blue", "blue", "NA", "red", "green", "blue"] # 将查询结果放入对应行的新列(需协助) # 得到的中间结果: # ID1 ID2 names query_result_fav_color # 01 01 "John" "pink" # 01 02 "Kate, Ashten" "blue", "blue" # 01 03 "NA" # 01 04 "Emily, Cathy, Joy" "red", "green", "blue" # 移除行内重复值,并确保结果仅外层带引号(需协助)
补充说明
尝试过以下代码,在样本数据中有效,但实际大型数据集出现结果重复、映射错误的问题:
df = df.assign(names = df["names"].str.split(",")).explode(column="names").assign(query_result_fav_color=results).groupby(["ID1", "ID2"])["names", "query_result_fav_color"].agg(list) df.assign( names=df["names"].apply(lambda x: ", ".join(x) if x else ""), query_result_fav_color=df["query_result_fav_color"].apply(lambda x: ", ".join(x)) ).reset_index()
实际数据集错误结果(重点关注3-5行):
ID1 ID2 names query_result_fav_color 0 01 01 John pink 1 01 02 Kate, Ashton blue, blue 2 01 03 NA 3 01 04 Emily, Cathy, Joy red, red, red 4 01 05 Jason green 5 01 06 blue
解决方案
步骤1:预处理names列,去除引号并拆分
先清理names列的引号,再将每行的名称拆分为列表,同时记录每行对应的名称数量,确保后续结果映射准确:
import pandas as pd # 复制原始数据避免修改原表 df = original_df.copy() # 去除引号,处理空值 df['clean_names'] = df['names'].str.replace('"', '', regex=False).fillna('') # 拆分名称为列表,空值转为空列表 df['name_list'] = df['clean_names'].apply(lambda x: [name.strip() for name in x.split(',')] if x else []) # 计算每行的名称数量,用于后续结果切片 df['name_count'] = df['name_list'].apply(len)
步骤2:正确映射查询结果到每个名称
根据每行的名称数量,将results列表按顺序分配到对应的行:
# 初始化结果列表指针 ptr = 0 row_results = [] for cnt in df['name_count']: if cnt == 0: # 空行取对应结果 row_results.append([results[ptr]]) ptr += 1 else: # 取对应数量的结果 row_results.append(results[ptr:ptr+cnt]) ptr += cnt # 将结果存入DataFrame df['raw_results'] = row_results
步骤3:行内去重并格式化结果
对每行的查询结果去重,再格式化为逗号分隔的字符串,同时保留外层引号:
# 行内去重,保持原始顺序 df['unique_results'] = df['raw_results'].apply(lambda x: list(dict.fromkeys(x))) # 格式化为带外层引号的字符串,空值处理为"" df['query_result_fav_color'] = df['unique_results'].apply( lambda x: f'"{", ".join(x)}"' if x else "" ) # 还原原始names列(如果需要保留原格式),或者替换为清理后的names # 这里保留原始names列,若需要替换为无引号的列,可改为df['names'] = df['clean_names']
步骤4:整理最终数据集
删除中间辅助列,得到最终结果:
final_df = df.drop(['clean_names', 'name_list', 'name_count', 'raw_results', 'unique_results'], axis=1) print(final_df)
内容的提问来源于stack exchange,提问作者youtube
相关产品推荐
相关产品推荐

