iloc,ix和loc如何不同?

时间:2015-07-23 16:34:11

标签: python pandas indexing dataframe

有人可以解释这三种切片方法有何不同? 我见过the docs, 而且我已经看过these answers,但我仍然发现自己无法解释三者是如何不同的。对我来说,它们在很大程度上似乎是可以互换的,因为它们处于较低的切片水平。

例如,假设我们想获得DataFrame的前五行。这三个都是如何运作的?

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

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

4 个答案:

答案 0 :(得分:758)

注意:在pandas版本0.20.0及更高版本中,ixdeprecated,我们鼓励使用lociloc。我已经将这个答案的部分内容完整地描述为ix,作为早期版本熊猫用户的参考。下面添加了示例,显示ix 的替代方法。

首先,这里回顾一下三种方法:

  • loc从索引中获取带有特定标签的行(或列)。
  • iloc获取索引中特定位置的行(或列)(因此只需要整数)。
  • ix通常会尝试表现得像loc,但如果索引中没有标签,则会回归到iloc的行为。

重要的是要注意一些可能使ix使用起来有些棘手的细微之处:

  • 如果索引是整数类型,ix将仅使用基于标签的索引,而不会回退到基于位置的索引。如果标签不在索引中,则会引发错误。

  • 如果索引不包含整数,则给定一个整数,ix将立即使用基于位置的索引而不是基于标签的索引。但是,如果ix被赋予其他类型(例如字符串),则可以使用基于标签的索引。

为了说明三种方法之间的差异,请考虑以下系列:

>>> 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

我们将使用整数值3来查看切片。

在这种情况下,s.iloc[:3]会返回前3行(因为它将3视为一个位置),而s.loc[:3]会返回前8行(因为它将3视为标签):< / p>

>>> 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.loc[:3]相同的系列,因为它首先查找标签而不是位置(并且s的索引是整数类型)。

如果我们尝试使用索引中的整数标签(例如6),该怎么办?

此处s.iloc[:6]按预期返回系列的前6行。但是,s.loc[:6]会引发KeyError,因为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。因为我们的索引是整数类型ix,所以不会像iloc一样回归。

但是,如果我们的索引是混合类型,则给定整数ix会立即表现为iloc而不是引发KeyError:

>>> s2 = pd.Series(np.nan, index=['a','b','c','d','e', 1, 2, 3, 4, 5])
>>> s2.index.is_mixed() # index is mix of different types
True
>>> s2.ix[:6] # now 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

作为一般建议,如果您仅使用标签进行索引,或仅使用整数位置编制索引,请坚持使用lociloc以避免意外结果 - 请勿使用{{1} }。

结合基于位置和基于标签的索引

有时给定一个DataFrame,您需要为行和列混合标签和位置索引方法。

例如,请考虑以下DataFrame。如何最好地将行切割为包括&#39; c&#39; 取前四列?

ix

在早期版本的pandas中(0.20.0之前)>>> df = pd.DataFrame(np.nan, index=list('abcde'), columns=['x','y','z', 8, 9]) >>> df x y z 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 让你可以非常巧妙地做到这一点 - 我们可以按标签和列的位置对行进行切片(注意列为ix}将默认为基于位置的切片,因为ix不是列名称):

4

在pandas的更高版本中,我们可以使用>>> df.ix[:'c', :4] x y z 8 a NaN NaN NaN NaN b NaN NaN NaN NaN c NaN NaN NaN NaN 和另一种方法的帮助来实现此结果:

iloc

get_loc()是一种索引方法,意思是&#34;获取该索引中标签的位置&#34;。请注意,由于使用>>> df.iloc[:df.index.get_loc('c') + 1, :4] x y z 8 a NaN NaN NaN NaN b NaN NaN NaN NaN c NaN NaN NaN NaN 进行切片不包含其端点,因此如果我们需要行&#39; c&#39;同样。

熊猫还有其他例子。文档here

答案 1 :(得分:108)

iloc基于整数定位。因此,无论您的行标签是什么,您都可以通过

始终获得第一行
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使用命名索引。让我们设置一个数据框,其中包含字符串作为行标签和列标签:

df = pd.DataFrame(index=['a', 'b', 'c'], columns=['time', 'date', 'name'])

然后我们可以通过

获得第一行
df.loc['a']     # equivalent to df.iloc[0]

和<{p>的'date'列的后两行

df.loc['b':, 'date']   # equivalent to df.iloc[1:, 1]

等等。现在,值得指出的是DataFrame的默认行和列索引是0的整数,在这种情况下ilocloc将以相同的方式工作。这就是为什么你的三个例子是等价的。 如果您有非数字索引,例如字符串或日期时间, df.loc[:5] 会引发错误。

此外,您只需使用数据框的__getitem__

即可进行列检索
df['time']    # equivalent to df.loc[:, 'time']

现在假设您要混合位置和命名索引,即使用行上的名称和列上的位置进行索引(澄清一下,我的意思是从我们的数据框中选择,而不是在行索引中创建包含字符串的数据框)和列索引中的整数)。这是.ix的来源:

df.ix[:2, 'time']    # the first two rows of the 'time' column

我认为值得一提的是你也可以将布尔向量传递给loc方法。例如:

 b = [True, False, True]
 df.loc[b] 

将返回df的第1行和第3行。这相当于df[b]的选择,但它也可以用于通过布尔向量进行赋值:

df.loc[b, 'name'] = 'Mary', 'John'

答案 2 :(得分:82)

在我看来,接受的答案令人困惑,因为它使用只有缺失值的DataFrame。我也不喜欢.iloc基于位置一词,而是更喜欢整数位置,因为它更具描述性,而且恰好是.iloc代表。关键词是INTEGER - .iloc需要INTEGERS。

