Pandas按条件拆分列赋值失败:COL1/COL2全为NaN问题求助
Pandas 按条件拆分列赋值失效问题解决
问题场景
需要对DataFrame中Class列以TEST开头的行,将Values列按/拆分后分别存入新增的COL1和COL2列,其余行保持NaN。但执行代码后COL1和COL2全为NaN;直接操作筛选出的子集也无法修改原DataFrame:
示例代码
import pandas as pd sample_data = { 'Class': ['TEST', 'NOT TEST', 'TEST 123', 'SOMETHING ELSE', 'TEST'], 'Values': ['1.3 / 4.5', '1.5', '0.7 / 5.2', '123', '1.5 / 4.0'] } df = pd.DataFrame(sample_data) mask = df['Class'].str.startswith('TEST') # 期望的操作 df.loc[mask, ['COL1', 'COL2']] = df.loc[mask, 'Values'].str.split(' / ', expand=True) df.head() # COL1、COL2全为NaN
子集操作无效的情况
df_subset = df[mask] df_subset[['COL1', 'COL2']] = df_subset['Values'].str.split(' / ', expand=True) df.head() # 原DataFrame无变化,但df_subset已正确赋值
失效原因分析
直接赋值全NaN的原因:
str.split(expand=True)返回的临时DataFrame列名为0和1,而目标列是COL1和COL2,Pandas赋值时会严格对齐列名,因列名不匹配导致赋值失败,最终COL1和COL2保持初始全NaN状态。子集操作无效的原因:
df[mask]属于布尔索引,返回的是原DataFrame的副本而非视图,对副本的修改不会同步到原DataFrame中,这也是Pandas常见SettingWithCopyWarning的触发场景。
解决方案
方案1:对齐列名后赋值
先将拆分结果的列名修改为目标列名,再通过loc赋值:
import pandas as pd sample_data = { 'Class': ['TEST', 'NOT TEST', 'TEST 123', 'SOMETHING ELSE', 'TEST'], 'Values': ['1.3 / 4.5', '1.5', '0.7 / 5.2', '123', '1.5 / 4.0'] } df = pd.DataFrame(sample_data) mask = df['Class'].str.startswith('TEST') # 拆分并修改列名 split_df = df.loc[mask, 'Values'].str.split(' / ', expand=True).rename(columns={0: 'COL1', 1: 'COL2'}) # 赋值到原DataFrame df.loc[mask, ['COL1', 'COL2']] = split_df print(df.head())
方案2:直接使用值数组赋值
跳过列名对齐,直接提取拆分结果的数值数组进行赋值:
import pandas as pd sample_data = { 'Class': ['TEST', 'NOT TEST', 'TEST 123', 'SOMETHING ELSE', 'TEST'], 'Values': ['1.3 / 4.5', '1.5', '0.7 / 5.2', '123', '1.5 / 4.0'] } df = pd.DataFrame(sample_data) mask = df['Class'].str.startswith('TEST') # 初始化COL1、COL2为NaN df[['COL1', 'COL2']] = pd.NA # 提取拆分结果的数值数组赋值 df.loc[mask, ['COL1', 'COL2']] = df.loc[mask, 'Values'].str.split(' / ', expand=True).values print(df.head())
方案3:避免操作副本,直接修改原DataFrame
通过loc直接定位原DataFrame的行进行修改,而非赋值给新变量:
import pandas as pd sample_data = { 'Class': ['TEST', 'NOT TEST', 'TEST 123', 'SOMETHING ELSE', 'TEST'], 'Values': ['1.3 / 4.5', '1.5', '0.7 / 5.2', '123', '1.5 / 4.0'] } df = pd.DataFrame(sample_data) mask = df['Class'].str.startswith('TEST') # 直接通过loc修改原DataFrame的子集 df.loc[mask, ['COL1', 'COL2']] = df.loc[mask, 'Values'].str.split(' / ', expand=True).values print(df.head())
内容的提问来源于stack exchange,提问作者Russell Hirsch
相关产品推荐
相关产品推荐

