当返回的列表长度与数据框列数相同时,应用 + 列表推导会给出 ValueError

Posted

技术标签:

【中文标题】当返回的列表长度与数据框列数相同时,应用 + 列表推导会给出 ValueError【英文标题】:apply + list comprehension gives ValueError when returned list length is same as number of data frame columns 【发布时间】:2018-05-01 19:55:03 【问题描述】:

这个问题来自this comment thread。使用熊猫0.20.3

我试图理解为什么 apply() 操作会引发错误:

ValueError: 传递的项目数错误 2,位置暗示 1

Pandas ValueError 的这种特殊风格是 not uncommon,但它通常来自更明显的尝试,即把一堆元素塞进一个为较小容量而设计的数据结构中。这里肯定发生了同样的事情,但我不知道为什么。

给定一个包含整数列 AB 的数据框:

import pandas as pd

df = pd.DataFrame('A': [1,2], 'B': [3,4])
df
   A  B
0  1  3
1  2  4

我可以构造一个新列C,它是一列列表。C 中的每个列表都包含来自 AB 的值。C 应如下所示:

     C
[1, 3]
[2, 4]

我选择使用apply() 和列表理解来构建C

df['C'] = df.apply(lambda x: [val for val in x], axis=1)

(现在,请忽略这不是实现此目标的最优雅方式的可能性 - 它主要是解决我感到困惑的错误的途径。)

这会抛出上面提到的ValueError但是,我可以毫无困难地创建每行包含 更多 个项目的列表:

df['C'] = df.apply(lambda x: [val for val in x]+[1], axis=1)
df
   A  B          C
0  1  3  [1, 3, 1]
1  2  4  [2, 4, 1]

我原以为我会得到同样的错误,只是使用 Wrong number of items passed 3... 而不是 2

我也可以用更少的项目创建C

df['C'] = df.apply(lambda x: [val for val in x][:1], axis=1)
df
   A  B    C
0  1  3  [1]
1  2  4  [2]

此外,C 在第一行的列表长度小于或大于[1,3] 时构建,但在第一行的列表长度与len([1,3]) 匹配时失败,即使后续列表长度不同:

df['C'] = df.apply(lambda x: [val for val in x if val != 1], axis=1) # this works
df['C'] = df.apply(lambda x: [val for val in x if val != 4], axis=1) # this fails

考虑到所有这些不同的情况,我不明白placement implies 1 指的是什么,以及为什么我不能只使用AB 的元素来制作C 中的列表,使用这种方法。 我如何误解了此错误消息?

【问题讨论】:

我无法在 0.21 上重现此内容。但我可以告诉你,pandas 特例列表和 numpy 数组与数据框具有相同的宽度。 这也是你可以做df.apply(tuple, 1)但不能做df.apply(list, 1)的原因 有趣 - 你能指出我讨论“特殊情况”的任何地方吗? 我认为最相关的链接是:github.com/pandas-dev/pandas/issues/16321 在我尝试之后,df.apply(lambda x: [val for val in x if val != 2], axis=1),我感到震惊...... 【参考方案1】:

这种行为似乎是由 (a) .apply() 试图提供帮助和 (b) 滥用 .apply() 作为输出手段的混合造成的非标量值。已在 Pandas 版本0.21 中修复。

我从各种 Pandas Github 问题页面 [1、2、3] 拼凑了这个解释,其中一些也链接到 this answer。这并不能真正解释为什么会在实施级别发生这种情况,但它至少实质性地回答了这个问题。 很高兴接受任何相关的更新/编辑。

.apply() 试图提供帮助: 如果返回一个与输入 DataFrame 具有相同形状的多维值,apply 将推断一个 DataFrame 作为输出:

TomAugspurger:DataFrame.apply 尝试根据结果推断输出。您的输出结果被推断为具有相同列的 DataFrame。 [ref]

jreback:问题是 .apply 必须尝试找出您返回的内容以及它如何映射到起始数据。 [ref]

关于滥用 .apply() 作为输出非标量值的一种方式: 简而言之,如果可以避免,请不要这样做。如果必须,期待偶尔有趣的结果。

jreback:请注意,通常不建议返回非标量,也无法有效支持。 [ref]

【讨论】:

以上是关于当返回的列表长度与数据框列数相同时,应用 + 列表推导会给出 ValueError的主要内容,如果未能解决你的问题,请参考以下文章

循环遍历 pandas 数据框列中的列表元素以在新列中返回列表

将一些函数应用于列表中的数据框列

当列数事先未知时如何访问 Pandas 数据框列

将列表与数据框列进行比较并使用数字创建新列

当 QPlainTextEdit 在一定长度时运行方法

将字典映射到数据框列中的列表