我们知道设置单个单元格的标准方法是使用at或iat.但是,我注意到一些有趣的行为,我想知道是否有人可以合理化.
在求解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’] = …即可.但是使用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为什么这样做?是记录的行为还是错误?
解决方法:
发生这种情况是因为loc执行bunch检查所支持的所有用例. (注意:历史是loc和iloc的创建是为了消除ix的歧义,可追溯到2013 v0.11,但即使在今天,loc仍然有很多歧义.)
在这种情况下,df.loc [1,’B’]可以返回:
>单个元素(在这种情况下,当1 /’B’具有唯一的索引/列时).
>系列(如果1 /’B’之一在索引/列中多次出现).
>一个数据框(如果同时在索引/列中同时出现“ 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)
因此,您不能只传递列表列表并期望获得正确的数组.相反,您可以显式设置为对象数组:
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中使用列表!