Pandas:基于特定值选择性拼接列的技术问题求助
Pandas序列号拼接:高效向量化解决方案
问题回顾
数据集包含sn1至sn13列,其中前11列(列名存于serialname_list)为序列号的ASCII码,需完成:
- 将ASCII码转为字符
- 按两种格式拼接序列号:
- 常规格式:
XXX-XXXX-XXX(sn4不为'A'时) - 特殊格式:
XXXA-XXX-XXX(sn4为'A'时,A固定在第4位)
- 常规格式:
- 结果存入
serial字段,移除原sn列
原代码存在两个核心问题:
- 两次赋值
serial字段,导致不符合条件的行被覆盖为NaN - 逐行
apply效率低下,未利用Pandas向量化特性
问题根源
原代码中df['serial'] = df[df['sn4']=='A'].apply(...)仅给符合条件的行赋值,其他行留空;第二次赋值df['serial'] = df[df['sn4']!='A'].apply(...)会覆盖第一次的结果,最终只有第二次条件匹配的行有值,其余为NaN。
优化方案(向量化实现)
利用Pandas字符串操作和np.where实现全量向量化处理,彻底避免逐行循环:
步骤1:ASCII转字符
用applymap直接对所有元素执行chr转换,比逐列map更简洁:
df_serial = df[serialname_list].applymap(chr)
步骤2:构造完整字符串并按格式拆分拼接
先将每行的字符拼接成完整字符串,再按两种格式截取并添加分隔符:
# 拼接每行的所有字符为完整字符串 df_serial['full_str'] = df_serial.agg(''.join, axis=1) # 生成常规格式序列号:XXX-XXXX-XXX df_serial['normal_serial'] = ( df_serial['full_str'].str[:3] + '-' + df_serial['full_str'].str[3:7] + '-' + df_serial['full_str'].str[7:10] ) # 生成特殊格式序列号:XXXA-XXX-XXX df_serial['long_serial'] = ( df_serial['full_str'].str[:4] + '-' + df_serial['full_str'].str[4:7] + '-' + df_serial['full_str'].str[7:10] )
步骤3:根据sn4值选择对应格式
用np.where一次性完成赋值,完全避免覆盖问题:
import numpy as np df_serial['serial'] = np.where( df_serial['sn4'] == 'A', df_serial['long_serial'], df_serial['normal_serial'] )
步骤4:清理冗余列
保留serial字段,移除原sn列和中间临时列:
result = df_serial.drop(columns=serialname_list + ['full_str', 'normal_serial', 'long_serial'])
完整优化代码
import numpy as np import pandas as pd def convertserial(df): # 1. ASCII转字符 df_serial = df[serialname_list].applymap(chr) # 2. 拼接完整字符串并生成两种格式的序列号 df_serial['full_str'] = df_serial.agg(''.join, axis=1) # 常规格式:XXX-XXXX-XXX df_serial['normal_serial'] = ( df_serial['full_str'].str[:3] + '-' + df_serial['full_str'].str[3:7] + '-' + df_serial['full_str'].str[7:10] ) # 特殊格式:XXXA-XXX-XXX df_serial['long_serial'] = ( df_serial['full_str'].str[:4] + '-' + df_serial['full_str'].str[4:7] + '-' + df_serial['full_str'].str[7:10] ) # 3. 根据sn4选择对应格式 df_serial['serial'] = np.where( df_serial['sn4'] == 'A', df_serial['long_serial'], df_serial['normal_serial'] ) # 4. 清理冗余列 return df_serial.drop(columns=serialname_list + ['full_str', 'normal_serial', 'long_serial'])
关键优势
- 效率提升:全向量化操作避免逐行循环,处理大数据集时性能远超
apply(axis=1) - 无值覆盖:一次性赋值所有行,不会出现NaN覆盖问题
- 代码简洁:逻辑清晰,易于维护和扩展
内容的提问来源于stack exchange,提问作者user2059972
相关产品推荐
相关产品推荐

