pandas iloc vs ix vs loc解释?

有人可以解释这三种切片的方法是不同的吗?
我看过这些文档 ,而且我看到了这些 答案 ,但是我仍然发现自己无法解释三者是如何不同的。 对我来说,他们似乎是可以互换的,因为他们处于较低层次的切片。

例如,假设我们想获得DataFrame的前五行。 这三个工作怎么样?

 df.loc[:5] df.ix[:5] df.iloc[:5] 

有人可以提出三个使用区分更清楚的案例吗?

注意:在pandas版本0.20.0及以上版本中, 不推荐使用ixiloc鼓励使用lociloc 我已经将描述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议,如果只使用标签进行索引,或者只使用整数位置进行索引,请使用lociloc以避免意外结果 – 请勿使用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()是一个索引方法,意思是“获取该索引中标签的位置”。 请注意,由于使用ilociloc包含其端点,因此如果我们也希望行'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的整数,在这种情况下, ilocloc将以相同的方式工作。 这就是为什么你的三个例子是相同的。 如果您有一个非数字索引,如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']) 

在这里输入图像说明

所有粗体字都是标签。 标签, agecolorfoodheightscorestate用于 。 其他品牌, JaneNickAaronPenelopeDeanChristinaCornelia被用于指数


在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标签或整数位置。

例如,如果我们想要selectNickCornelia以及第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岁以上的所有行,并返回foodscore列,我们可以执行以下操作:

 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'