将列表插入单元格中-为什么loc在这里实际起作用?

时间:2019-01-28 10:39:01

标签: python pandas list indexing

我们知道设置单个单元格的标准方法是使用atiat。但是,我注意到一些有趣的行为,我想知道是否有人可以合理化。

在解决this question时,我遇到了loc的一些奇怪行为。

# Setup.

pd.__version__
# '0.24.0rc1'

df = pd.DataFrame({'A': [12, 23], 'B': [['a', 'b'], ['c', 'd']]})
df
    A       B
0  12  [a, b]
1  23  [c, d]

要设置单元格(1,'B'),只需使用df.at[1, 'B'] = ...这样的at即可。但是使用loc时,我最初尝试了此方法,但没有成功:

df.loc[1, 'B'] = ['m', 'n', 'o', 'p'] 
# ValueError: Must have equal len keys and value when setting with an iterable

所以,我尝试了(也失败了)

df.loc[1, 'B'] = [['m', 'n', 'o', 'p']]
# ValueError: Must have equal len keys and value when setting with an ndarray

我认为loc还能以某种方式在此处获取嵌套列表。在一件奇怪的事件中,这个代码起作用了:

df.loc[1, 'B'] = [['m'], ['n'], ['o'], ['p']]
df

    A             B
0  12        [a, b]
1  23  [m, n, o, p]

loc为什么这样工作?此外,如果您将任何其他元素添加到任何列表中,则会失败:

df.loc[1, 'B'] = [['m'], ['n'], ['o'], ['p', 'q']]
# ValueError: Must have equal len keys and value when setting with an iterable

空列表也不起作用。将每个元素嵌套在自己的列表中似乎没有意义。

为什么loc会这样做?是记录下来的行为还是错误?

1 个答案:

答案 0 :(得分:2)

之所以会这样,是因为loc进行了bunch的检查,以检查它支持的所有用例。 (请注意:历史记录是lociloc的创建是为了消除ix的歧义,可追溯到2013年v0.11,但即使到今天,{{ 1}}。)

在这种情况下,loc可以返回:

  • 单个元素(例如,在这种情况下,当1 /'B'具有唯一的索引/列时)。
  • 一个系列(如果1 /'B'之一在索引/列中多次出现)。
  • DataFrame(如果同时在索引/列中同时出现“ 1 / B”)。

此外:df.loc[1, 'B']在这种情况下会遇到相同的问题,尽管总是总是第一种情况,但这可能是因为loc和iloc共享此分配代码。 < / p>

所以熊猫需要支持所有这些情况以进行分配!

赋值逻辑的早期部分将列表中的列表转换为numpy数组:

iloc

因此,您不能仅传递列表列表并期望获得正确的数组。相反,您可以显式设置为对象数组:

In [11]: np.array(['m', 'n', 'o', 'p']).shape
Out[11]: (4,)

In [12]: np.array([['m', 'n', 'o', 'p']]).shape
Out[12]: (1, 4)

现在您可以在作业中使用它:

In [13]: a = np.empty(1, dtype=object)

In [14]: a[0] = ['m', 'n', 'o', 'p']

In [15]: a
Out[15]: array([list(['m', 'n', 'o', 'p'])], dtype=object)

这仍然不是理想的,但要重申In [16]: df.loc[0, 'B'] = a In [17]: df Out[17]: A B 0 12 [m, n, o, p] 1 23 [c, d] loc中有很多极端情况,解决方案是尽可能明确地避免它们(使用iloc这里)。而且,正如您所知,更普遍的是,避免在DataFrame中使用列表!