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

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列。

原始数据

SegmentCountrySegment 1Country 1Segment 2
NaNNaN123456123456NaN
NaNNaNNaNNaNNaN
NaNNaNNaN123456123456
NaNNaNNaN123456123456

当前错误结果

SegmentCountrySegment 1Country 1Segment 2
Seg1 ; Country1 ;Seg1 ; Country1 ;123456123456NaN
NaNNaNNaNNaNNaN
country1 ; seg2 ;country1 ; seg2 ;NaN123456123456
country1 ; seg2 ;country1 ; seg2 ;NaN123456123456

期望结果

SegmentCountrySegment 1Country 1Segment 2
Segment 1Country 1123456123456NaN
NaNNaNNaNNaNNaN
Segment 2Country 1NaN123456123456
Segment 2Country 1NaN123456123456

当前代码及错误

#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)

代码逻辑说明

  1. 列分类:先筛选出所有Segment类型和Country类型的扩展列,排除需要填充的目标列(Segment、Country)。
  2. 目标列填充:对每行遍历对应类型的扩展列,取最后一个非空列的列名填充到目标列(符合示例期望结果的逻辑)。
  3. Amount列处理:按原需求,将Segment类列的非空值填充到Amount列。
  4. 避免报错:全程未使用str访问器处理可能含NaN的列,从根源避免了原错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 21:25:18