将列表插入单元格 - 为什么loc在这里工作?

cs9*_*s95 10 python indexing list pandas

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

在解决这个问题时,我遇到了一些奇怪的行为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]
Run Code Online (Sandbox Code Playgroud)

要设置单元格(1,'B'),只需使用at即可df.at[1, 'B'] = ....但是对于loc,我最初尝试过这个,但是没有用:

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

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

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

我想loc也能以某种方式在这里采用嵌套列表.在一个奇怪的事件中,这段代码有效:

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

    A             B
0  12        [a, b]
1  23  [m, n, o, p]
Run Code Online (Sandbox Code Playgroud)

为什么这样loc工作?此外,如果您向任何列表添加另一个元素,它将触发:

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

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

为什么这样loc做?这是记录在案的行为,还是一个错误?

And*_*den 5

这是因为loc做了一堆检查所有支持的多数用例的。(注意:历史是这样的,loc并且iloc是为了消除ix2013 v0.11 的歧义而创建的,但即使在今天, . 中仍然存在很多歧义loc。)

在这种情况下df.loc[1, 'B']可以返回:

  • 单个元素(如在本例中,当 1/'B' 有唯一索引/列时)。
  • 一个系列(如果 1/'B' 之一多次出现在索引/列中)。
  • 一个 DataFrame(如果 BOTH 1/'B' 多次出现在索引/列中)。

旁白:iloc在这种情况下遇到同样的问题,即使它总是第一种情况,但这可能是因为 loc 和 iloc 共享此分配代码。

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

赋值逻辑的早期部分将列表(列表)转换为一个 numpy 数组:

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)
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

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

In [16]: df.loc[0, 'B'] = a

In [17]: df
Out[17]:
    A             B
0  12  [m, n, o, p]
1  23        [c, d]
Run Code Online (Sandbox Code Playgroud)

它仍然不理想,但重申在locand 中有太多边缘情况,iloc解决方案是尽可能明确以避免它们(at在此处使用)。更一般地说,如您所知,避免在 DataFrame 中使用列表!