有关更多信息,请参阅我非常详细的blog series子集选择

.ix已弃用且含糊不清,绝不应使用

由于.ix已被弃用,我们只关注.loc.iloc之间的差异。

在我们讨论差异之前,了解DataFrames有标签可以帮助识别每个列和每个索引,这一点非常重要。我们来看看示例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'])

enter image description here

粗体中的所有字词都是标签。标签agecolorfoodheightscorestate用于 。其他标签JaneNickAaronPenelopeDeanChristinaCornelia用于<强>索引

在DataFrame中选择特定行的主要方法是使用.loc.iloc索引器。这些索引器中的每一个也可用于同时选择列,但现在更容易关注行。此外,每个索引器都使用一组括号,这些括号紧跟其名称后进行选择。

.loc仅按标签

选择数据

我们将首先讨论.loc索引器,它仅通过索引或列标签选择数据。在我们的示例DataFrame中,我们提供了有意义的名称作为索引的值。许多DataFrames没有任何有意义的名称,而是默认只有从0到n-1的整数,其中n是DataFrame的长度。

您可以使用三种不同的输入.loc

  • 一个字符串
  • 字符串列表
  • 使用字符串作为起始值和停止值的切片表示法

使用字符串

选择带有.loc的单行

要选择单行数据,请将索引标签放在.loc后面的括号内。

df.loc['Penelope']

这会将数据行作为Series

返回
age           4
color     white
food      Apple
height       80
score       3.3
state        AL
Name: Penelope, dtype: object

使用.loc和字符串列表选择多行

df.loc[['Cornelia', 'Jane', 'Dean']]

这将返回一个DataFrame,其中的行按列表中指定的顺序排列:

enter image description here

使用带有切片表示法的.loc选择多行

切片表示法由开始,停止和步骤值定义。按标签切片时,pandas在返回时包含停止值。以下切片从Aaron到Dean,包括在内。其步长未明确定义,但默认为1。

df.loc['Aaron':'Dean']

enter image description here

复杂切片的采用方式与Python列表相同。

.iloc仅按整数位置选择数据

现在转向.iloc。 DataFrame中的每一行和每列数据都有一个定义它的整数位置。 这是在输出中直观显示的标签的补充。整数位置只是从0开始的顶部/左侧的行数/列数。

您可以使用三种不同的输入.iloc

  • 整数
  • 整数列表
  • 使用整数作为起始值和停止值的切片表示法

选择带有整数

的.iloc的单行
df.iloc[4]

这将第5行(整数位置4)作为Series

返回
age           32
color       gray
food      Cheese
height       180
score        1.8
state         AK
Name: Dean, dtype: object

使用带有整数列表的.iloc选择多行

df.iloc[[2, -2]]

这将返回第三行和第二行到最后一行的DataFrame:

enter image description here

使用带有切片表示法的.iloc选择多行

df.iloc[:5:3]

enter image description here

使用.loc和.iloc

同时选择行和列

.loc/.iloc的一个优秀能力是它们能够同时选择行和列。在上面的示例中,从每个选择中返回所有列。我们可以选择具有与行相同类型输入的列。我们只需要使用逗号分隔行和列选择。

例如,我们可以选择行Jane,而Dean只选择列高度,分数和状态,如下所示:

df.loc[['Jane', 'Dean'], 'height':]

enter image description here

这使用行的标签列表和列

的切片表示法

我们可以自然地使用.iloc仅使用整数执行类似的操作。

df.iloc[[1,4], 2]
Nick      Lamb
Dean    Cheese
Name: food, dtype: object

使用标签和整数位置同时选择

.ix用于与标签和整数位置同时进行选择,这些选项虽然有用但有时令人困惑和含糊不清,幸好它已被弃用。如果您需要使用混合标签和整数位置进行选择,则必须同时选择标签或整数位置。

例如,如果我们想要选择行NickCornelia以及第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]]

布尔选择

.loc索引器也可以进行布尔选择。例如,如果我们有兴趣查找年龄超过30的所有行并仅返回foodscore列,我们可以执行以下操作:

df.loc[df['age'] > 30, ['food', 'score']] 

您可以使用.iloc复制此内容,但不能将其传递给布尔系列。您必须将布尔系列转换为numpy数组,如下所示:

df.iloc[(df['age'] > 30).values, [2, 4]] 

选择所有行

可以使用.loc/.iloc进行列选择。您可以使用冒号选择所有行:

df.loc[:, 'color':'score':2]

enter image description here

索引操作符[]也可以选择行和列,但不能同时选择。

大多数人都熟悉DataFrame索引运算符的主要用途,即选择列。字符串选择单个列作为Series,字符串列表选择多个列作为DataFrame。

df['food']

Jane          Steak
Nick           Lamb
Aaron         Mango
Penelope      Apple
Dean         Cheese
Christina     Melon
Cornelia      Beans
Name: food, dtype: object

使用列表选择多列

df[['food', 'score']]

enter image description here

人们不太熟悉的是,当使用切片表示法时,选择是通过行标签或整数位置进行的。这非常令人困惑,我几乎从不使用它,但确实有效。

df['Penelope':'Christina'] # slice rows by label

enter image description here

df[2:6:2] # slice rows by integer location

enter image description here

.loc/.iloc显式选择行是非常优选的。单独的索引操作符无法同时选择行和列。

df[3:5, 'color']
TypeError: unhashable type: 'slice'

答案 3 :(得分:0)

  • DataFrame.loc():按索引值选择行
  • DataFrame.iloc():按行号选择行

示例:

  1. 选择表的前5行,df1是您的数据框

df1.iloc [:5]

  1. 选择表的前A,B行,df1是您的数据框

df1.loc ['A','B']