协慌网

登录 贡献 社区

iloc 和 loc 有何不同?

有人可以解释这两种切片方法有何不同吗?
我看过文档,也看过这些答案,但是我仍然发现自己无法理解这三个方面的不同。在我看来,它们在很大程度上似乎是可互换的,因为它们处于切片的较低级别。

例如,假设我们要获取DataFrame的前五行。这两个如何运作?

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

有人能提出三种情况下用途区别更清楚的情况吗?


很久以前,我也想知道这两个函数与df.ix[:5]不同,但是ix已从 pandas 1.0 中删除,所以我不再在乎了。

答案

标签位置

两种方法之间的主要区别是:

  • loc获取带有特定标签的行(和 / 或列)。

  • iloc在整数位置获取行(和 / 或列)。

为了演示,考虑一系列s字符与非单调的整数索引:

>>> s = pd.Series(list("abcdef"), index=[49, 48, 47, 0, 1, 2]) 
49    a
48    b
47    c
0     d
1     e
2     f

>>> s.loc[0]    # value at index label 0
'd'

>>> s.iloc[0]   # value at index location 0
'a'

>>> s.loc[0:1]  # rows at index labels between 0 and 1 (inclusive)
0    d
1    e

>>> s.iloc[0:1] # rows at index location between 0 and 1 (exclusive)
49    a

当传递各种对象时, s.locs.iloc之间的一些差异 / 相似之处:

<对象>描述s.loc[<object>] s.iloc[<object>]
0单项索引标签0值(字符串'd'索引位置0 处的值(字符串'a'
0:1行(标签01排(第一行在位置 0)
1:47越界结束的切片行(空系列)五行(从位置 1 开始)
1:47:-1带有负阶跃的切片排(标签147行(空系列)
[2, 0]整数列表行带有给定标签具有给定位置的两行
s > 'e'布尔系列(指示哪些值具有属性) (含有一个'f' NotImplementedError
(s>'e').values布尔数组(含有一个'f'loc
999 int 对象不在索引中KeyError IndexError (超出范围)
-1 int 对象不在索引中KeyError s中的最后一个值
lambda x: x.index[3]可调用的应用于系列(此处返回索引中的第三项) s.loc[s.index[3]] s.iloc[s.index[3]]

loc的标签查询功能扩展了超出整数索引的范围,值得重点介绍几个其他示例。

这是一个其中索引包含字符串对象的系列:

>>> s2 = pd.Series(s.index, index=s.values)
>>> s2
a    49
b    48
c    47
d     0
e     1
f     2

由于loc s2.loc['a']获取 Series 中的第一个值。它也可以切片非整数对象:

>>> s2.loc['c':'e']  # all rows lying between 'c' and 'e' (inclusive)
c    47
d     0
e     1

对于 DateTime 索引,我们不需要传递确切的日期 / 时间即可按标签进行获取。例如:

>>> s3 = pd.Series(list('abcde'), pd.date_range('now', periods=5, freq='M')) 
>>> s3
2021-01-31 16:41:31.879768    a
2021-02-28 16:41:31.879768    b
2021-03-31 16:41:31.879768    c
2021-04-30 16:41:31.879768    d
2021-05-31 16:41:31.879768    e

然后,要获取 2021 年 3 月 / 4 月的行,我们只需要:

>>> s3.loc['2021-03':'2021-04']
2021-03-31 17:04:30.742316    c
2021-04-30 17:04:30.742316    d

行和列

lociloc工作方式与在 Series 中相同。值得注意的是,这两种方法都可以同时处理列和行。

给定元组时,第一个元素用于索引行,如果存在,则第二个元素用于索引列。

考虑下面定义的 DataFrame:

>>> import numpy as np 
>>> df = pd.DataFrame(np.arange(25).reshape(5, 5),  
                      index=list('abcde'), 
                      columns=['x','y','z', 8, 9])
>>> df
    x   y   z   8   9
a   0   1   2   3   4
b   5   6   7   8   9
c  10  11  12  13  14
d  15  16  17  18  19
e  20  21  22  23  24

然后例如:

>>> df.loc['c': , :'z']  # rows 'c' and onwards AND columns up to 'z'
    x   y   z
c  10  11  12
d  15  16  17
e  20  21  22

>>> df.iloc[:, 3]        # all rows, but only the column at index location 3
a     3
b     8
c    13
d    18
e    23

有时我们想为行和列混合标签和位置索引方法,以某种方式结合lociloc的功能。

例如,考虑以下 DataFrame。如何最好地将行切成 “c”包括前四列?

>>> import numpy as np 
>>> df = pd.DataFrame(np.arange(25).reshape(5, 5),  
                      index=list('abcde'), 
                      columns=['x','y','z', 8, 9])
>>> df
    x   y   z   8   9
a   0   1   2   3   4
b   5   6   7   8   9
c  10  11  12  13  14
d  15  16  17  18  19
e  20  21  22  23  24

iloc和另一种方法的帮助来实现此结果:

>>> df.iloc[:df.index.get_loc('c') + 1, :4]
    x   y   z   8
a   0   1   2   3
b   5   6   7   8
c  10  11  12  13

get_loc()是一个索引方法,意思是 “获取标签在此索引中的位置”。请注意,由于使用iloc切片不包括其端点,因此如果还要行'c',则必须在此值上加 1。

iloc基于整数定位。因此,无论您的行标签是什么,您都可以始终执行以下操作:

df.iloc[0]

或最后五行

df.iloc[-5:]

您也可以在列上使用它。这将检索第三列:

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]

'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的第一行和第三行。这等效于df[b]进行选择,但也可以用于通过布尔向量进行分配:

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 中选择特定行的主要方法是使用.loc.iloc索引器。这些索引器中的每一个也可以用于同时选择列,但是现在只专注于行会更容易。同样,每个索引器都使用紧跟其名称的一组括号进行选择。

.loc 仅通过标签选择数据

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

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

  • 一串
  • 字符串列表
  • 使用字符串作为起始值和终止值的切片符号

用带字符串的. loc 选择单行

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

df.loc['Penelope']

这将数据行作为系列返回

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

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

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

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

在此处输入图片说明

使用带有切片符号的. loc 选择多行

切片符号由开始值,停止值和步长值定义。按标签切片时,熊猫会在返回值中包含停止值。以下是从亚伦(Aaron)到院长(Dean)的片段。它的步长未明确定义,但默认为 1。

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

在此处输入图片说明

可以采用与 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:

在此处输入图片说明

使用带有切片符号的. iloc 选择多行

df.iloc[:5:3]

在此处输入图片说明


使用. loc 和. iloc 同时选择行和列

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

例如,我们可以选择 Jane 行和 Dean 行,它们的高度,得分和状态如下:

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

在此处输入图片说明

这对行使用标签列表,对列使用切片符号

我们自然可以只使用整数.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 index 方法将索引标签转换为整数。

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复制此文件,但不能将其传递为布尔系列。您必须将 boolean Series 转换为 numpy 数组,如下所示:

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

选择所有行

可以将.loc/.iloc仅用于列选择。您可以使用冒号选择所有行,如下所示:

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

在此处输入图片说明


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

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

df['food']

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

使用列表选择多个列

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

在此处输入图片说明

人们所不熟悉的是,当使用切片符号时,选择是通过行标签或整数位置进行的。这非常令人困惑,我几乎从未使用过,但是确实可以使用。

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

在此处输入图片说明

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

在此处输入图片说明

.loc/.iloc来选择行。单独的索引运算符无法同时选择行和列。

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