pandas iloc vs ix vs loc解释?
有人可以解释这三种切片的方法是不同的吗?
我看过这些文档 ,而且我看到了这些 答案 ,但是我仍然发现自己无法解释三者是如何不同的。 对我来说,他们似乎是可以互换的,因为他们处于较低层次的切片。
例如,假设我们想获得DataFrame
的前五行。 这三个工作怎么样?
df.loc[:5] df.ix[:5] df.iloc[:5]
有人可以提出三个使用区分更清楚的案例吗?
注意:在pandas版本0.20.0及以上版本中, 不推荐使用ix
, iloc
鼓励使用loc
和iloc
。 我已经将描述ix
的这个答案的部分留给了pandas早期版本的用户。 以下示例添加了ix
替代scheme 。
首先回顾一下:
-
loc
在索引中的标签上工作。 -
iloc
在索引中的位置工作(所以它只需要整数)。 -
ix
通常会尝试像loc
一样行为,但如果标签不在索引中,iloc
退回到像iloc
一样的行为。
重要的是要注意一些微妙的事情,可以使ix
稍微有点棘手的使用:
-
如果索引是整数types,则
ix
将只使用基于标签的索引,而不会回退到基于位置的索引。 如果标签不在索引中,则会引发错误。 -
如果索引不仅包含整数,则给定一个整数,
ix
将立即使用基于位置的索引而不是基于标签的索引。 如果ix
被赋予另一种types(例如string),则可以使用基于标签的索引。
为了说明三种方法之间的差异,请考虑以下系列:
>>> s = pd.Series(np.nan, index=[49,48,47,46,45, 1, 2, 3, 4, 5]) >>> s 49 NaN 48 NaN 47 NaN 46 NaN 45 NaN 1 NaN 2 NaN 3 NaN 4 NaN 5 NaN
然后s.iloc[:3]
返回前3行(因为它查看位置), s.loc[:3]
返回前8行(因为它查看标签):
>>> s.iloc[:3] # slice the first three rows 49 NaN 48 NaN 47 NaN >>> s.loc[:3] # slice up to and including label 3 49 NaN 48 NaN 47 NaN 46 NaN 45 NaN 1 NaN 2 NaN 3 NaN >>> s.ix[:3] # the integer is in the index so s.ix[:3] works like loc 49 NaN 48 NaN 47 NaN 46 NaN 45 NaN 1 NaN 2 NaN 3 NaN
注意s.ix[:3]
返回与s.ix[:3]
相同的系列,因为它首先查找标签,而不是按位置查找(索引是整数types)。
如果我们尝试使用不在索引中的整数标签(如6
)呢?
这里s.iloc[:6]
按照预期返回系列的前6行。 但是, s.loc[:6]
会引发s.loc[:6]
因为6
不在索引中。
>>> s.iloc[:6] 49 NaN 48 NaN 47 NaN 46 NaN 45 NaN 1 NaN >>> s.loc[:6] KeyError: 6 >>> s.ix[:6] KeyError: 6
根据上面提到的微妙之处, s.ix[:6]
现在引发了一个KeyError,因为它试图像loc
一样工作,但是在索引中找不到6
。 因为我们的索引是整数types的,所以它不会像iloc
那样iloc
。
但是,如果我们的索引是混合types的,给定一个整数ix
将立即行为像iloc
,而不是引发iloc
:
>>> s2 = pd.Series(np.nan, index=['a','b','c','d','e', 1, 2, 3, 4, 5]) >>> s2.index.is_mixed() # index is mix of types True >>> s2.ix[:6] # behaves like iloc given integer a NaN b NaN c NaN d NaN e NaN 1 NaN
请记住, ix
仍然可以接受非整数,并像loc
一样行事:
>>> s2.ix[:'c'] # behaves like loc given non-integer a NaN b NaN c NaN
作为一般build议,如果只使用标签进行索引,或者只使用整数位置进行索引,请使用loc
或iloc
以避免意外结果 – 请勿使用ix
。
结合基于位置和基于标签的索引
有时给定一个DataFrame,你会想混合行和列的标签和位置索引方法。
例如,考虑下面的DataFrame。 如何最好地将行分成“c” 和 “前四列”?
>>> df = pd.DataFrame(np.nan, index=list('abcde'), columns=['x','y','z', 8, 9]) >>> df xyz 8 9 a NaN NaN NaN NaN NaN b NaN NaN NaN NaN NaN c NaN NaN NaN NaN NaN d NaN NaN NaN NaN NaN e NaN NaN NaN NaN NaN
在早期版本的pandas(0.20.0版本之前)中, ix
可以很好地完成这项工作 – 我们可以按标签和按位分列(注意,对于列, ix
默认为基于位置的分片,因为标签4
是不是列名):
>>> df.ix[:'c', :4] xyz 8 a NaN NaN NaN NaN b NaN NaN NaN NaN c NaN NaN NaN NaN
在后来的pandas版本中,我们可以使用iloc
和另一种方法的帮助来实现这个结果:
>>> df.iloc[:df.index.get_loc('c') + 1, :4] xyz 8 a NaN NaN NaN NaN b NaN NaN NaN NaN c NaN NaN NaN NaN
get_loc()
是一个索引方法,意思是“获取该索引中标签的位置”。 请注意,由于使用iloc
片iloc
包含其端点,因此如果我们也希望行'c',则必须将此值加1。
pandas文档中还有更多的例子。
iloc
基于整数定位工作。 所以不pipe你的行标签是什么,你总是可以做到的,例如,做第一行
df.iloc[0]
或者做最后五行
df.iloc[-5:]
你也可以在列上使用它。 这检索第3列:
df.iloc[:, 2] # the : in the first position indicates all rows
你可以合并它们来获得行和列的交集:
df.iloc[:3, :3] # The upper-left 3 X 3 entries (assuming df has 3+ rows and columns)
另一方面, .loc
使用命名索引。 让我们用一个string作为行和列标签来设置一个数据框:
df = pd.DataFrame(index=['a', 'b', 'c'], columns=['time', 'date', 'name'])
然后我们可以得到第一行
df.loc['a'] # equivalent to df.iloc[0]
和'date'
列的第二行
df.loc['b':, 'date'] # equivalent to df.iloc[1:, 1]
等等。 现在,可能值得指出的是, DataFrame
的默认行和列索引是从0 DataFrame
的整数,在这种情况下, iloc
和loc
将以相同的方式工作。 这就是为什么你的三个例子是相同的。 如果您有一个非数字索引,如string或date时间,则 df.loc[:5]
会引发错误。
此外,您可以通过使用数据框的__getitem__
来执行列检索:
df['time'] # equivalent to df.loc[:, 'time']
现在假设你想混合位置和命名索引,也就是使用行上的名字和列上的位置来索引(为了说明,我的意思是从我们的数据框中select,而不是在行索引中使用string创build数据框,列索引)。 这是.ix
进来的地方:
df.ix[:2, 'time'] # the first two rows of the 'time' column
编辑:我觉得还值得一提的是,你也可以传递布尔向量到loc
方法。 例如:
b = [True, False, True] df.loc[b]
将返回df
的第一和第三行。 这相当于用于select的df[b]
,但它也可以用于通过布尔vector进行赋值:
df.loc[b, 'name'] = 'Mary', 'John'
在我看来,接受的答案是令人困惑的,因为它使用一个只有缺失值的DataFrame。 我也不喜欢.iloc
的基于位置的术语,而是更喜欢整数位置,因为它更具描述性,正是.iloc
代表的。 关键词是INTEGER – .iloc
需要INTEGERS。
.ix被弃用和模糊,不应该被使用
由于.ix
已被弃用,我们将只关注.loc
和.iloc
之间的区别。
在讨论差异之前,重要的是要明白,DataFrame具有帮助识别每列和每个索引的标签。 我们来看一个示例DataFrame:
df = pd.DataFrame({'age':[30, 2, 12, 4, 32, 33, 69], 'color':['blue', 'green', 'red', 'white', 'gray', 'black', 'red'], 'food':['Steak', 'Lamb', 'Mango', 'Apple', 'Cheese', 'Melon', 'Beans'], 'height':[165, 70, 120, 80, 180, 172, 150], 'score':[4.6, 8.3, 9.0, 3.3, 1.8, 9.5, 2.2], 'state':['NY', 'TX', 'FL', 'AL', 'AK', 'TX', 'TX'] }, index=['Jane', 'Nick', 'Aaron', 'Penelope', 'Dean', 'Christina', 'Cornelia'])
所有粗体字都是标签。 标签, age
, color
, food
, height
, score
和state
用于列 。 其他品牌, Jane
, Nick
, Aaron
, Penelope
, Dean
, Christina
, Cornelia
被用于指数 。
在DataFrame中select特定行的主要方法是使用.loc
和.iloc
索引器。 这些索引器中的每一个也可以用来同时select列,但现在更容易集中在行上。 而且,每个索引器都使用一组紧跟其名称的括号来进行select。
.loc只能通过标签select数据
我们将首先讨论仅通过索引或列标签select数据的.loc
索引器。 在我们的示例DataFrame中,我们提供了有意义的名称作为索引的值。 许多DataFrames将不会有任何有意义的名称,而是默认为0到n-1的整数,其中n是DataFrame的长度。
有三种不同的input可以用于.loc
- 一个string
- string列表
- 切片符号使用string作为开始和停止值
用一个stringselect带有.loc的单个行
要select一行数据,将索引标签放在括号内的.loc
后面。
df.loc['Penelope']
这将返回一行数据作为一个系列
age 4 color white food Apple height 80 score 3.3 state AL Name: Penelope, dtype: object
使用string列表select带有.loc的多行
df.loc[['Cornelia', 'Jane', 'Dean']]
这会按照列表中指定的顺序返回一个DataFrame:
用切片符号select多个带.loc的行
切片符号由开始,停止和步骤值定义。 按标签切片时,pandas在返回中包含停止值。 以下片段从Aaron到Dean,包含在内。 其步长没有明确定义,但默认为1。
df.loc['Aaron':'Dean']
复杂的切片可以采取与Python列表相同的方式。
.iloc只能通过整数位置来select数据
现在我们来.iloc
。 DataFrame中的每一行和一列数据都有一个定义它的整数位置。 这是在输出中可视化显示的标签之外的。 整数位置只是从0开始的顶部/左侧的行数/列数。
有三种不同的input可以用于.iloc
- 一个整数
- 整数列表
- 切片符号使用整数作为开始和停止值
用一个整数select带有.iloc的单个行
df.iloc[4]
这将返回第5行(整数位置4)作为一个系列
age 32 color gray food Cheese height 180 score 1.8 state AK Name: Dean, dtype: object
用整数列表select多行.iloc
df.iloc[[2, -2]]
这将返回第三个和第二个到最后一个行的DataFrame:
用切片符号select多行.iloc
df.iloc[:5:3]
使用.loc和.iloc同时select行和列
.loc/.iloc
一个很好的能力是它们同时select行和列的能力。 在上面的示例中,所有列都是从每个select中返回的。 我们可以select与input行types相同的列。 我们只需要用逗号分隔行和列的select。
例如,我们可以selectJane和Dean,只有列的高度,得分和状态如下所示:
df.loc[['Jane', 'Dean'], 'height':]
这使用行的列表标签和列的切片符号
我们自然可以用.iloc
做类似的操作, .iloc
用整数。
df.iloc[[1,4], 2] Nick Lamb Dean Cheese Name: food, dtype: object
同时select标签和整数位置
.ix
被用来与标签和整数位置同时进行select,这有时候是有用的,但是有时会令人困惑和模糊,幸好它已经被弃用了。 如果您需要使用标签和整数位置混合进行select,则必须同时创buildselect标签或整数位置。
例如,如果我们想要selectNick
和Cornelia
以及第2列和第4列,我们可以使用.loc
将整数转换为标签,如下所示:
col_names = df.columns[[2, 4]] df.loc[['Nick', 'Cornelia'], col_names]
或者,也可以使用get_loc
索引方法将索引标签转换为整数。
labels = ['Nick', 'Cornelia'] index_ints = [df.index.get_loc(label) for label in labels] df.iloc[index_ints, [2, 4]]
布尔select
.loc索引器也可以做布尔select。 例如,如果我们有兴趣查找年龄在30岁以上的所有行,并返回food
和score
列,我们可以执行以下操作:
df.loc[df['age'] > 30, ['food', 'score']]
你可以用.iloc
复制这个,但是你不能把它传给布尔系列。 您必须将布尔型系列转换为像这样的numpy数组:
df.iloc[(df['age'] > 30).values, [2, 4]]
select所有行
可以使用.loc/.iloc
作为列select。 你可以使用像这样的冒号来select所有的行:
df.loc[:, 'color':'score':2]
索引操作符[]
可以切片也可以同时select行和列。
大多数人都熟悉DataFrame索引操作符的主要用途,即select列。 一个stringselect一个列作为一个Series,一个string列表select多个列作为一个DataFrame。
df['food'] Jane Steak Nick Lamb Aaron Mango Penelope Apple Dean Cheese Christina Melon Cornelia Beans Name: food, dtype: object
使用列表select多个列
df[['food', 'score']]
人们不太熟悉的是,当使用切片符号时,则通过行标签或整数位置进行select。 这是非常混乱,我几乎从来没有使用,但它确实工作。
df['Penelope':'Christina'] # slice rows by label
df[2:6:2] # slice rows by integer location
用于select行的.loc/.iloc
的显式性是非常优选的。 索引操作符本身不能同时select行和列。
df[3:5, 'color'] TypeError: unhashable type: 'slice'