Pandas按Segment/Country列类型填充对应列及代码报错解决
Pandas按列类型填充Segment/Country列解决方案
需求说明
与Stack Overflow帖子《How to fill in a column with column names whose rows are not NULL in Pandas?》需求类似,但无需拼接非空列名,而是根据列名属于Segment或Country类型,分别填充到对应的Segment列和Country列。
原始数据
| Segment | Country | Segment 1 | Country 1 | Segment 2 |
|---|---|---|---|---|
| NaN | NaN | 123456 | 123456 | NaN |
| NaN | NaN | NaN | NaN | NaN |
| NaN | NaN | NaN | 123456 | 123456 |
| NaN | NaN | NaN | 123456 | 123456 |
当前错误结果
| Segment | Country | Segment 1 | Country 1 | Segment 2 |
|---|---|---|---|---|
| Seg1 ; Country1 ; | Seg1 ; Country1 ; | 123456 | 123456 | NaN |
| NaN | NaN | NaN | NaN | NaN |
| country1 ; seg2 ; | country1 ; seg2 ; | NaN | 123456 | 123456 |
| country1 ; seg2 ; | country1 ; seg2 ; | NaN | 123456 | 123456 |
期望结果
| Segment | Country | Segment 1 | Country 1 | Segment 2 |
|---|---|---|---|---|
| Segment 1 | Country 1 | 123456 | 123456 | NaN |
| NaN | NaN | NaN | NaN | NaN |
| Segment 2 | Country 1 | NaN | 123456 | 123456 |
| Segment 2 | Country 1 | NaN | 123456 | 123456 |
当前代码及错误
#For each column in df, check if there is a value and if yes : first copy the value into the 'Amount' Column, then copy the column name into the 'Segment' or 'Country' columns for column in df.columns[3:]: valueList = df[column][3:].values valueList = valueList[~pd.isna(valueList)] def detect(d): cols = d.columns.values dd = pd.DataFrame(columns=cols, index=d.index.unique()) for col in cols: s = d[col].loc[d[col].str.contains(col[0:3], case=False)].str.replace(r'(\w+)(\d+)', col + r'\2') dd[col] = s return dd #Fill amount Column with other columns values if NaN if column in isSP: df['Amount'].fillna(df[column], inplace = True) df['Segment'] = df.iloc[:, 3:].notna().dot(df.columns[3:] + ';' ).str.strip(';') df['Country'] = df.iloc[:, 3:].notna().dot(df.columns[3:] + ' ; ' ).str.strip(';') df[['Segment', 'Country']] = detect(df[['Segment', 'Country']].apply(lambda x: x.astype(str).str.split(r'\s+[+]\s+').explode()))
错误信息:AttributeError: Can only use .str accessor with string values!. Did you mean: 'std'?
问题分析与解决方案
错误原因
原代码中调用d[col].str.contains时,目标列存在NaN值(如第二行的Segment和Country列),而str访问器仅支持字符串类型,NaN不属于字符串类型,因此触发报错。此外原代码逻辑复杂且偏离需求,可大幅简化。
修正后代码
import pandas as pd import numpy as np # 构造示例数据(若已有数据可跳过此步) data = { 'Segment': [np.nan, np.nan, np.nan, np.nan], 'Country': [np.nan, np.nan, np.nan, np.nan], 'Segment 1': [123456, np.nan, np.nan, np.nan], 'Country 1': [123456, np.nan, 123456, 123456], 'Segment 2': [np.nan, np.nan, 123456, 123456] } df = pd.DataFrame(data) # 区分Segment和Country类型的扩展列(排除目标填充列) segment_cols = [col for col in df.columns if col.startswith('Segment') and col != 'Segment'] country_cols = [col for col in df.columns if col.startswith('Country') and col != 'Country'] # 填充Segment列:取每行中最后一个非空的Segment类列名 df['Segment'] = df[segment_cols].apply( lambda row: next((col for col in reversed(segment_cols) if pd.notna(row[col])), np.nan), axis=1 ) # 填充Country列:取每行中最后一个非空的Country类列名 df['Country'] = df[country_cols].apply( lambda row: next((col for col in reversed(country_cols) if pd.notna(row[col])), np.nan), axis=1 ) # 处理Amount列填充(按原需求,假设isSP为Segment类列集合) isSP = set(segment_cols) df['Amount'] = np.nan # 初始化Amount列 for col in segment_cols + country_cols: if col in isSP: df['Amount'].fillna(df[col], inplace=True) # 输出结果 print(df)
代码逻辑说明
- 列分类:先筛选出所有Segment类型和Country类型的扩展列,排除需要填充的目标列(Segment、Country)。
- 目标列填充:对每行遍历对应类型的扩展列,取最后一个非空列的列名填充到目标列(符合示例期望结果的逻辑)。
- Amount列处理:按原需求,将Segment类列的非空值填充到Amount列。
- 避免报错:全程未使用
str访问器处理可能含NaN的列,从根源避免了原错误。
内容的提问来源于stack exchange,提问作者Gatarlo
相关产品推荐
相关产品推荐

