Pandas通过for循环逐列排序合并DataFrame时出现NaN问题的解决方法
问题根因
出现批量NaN完全是pd.concat的默认对齐规则和现有拼接逻辑不匹配导致的:
- 每次调用
sort_it(num)返回的DataFrame,保留的是原pbr2经过排序后的原始行索引,没有做连续重排
pandas的
pd.concat默认会按同名行索引匹配值后再拼接
你每次传入的排序结果是对不同列做升序得到的,不同结果的行索引顺序几乎完全不重叠。索引匹配不上的位置,pandas就会自动填充NaN。
举个实际场景的例子:你拿i=4的排序结果(行索引为87、18、47…)作为初始的total_df,后续拼入i=5的排序结果(行索引为22、131、52…),两个表的行索引几乎没有重合,自然除了能匹配上的列名,所有值都会错位变成NaN。
修正实现
按照你的要求(每列的排序效果和单独调用sort_it(i)的输出完全一致),提供两种适配不同使用场景的可直接运行的写法:
方案1:灵活管理所有列的排序结果,避免硬拼接的问题
适合需要单独调用某列排序结果做后续分析的场景,代码改动幅度最小:
def sort_it(num): # 提取Stock列+目标排序列,排序后立刻重置索引,消除原索引带来的对齐冲突 df = pbr2.iloc[:, [1, num]].sort_values(pbr2.columns[num]).reset_index(drop=True) return df # 用字典存储每列的排序结果,比直接拼DataFrame稳定性高很多 sorted_collect = {} # 遍历所有需要处理的目标列 for col_idx in range(4, 10): col_name = pbr2.columns[col_idx] sorted_collect[col_name] = sort_it(col_idx) # 如果需要把所有列的排序结果拼成一张总表,横向拼接即可 total_df = pd.concat(sorted_collect.values(), axis=1)
核心改动是排序后加reset_index(drop=True),把每个子表的行索引改成从0开始的连续整数,横向拼接时同行位置的内容直接对应,不会因为原索引不匹配产生空值。
方案2:保留全表结构,每列独立排序不互相干扰
适合需要对照不同日期的PBR升序排序结果的场景,不会打乱其他列的原始值:
# 初始化空的结果表 total_df = pd.DataFrame(columns=pbr2.columns) for col_idx in range(4, 10): target_col = pbr2.columns[col_idx] # 提取对应列的Stock和数值,按目标列升序排序,重置为连续索引 sorted_part = pbr2[['Stock', target_col]].sort_values(target_col).reset_index(drop=True) # 逐列赋值到总表 total_df['Stock'] = sorted_part['Stock'] total_df[target_col] = sorted_part[target_col]
踩坑提醒
- 对不同列单独做排序得到的结果,行顺序没有任何对应关系,不要靠原行索引做纵向拼接,一定会产生大量错位空值
- 所有独立的排序子表在拼接前,最好都重置为连续索引,从根源上避免pandas的自动对齐机制带来的意外空值
内容的提问来源于stack exchange,提问作者John.H 1
相关产品推荐
相关产品推荐

