创建一个带有集合的列,将该集合复制n次。

4
我在使用pandas时遇到了这种意想不到的行为,我无法解释,并且在SO上没有发现任何相关的问题。
从列表字典创建数据帧时,按照预期会将可迭代对象中的每个元素放入由给定键指定的新行列中。
pd.DataFrame({'a':[1,2,3]})

   a
0  1
1  2
2  3

然而,尝试对一个set执行相同操作则会产生以下结果:
pd.DataFrame({'a':{1,2,3}})

       a
0  {1, 2, 3}
1  {1, 2, 3}
2  {1, 2, 3}

看起来这个集合被复制了,直到它实际包含的元素数量为止,即3个。

我知道对于这个问题使用集合似乎并没有什么意义,因为集合按照定义是无序的集合。但是我找不到任何关于这种行为的参考或解释。文档中是否有指定?我是否忽略了显而易见的原因?

pd.__version__
# '1.0.0'

奇怪,可以确认0.25.3版本做了同样的事情。 - kakkeuno
1个回答

3
问题出在 extract_index 和有点儿出在 sanitize_array。完整的步骤如下:
import pandas as pd
from pandas.core.internals.construction import init_dict

#pd.DataFrame({'a':{1,2,3}})
data = {'a': {1,2,3}}
index = None
columns = None
dtype = None

从字典构建将经过此代码块

elif isinstance(data, dict):
    mgr = init_dict(data, index, columns, dtype=dtype)

而且你可以看到索引是不正确的:

BlockManager
Items: Index(['a'], dtype='object')
Axis 1: RangeIndex(start=0, stop=4, step=1)
ObjectBlock: slice(0, 1, 1), 1 x 4, dtype: object

这是因为init_dict这样做,它将arrays=[{1, 2, 3}]传递给extract_index,而pandas认为集合是类似于列表的。这意味着它将此集合的长度作为您的索引长度
from pandas.core.dtypes.common import is_list_like

is_list_like({1,2,3})
#True

另一个问题是由于存储列表或集合的数组的ndim差异,因此底层的np.array创建方式不同。这个问题相当隐蔽 在这里
np.array({1,2,3}).ndim
#0

np.array([1,2,3]).ndim
#1

因此,该集合被视为“标量”,它被广播到上面指定的整个RangeIndex,变成array([{1, 2, 3}, {1, 2, 3}, {1, 2, 3}], dtype=object),而列表保持为array([1, 2, 3])
由于提取索引时存在问题,简单的解决方法是指定索引,这样就不会经过任何一个索引。
pd.DataFrame({'a': {1,2,3}}, index=[0])
#           a
#0  {1, 2, 3}

1
抱歉,我想好好看看这个,但现在没有太多时间。我会尽快回复你的。在此期间非常感谢你的帮助 :-) - yatu
看到您分享的最后一个链接中所做的事情,感觉很有见地。基本上会调用construct_1d_arraylike_from_scalar函数,由于将值视为标量,因此似乎会将其值广播到length,而length将使用索引长度? - yatu
@yatu 是的。可能会出现混乱,因为它们执行 getattr(val, "ndim", 1) == 1,所以当 val{1,2,3} 时,它将没有 ndim,但会得到默认值 1,因此会通过该子句,但很可能不应该这样做,然后稍后这是一个错误,因为 numpy.array({1,2,3}) 的 ndim 不是 1。 - ALollz
嗯,我明白了。你发现得很好!我的观点是,在这种情况下,似乎存在缺陷。并不是用字典集定义数据帧最有意义,但无论如何,这种行为显然是出乎意料的。 - yatu
1
@yatu 我同意。特别是因为 pd.DataFrame({'a': {1}, 'b': {1,2}}) 会在错误中报告长度不匹配,尽管我们知道在广播时它只会将它们视为标量。也许值得提出一个错误报告,但我现在没有时间。 - ALollz
1
已经有一个PR来解决这个问题,看起来解决方案将是从集合中构建一个列表:if isinstance(data, set): data = list(data) - yatu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接