求Pandas低时间复杂度实现DataFrame跨行条件更新的最优方案
问题描述
我有一个包含350万条(行)网页爬取数据的Pandas DataFrame。其中R公司的数据干净规范,M公司的数据则不然。需要将所有M公司的文章中,同时存在于R公司的文章对应的brand、category、series字段替换为R公司的对应值,但当前运行代码耗时过长,求时间复杂度最低的Pandas解决方案。
原始代码
import pandas as pd d = { 'company': [ 'R', 'R', 'M', 'M', 'M', 'G' ], 'article': [ 'a', 'b', 'a', 'a', 'c', 'a' ], 'brand': [ 'brand1', 'brand1', 'brand1x', 'brand1x', 'brand1x', 'brand' ], 'category':[ 'cat', 'cat', 'catx', 'catx', 'catx', 'cat' ], 'series':[ 'series1', 'series1', 'series1x', 'series1x', 'series1x', 'series' ], 'price':[ 2, 2.2, 2.25, 2.27, 2.27, '', ], 'date':[ '2023-11-05', '2023-11-11', '2023-11-05', '2023-11-11', '2023-11-11', '' ], } df = pd.DataFrame(data=d) # 创建仅包含R公司数据且去重的DataFrame selected_columns = df[df['company'] == 'R'][['article', 'brand', 'category', 'series']].drop_duplicates() # 定义更新字段的函数 def update_values(row): article = row['article'] if article in selected_columns['article'].values: selected_row = selected_columns[selected_columns['article'] == article] row['brand'] = selected_row['brand'].values[0] row['category'] = selected_row['category'].values[0] row['series'] = selected_row['series'].values[0] return row # 对M公司数据应用更新函数 new = df[df['company'] == 'M'].apply(update_values, axis=1) # 筛选出R公司数据 df = df[df['company'] == 'R'] # 合并结果 frames = [new,df] df = pd.concat(frames)
原始代码的问题
原始代码使用apply逐行处理M公司数据,本质是Python层面的循环,在350万行的数据集上会非常耗时——虽然时间复杂度是O(n),但常数项极大,完全没利用Pandas的向量化运算优势。
优化方案(时间复杂度最优)
核心思路是利用Pandas的向量化操作和索引映射,彻底避免逐行循环:
- 提取R公司的唯一文章-规范字段映射表,以
article为索引,确保每个article只对应一组规范值 - 用掩码筛选出需要更新的M公司行(即article存在于R公司映射表中的行)
- 批量替换这些行的目标字段
优化后的代码
import pandas as pd d = { 'company': ['R', 'R', 'M', 'M', 'M', 'G'], 'article': ['a', 'b', 'a', 'a', 'c', 'a'], 'brand': ['brand1', 'brand1', 'brand1x', 'brand1x', 'brand1x', 'brand'], 'category': ['cat', 'cat', 'catx', 'catx', 'catx', 'cat'], 'series': ['series1', 'series1', 'series1x', 'series1x', 'series1x', 'series'], 'price': [2, 2.2, 2.25, 2.27, 2.27, ''], 'date': ['2023-11-05', '2023-11-11', '2023-11-05', '2023-11-11', '2023-11-11', ''] } df = pd.DataFrame(data=d) # 1. 创建R公司的文章-规范字段映射表,以article为索引并去重 r_mapping = df[df['company'] == 'R'][['article', 'brand', 'category', 'series']].drop_duplicates().set_index('article') # 2. 复制原DataFrame避免修改原始数据 df_updated = df.copy() # 3. 生成需要更新的行的掩码:M公司且article在R的映射表中 update_mask = (df_updated['company'] == 'M') & (df_updated['article'].isin(r_mapping.index)) # 4. 批量更新指定字段(向量化操作,效率极高) df_updated.loc[update_mask, 'brand'] = df_updated.loc[update_mask, 'article'].map(r_mapping['brand']) df_updated.loc[update_mask, 'category'] = df_updated.loc[update_mask, 'article'].map(r_mapping['category']) df_updated.loc[update_mask, 'series'] = df_updated.loc[update_mask, 'article'].map(r_mapping['series']) # 查看结果 print(df_updated)
预期输出
d = { 'company': ['R', 'R', 'M', 'M', 'M', 'G'], 'article': ['a', 'b', 'a', 'a', 'c', 'a'], 'brand': ['brand1', 'brand1', 'brand1', 'brand1', 'brand1x', 'brand'], 'category': ['cat', 'cat', 'cat', 'cat', 'catx', 'cat'], 'series': ['series1', 'series1', 'series1', 'series1', 'series1x', 'series'], 'price': [2, 2.2, 2.25, 2.27, 2.27, ''], 'date': ['2023-11-05', '2023-11-11', '2023-11-05', '2023-11-11', '2023-11-11', ''] } print(pd.DataFrame(d))
内容的提问来源于stack exchange,提问作者hm2330
相关产品推荐
相关产品推荐

