如何用更高效方法替代Pandas中iloc+append嵌套循环汇总表格?
资助申请学科汇总代码优化
问题场景
现有一张记录资助申请编号与对应学科的表格,单元格值为1代表该申请归属此学科。初始数据处理代码如下:
import pandas as pd import numpy as np data={'Application number':[0,1,2,3,4,5,6,7,8,9], 'Physics':[0,0,1,0,0,0,0,1,1,0], 'Chemistry':[1,0,0,0,0,0,0,0,0,1], 'Biology':[0,1,0,1,0,0,1,0,0,0], 'Mathematics':[0,0,0,0,1,1,0,0,0,0]} df=pd.DataFrame(data) # 统计每个申请的学科数量 df['All_Discipline_count']=df.loc[:,'Physics' : 'Mathematics'].sum(axis=1)
需要为每个申请生成对应的学科列表,并汇总学科数量。当前采用嵌套循环实现的代码存在两个问题:一是触发append方法弃用的警告,二是数据量较大时运行速度缓慢:
dfA = pd.DataFrame(columns = ['Application number', 'Discipline_list', 'All_Discipline_count']) i=0 j=1 Aanvraag_nummer=0 k=df.columns.get_loc("All_Discipline_count") l=len(df.index) for i in range (0,l): Discipline_count=0 Discipline_list=" " for j in range (1,k): if (df.iloc[i,j]==1) & (Discipline_count<df.iloc[i,k]): Discipline_list=Discipline_list+ df.columns[j] Discipline_count+=1 if Discipline_count==df.iloc[i,k]: Aanvraag_nummer=df.iloc[i,0] new_row = {'Application number':Aanvraag_nummer, 'Discipline_list':Discipline_list, 'All_Discipline_count':df.iloc[i,k]} dfA = dfA.append(new_row, ignore_index=True)
运行警告:
/tmp/ipykernel_26718/1290491379.py:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
优化实现
利用Pandas的向量化操作替代循环,既能解决警告问题,又能大幅提升运行效率:
方案1:apply结合布尔索引生成学科列表
def get_disciplines(row): # 筛选当前行值为1的学科列,拼接成字符串 return ', '.join(row[row == 1].index) # 定位所有学科列 discipline_columns = df.loc[:, 'Physics':'Mathematics'] # 生成学科列表列 df['Discipline_list'] = discipline_columns.apply(get_disciplines, axis=1) # 提取需要的结果列 result_df = df[['Application number', 'Discipline_list', 'All_Discipline_count']] print(result_df.head(10))
方案2:dot操作实现高效向量化拼接(适合大数据量)
如果处理的申请数量较多,apply的效率仍有提升空间,可使用dot操作直接完成列名拼接:
discipline_columns = df.loc[:, 'Physics':'Mathematics'] # 用dot将列名与对应的值相乘后拼接,最后去除末尾多余的分隔符 df['Discipline_list'] = discipline_columns.dot(discipline_columns.columns + ', ').str.rstrip(', ') # 整理结果 result_df = df[['Application number', 'Discipline_list', 'All_Discipline_count']] print(result_df.head(10))
优化说明
- 两种方案均摒弃了嵌套循环,利用Pandas内置的向量化运算,处理速度比原始代码提升数倍,数据量越大优势越明显
- 不再使用
append方法,彻底消除了弃用警告 - 默认生成的学科列表用逗号分隔,可读性更强;若需要原始代码的无间隔格式,只需将拼接分隔符改为空字符串即可
内容的提问来源于stack exchange,提问作者Rohit Nirmal
相关产品推荐
相关产品推荐

