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

如何为Pandas DataFrame生成符合条件的列名列表列,规避循环与赋值错误?

问题描述

现有如下结构的Pandas DataFrame,需要生成choices列:收集每行中值为1的列名后缀(如choice_a取a)组成列表,若没有值为1的列则设为NA。原循环代码运行报错,需解决错误并尽可能避免使用循环。

示例数据:

data = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 0, 1], [0, 0, 0]]
df = pd.DataFrame(data, columns=["choice_a", "choice_b", "choice_c"])

预期结果:

choice_a  choice_b  choice_c  choices
index                  
0        0       0           1         ['c']
1        0       1           0         ['b']
2        1       0           0         ['a']
3        1       0           1         ['a','c']
4        0       0           0         NA

原报错代码:

df['choices']=0
for i in np.arange(df.shape[0]):
    choice_list = []
    for j in np.arange(len(df.columns)):
        if df.iloc[i,j]==1:
            choice_list.append(df.columns[j].split('_')[1])
    df.iloc[i,4]=choice_list

报错信息:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/var/folders/65/3mqr9fpn37jf2xt2pxbcgp_w0000gn/T/ipykernel_1513/2279334138.py in <module>
      5         if main_dataset.iloc[i,j]==1:
      6             choice_list.append(main_dataset.columns[j].split('_')[1])
----> 7     main_dataset.iloc[i,5]=choice_list

~/opt/anaconda3/lib/python3.9/site-packages/pandas/core/indexing.py in __setitem__(self, key, value)
    714 
    715         iloc = self if self.name == "iloc" else self.obj.iloc
--> 716         iloc._setitem_with_indexer(indexer, value, self.name)
    717 
    718     def _validate_key(self, key, axis: int):

~/opt/anaconda3/lib/python3.9/site-packages/pandas/core/indexing.py in _setitem_with_indexer(self, indexer, value, name)
   1689         if take_split_path:
   1690             # We have to operate column-wise
-> 1691             self._setitem_with_indexer_split_path(indexer, value, name)
   1692         else:
   1693             self._setitem_single_block(indexer, value, name)

~/opt/anaconda3/lib/python3.9/site-packages/pandas/core/indexing.py in _setitem_with_indexer_split_path(self, indexer, value, name)
   1744                     return self._setitem_with_indexer((pi, info_axis[0]), value[0])
   1745 
-> 1746                 raise ValueError(
   1747                     "Must have equal len keys and value "
   1748                     "when setting with an iterable"

ValueError: Must have equal len keys and value when setting with an iterable

报错原因:直接通过iloc给单个单元格赋值列表时,Pandas会默认将列表视为要分配给多个元素的序列,而非单个单元格的值,因此触发长度不匹配的错误。

解决方案

以下是两种无需嵌套循环的高效实现方式:

方法一:使用apply+列表推导式(代码简洁,适合小数据集)

import pandas as pd
import numpy as np

data = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 0, 1], [0, 0, 0]]
df = pd.DataFrame(data, columns=["choice_a", "choice_b", "choice_c"])

# 提前提取所有列名的后缀
col_suffixes = [col.split('_')[1] for col in df.columns]

# 逐行筛选值为1的列对应的后缀,生成列表
df['choices'] = df.apply(
    lambda row: [col_suffixes[i] for i, val in enumerate(row) if val == 1],
    axis=1
)

# 将空列表替换为NA
df['choices'] = df['choices'].map(lambda x: x if x else np.nan)

方法二:使用melt+groupby(完全矢量化,适合大数据集)

import pandas as pd
import numpy as np

data = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 0, 1], [0, 0, 0]]
df = pd.DataFrame(data, columns=["choice_a", "choice_b", "choice_c"])

# 重置索引以便后续分组
df_reset = df.reset_index()
# 宽表转长表,拆分列名与对应值
melted = df_reset.melt(id_vars='index', var_name='choice_col', value_name='value')
# 提取列名后缀
melted['suffix'] = melted['choice_col'].str.split('_').str[1]
# 按索引分组,收集值为1的后缀成列表
choices = melted[melted['value'] == 1].groupby('index')['suffix'].agg(list)
# 合并回原DataFrame,无匹配的行自动填充NA
df = df.join(choices.rename('choices'))

两种方法都能得到预期结果,其中方法二完全基于Pandas的矢量化操作,避免了逐行处理,在数据量较大时性能更优。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 05:45:38