You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas批量转换多列数据异常,单独转换却正常?

Pandas批量转换ASCII列时丢失列和行的问题

问题背景

现有一个包含三类数据的DataFrame:

  • 13列ASCII码形式的序列号数据,列名存在列表serialname_list中;
  • 所有行都存在的核心数据列;
  • 仅80%行存在、含NaN值的附加数据列。

DataFrame结构示例:

sn1  sn2  ...  sn13  data1  data2   add1  add2  
0   74   79   76   66   5.0     5.0     NaN   NaN   
1   81   66   89   65   1.0     1.0     NaN   NaN   
2   82   81   78   66   2.0     2.0     79    80   

需求是将13列ASCII码转为对应字符,合并为单个字段后删除原列,同时删除含无效浮点值的序列号行。但使用df[serialname_list] = df[serialname_list].apply(lambda x: x.map(chr))批量转换时,会丢失所有附加数据列,且删除含NaN的附加数据行;仅逐个列调用apply才能正常运行。

问题原因

核心是混淆了Pandas中apply和applymap的适用场景:

  • apply默认按列/行处理,传入的是整个Series(列/行对象),而非单个元素。若直接对多列DataFrame调用apply,要么因传入对象不匹配触发隐式异常,要么因临时结果的索引对齐问题导致原DF的列/行意外丢失。
  • 逐个列调用apply时,是对单个Series的每个元素执行函数,因此能正常工作。

正确批量处理方式

方法1:用applymap实现元素级批量转换

applymap专门用于对DataFrame的每个元素执行函数,完全匹配批量转换ASCII码的需求:

def convertserial(df):
    def chr_convert(x):
        return chr(x)
    
    # 过滤无效ASCII行(值小于1的非有效ASCII)
    msk = df[serialname_list].lt(1).any(axis=1)
    df = df.drop(df.index[msk]).reset_index(drop=True)
    
    # 批量转换ASCII码为字符
    df[serialname_list] = df[serialname_list].astype(int).applymap(chr_convert)
    # 也可直接简化为:df[serialname_list] = df[serialname_list].astype(int).applymap(lambda x: chr(x))
    
    # 生成合并后的serial字段
    df.insert(0, "serial", df.apply(
        lambda x: f"{x['sn1']}{x['sn2']}{x['sn3']}{x['sn4']+'-'+x['sn5']+x['sn6']+x['sn7']+x['sn8']+'-'+x['sn9']+x['sn10']+x['sn11'] if x['sn4'] == 'A' else '-'+x['sn4']+x['sn5']+x['sn6']+x['sn7']+'-'+x['sn8']+x['sn9']+x['sn10']}",
        axis=1
    ))
    
    # 生成position字段
    df.insert(1, "position", df.apply(
        lambda x: f"{x['sn12']+x['sn13'] if x['sn4'] == 'A' else x['sn11']+x['sn12']}",
        axis=1
    ))
    
    # 删除原序列号列
    df.drop(columns=serialname_list, inplace=True)
    return df

方法2:循环遍历列批量处理

通过循环遍历serialname_list中的列,本质和逐个列调用逻辑一致,但避免了重复代码:

def convertserial(df):
    def chr_convert(x):
        return chr(x)
    
    # 过滤无效ASCII行
    msk = df[serialname_list].lt(1).any(axis=1)
    df = df.drop(df.index[msk]).reset_index(drop=True)
    df[serialname_list] = df[serialname_list].astype(int)
    
    # 循环处理每一列
    for col in serialname_list:
        df[col] = df[col].apply(chr_convert)
    
    # 后续生成合并字段、删除原列的代码与方法1一致
    df.insert(0, "serial", df.apply(
        lambda x: f"{x['sn1']}{x['sn2']}{x['sn3']}{x['sn4']+'-'+x['sn5']+x['sn6']+x['sn7']+x['sn8']+'-'+x['sn9']+x['sn10']+x['sn11'] if x['sn4'] == 'A' else '-'+x['sn4']+x['sn5']+x['sn6']+x['sn7']+'-'+x['sn8']+x['sn9']+x['sn10']}",
        axis=1
    ))
    
    df.insert(1, "position", df.apply(
        lambda x: f"{x['sn12']+x['sn13'] if x['sn4'] == 'A' else x['sn11']+x['sn12']}",
        axis=1
    ))
    
    df.drop(columns=serialname_list, inplace=True)
    return df

关键注意事项

  • 绝对避免将df[serialname_list].apply(...)的结果直接赋值给整个df,这会导致仅保留序列号列,丢失核心数据和附加数据列。
  • 元素级批量处理优先用applymap,列/行级复杂逻辑才用apply,两者不要混用。

内容的提问来源于stack exchange,提问作者user2059972

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 21:39:53