我对以下行为感到困惑。当我有这样的数据帧时:
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randn(6, 4), columns=list('ABCD'), index=list('bcdefg'))
如下所示:
A B C D
b -0.907325 0.211740 0.150066 -0.240011
c -0.307543 0.691359 -0.179995 -0.334836
d 1.280978 0.469956 -0.912541 0.487357
e 1.447153 -0.087224 -0.176256 1.319822
f 0.660994 -0.289151 0.956900 -1.063623
g -1.880520 1.099098 -0.759683 -0.657774
我收到预期错误
TypeError:不能对这些类型为'int'
的索引器[3]进行切片索引
当我使用.loc
尝试以下切片时:
print df.loc[3:, ['C', 'D']]
我希望将一个整数作为索引传递,而不是index
中包含的一个字母。
但是,如果我现在尝试
df.loc[3:, ['C', 'D']] = 10
它工作正常并给我输出:
A B C D
b -0.907325 0.211740 0.150066 -0.240011
c -0.307543 0.691359 -0.179995 -0.334836
d 1.280978 0.469956 -0.912541 0.487357
e 1.447153 -0.087224 10.000000 10.000000
f 0.660994 -0.289151 10.000000 10.000000
g -1.880520 1.099098 10.000000 10.000000
我的问题是为什么在打印某些内容时相同的命令会失败,以及为什么在分配值时它会起作用。当我检查.loc
的文档字符串时,我原以为这会导致上面提到的错误(特别是粗体部分):
允许的输入是:
- 单个标签,例如
5
或'a'
,(请注意,5
被解释为索引的标签,**从不为整数 沿着指数的位置**)。- 标签列表或数组,例如
['a', 'b', 'c']
。- 带有标签的切片对象,例如
'a':'f'
(请注意,与通常的python切片相反,两者开始和停止都是 包括!)。- 布尔数组。
- 带有一个参数的
callable
函数(调用Series,DataFrame或Panel)并返回有效的索引输出(一个 以上)
.loc
会在找不到商品时提出KeyError
。
对此的任何解释;我在这里错过了什么?
修改
在this question中,类似的行为被认为是在0.13中修复的错误。我用0.19.1。
编辑2 在@ EdChum的帖子上建立,可以做到以下几点:
df.loc[2] = 20
df.loc[3] = 30
df.loc[4] = 40
产生
A B C D
b 0.083326 -1.047032 0.830499 -0.729662
c 0.942744 -0.535013 0.809251 1.132983
d -0.074918 1.123331 -2.205294 -0.497468
e 0.213349 0.694366 -0.816550 0.496324
f 0.021347 0.917340 -0.595254 -0.392177
g -1.149890 0.965645 0.172672 -0.043652
2 20.000000 20.000000 20.000000 20.000000
3 30.000000 30.000000 30.000000 30.000000
4 40.000000 40.000000 40.000000 40.000000
然而,这仍然让我感到困惑,因为
print df.loc['d':'f', ['C', 'D']]
工作正常,命令
print df.loc[2:4, ['C', 'D']]
给出了上面提到的索引错误。
此外,当一个人现在分配这样的值
df.loc[2:4, ['C', 'D']] = 100
数据框如下所示:
A B C D
b 0.083326 -1.047032 0.830499 -0.729662
c 0.942744 -0.535013 0.809251 1.132983
d -0.074918 1.123331 100.000000 100.000000
e 0.213349 0.694366 100.000000 100.000000
f 0.021347 0.917340 -0.595254 -0.392177
g -1.149890 0.965645 0.172672 -0.043652
2 20.000000 20.000000 20.000000 20.000000
3 30.000000 30.000000 30.000000 30.000000
4 40.000000 40.000000 40.000000 40.000000
所以这些值不会添加到一个 - 或者至少我 - 期望它们被添加(使用位置而不是标签)。
答案 0 :(得分:3)
我不认为这是一个bug而不是未记录的语义,例如,对于行标签不存在的简单情况,允许使用放大设置:
In [22]:
df.loc[3] = 10
df
Out[22]:
A B C D
b -0.907325 0.211740 0.150066 -0.240011
c -0.307543 0.691359 -0.179995 -0.334836
d 1.280978 0.469956 -0.912541 0.487357
e 1.447153 -0.087224 -0.176256 1.319822
f 0.660994 -0.289151 0.956900 -1.063623
g -1.880520 1.099098 -0.759683 -0.657774
3 10.000000 10.000000 10.000000 10.000000
如果我们传递切片,则切片中找不到标签,但因为它是一个整数切片,所以它会转换为序数切片:
In [24]:
df.loc[3:5] = 9
df
Out[24]:
A B C D
b -0.907325 0.211740 0.150066 -0.240011
c -0.307543 0.691359 -0.179995 -0.334836
d 1.280978 0.469956 -0.912541 0.487357
e 9.000000 9.000000 9.000000 9.000000
f 9.000000 9.000000 9.000000 9.000000
g -1.880520 1.099098 -0.759683 -0.657774
3 10.000000 10.000000 10.000000 10.000000
您链接的帖子和错误指的是没有分配的选择,其中传递的不存在的标签应该引发KeyError
,这在这里是不同的
如果我们查看__setitem__
:
def __setitem__(self, key, value):
key = com._apply_if_callable(key, self)
# see if we can slice the rows
indexer = convert_to_index_sliceable(self, key))
此处它将尝试转换调用convert_to_index_sliceable
:
def convert_to_index_sliceable(obj, key):
"""if we are index sliceable, then return my slicer, otherwise return None
"""
idx = obj.index
if isinstance(key, slice):
return idx._convert_slice_indexer(key, kind='getitem')
如果我们查看文档字符串:
签名:df.index._convert_slice_indexer(key,kind = None)文档字符串: 转换切片索引器。禁止在开始/停止/步骤中浮动
参数 ---------- key:切片绑定类型的标签:{'ix','loc','getitem','iloc'}或None
然后运行:
In [29]:
df.index._convert_slice_indexer(slice(3,5),'loc')
Out[29]:
slice(3, 5, None)
然后用于切片索引:
In [28]:
df.index[df.index._convert_slice_indexer(slice(3,5),'loc')]
Out[28]:
Index(['e', 'f'], dtype='object')
所以我们看到即使您传递了看似不存在的标签,整数切片对象也会转换为根据不同规则与df兼容的序数切片