iloc 和 loc 有何不同?

2024-11-22 08:47:00
admin
原创
5
摘要:问题描述:有人能解释一下这两种切片方法有何不同吗?我看过文档,也看过以前的类似问题(1、2),但我仍然无法理解它们有何不同。对我来说,它们在很大程度上似乎可以互换,因为它们处于切片的较低级别。例如,假设我们想要获取 的前五行DataFrame。这两个是如何工作的?df.loc[:5] df.iloc[:5] ...

问题描述:

有人能解释一下这两种切片方法有何不同吗?我看过文档
,也看过以前的类似问题(1、2),但我仍然无法理解它们有何不同。对我来说,它们在很大程度上似乎可以互换,因为它们处于切片的较低级别。

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

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

有人可以举出一些用途区别更明确的案例吗?


曾几何时,我也想知道这两个函数有何不同df.ix[:5],但是ix它们已从 pandas 1.0 中删除,所以我不再关心了。


解决方案 1:

标签位置

这两种方法的主要区别是:

  • 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.loc一些差异/相似之处:s.iloc

<对象>描述s.loc[<object>]s.iloc[<object>]
0单件商品索引标签 处的值0(字符串'd'索引位置0 处的值(字符串'a'
0:1行(标签01一行(第一行位于位置 0)
1:47带界外末端的切片行(空系列)排(位置 1 及以上)
1:47:-1负向切球三行(标签1返回47行(空系列)
[2, 0]整数列表具有给定标签的两行行指定位置
s > 'e'Bool 系列(表示哪些值具有该属性)一行(包含'f'NotImplementedError
(s>'e').values布尔数组一行(包含'f'相同loc
999int 对象不在索引中KeyErrorIndexError(出界)
-1int 对象不在索引中KeyError返回最后一个值s
lambda x: x.index[3]可调用应用于系列(此处返回索引中的第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']。它还可以使用非整数对象进行切片:

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

行和列

loc并且iloc与 DataFrames 的工作方式与 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

loc有时我们希望混合使用行和列的标签和位置索引方法,以某种方式结合和的功能iloc

例如,考虑以下 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。

解决方案 2:

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]

'date'并且该列的后两行

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

等等。现在,可能值得指出的是,a 的默认行和列索引DataFrame是从 0 开始的整数,在本例中iloc,和loc的工作方式相同。这就是为什么你的三个例子是等效的。如果你有一个非数字索引,比如字符串或日期时间, 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] 

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

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

解决方案 3:

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

有关详细信息,请参阅我关于子集选择的极其详细的博客系列


.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'])

在此处输入图片描述

所有粗体字均为标签。标签 、、agecolorfood用于heightscorestate其他标签、、、、用于索引Jane`NickAaronPenelopeDeanChristina`Cornelia


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

.loc 仅通过标签选择数据

我们首先讨论.loc索引器,它仅通过索引或列标签选择数据。在我们的示例 DataFrame 中,我们提供了有意义的名称作为索引的值。许多 DataFrame 没有任何有意义的名称,而是默认为从 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,其行按照列表中指定的顺序排列:

在此处输入图片描述

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

切片符号由起始、终止和步长值定义。按标签切片时,pandas 在返回中包含终止值。以下切片从 Aaron 到 Dean(含)。其步长未明确定义,但默认为 1。

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

在此处输入图片描述

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

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

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

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

  • 一个整数

  • 整数列表

  • 使用整数作为起始值和终止值的切片符号

使用 .iloc 和整数选择一行

df.iloc[4]

这将以 Series 形式返回第 5 行(整数位置 4)

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是它们能够同时选择行和列。在上面的示例中,每次选择都会返回所有列。我们可以选择与行相同的输入类型的列。我们只需用逗号分隔行和列选择即可

例如,我们可以只选择列 height、score 和 state 的行 Jane 和 Dean,如下所示:

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

在此处输入图片描述

它使用标签列表表示行,使用切片符号表示列

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

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

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

.ix用于同时使用标签和整数位置进行选择,这种方法很有用,但有时会造成混淆和歧义,幸运的是,它已被弃用。如果您需要使用标签和整数位置的混合进行选择,则必须同时使用标签或整数位置进行选择。

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

布尔选择

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

在此处输入图片描述


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

大多数人都熟悉 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']]

在此处输入图片描述

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

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'

解决方案 4:

此示例将说明差异:

df = pd.DataFrame({'col1': [1,2,3,4,5], 'col2': ["foo", "bar", "baz", "foobar", "foobaz"]})
  col1  col2
0   1   foo
1   2   bar
2   3   baz
3   4   foobar
4   5   foobaz

df = df.sort_values('col1', ascending = False)
      col1  col2
    4   5   foobaz
    3   4   foobar
    2   3   baz
    1   2   bar
    0   1   foo

基于索引的访问:

df.iloc[0, 0:2]
col1         5
col2    foobaz
Name: 4, dtype: object

我们得到了排序后的数据框的第一行。(这不是索引为 0 的行,而是索引为 4 的行)。

基于位置的访问:

df.loc[0, 'col1':'col2']
col1      1
col2    foo
Name: 0, dtype: object

即使 df 已排序,我们也会得到索引为 0 的行。

解决方案 5:

loc这里的所有答案都讨论了查询数据框时和之间的区别iloc。其他一些区别:

loc可以放大Series/dataframe,但iloc不能

当涉及到分配/修改数据框中的值时,loc可以为全新的行分配值(以及更改已存在的内容),而iloc只能更改数据框中已有的内容。

在下面的代码中,使用loc,我们可以向数据框添加新行;但我们不能用 执行相同的操作iloc

df = pd.DataFrame({'A': [1, 2, 3], 'B': ['a', 'b', 'c']})

df.loc[3] = [4, 'd']     # <--- OK (now `df` has 4 rows)

df.iloc[4] = [4, 'd']    # <--- error

at同样的逻辑也适用于姊妹方法iat

df.at[4, 'A'] = 4        # <--- OK
df.iat[5, 0] = 5         # <--- error

iloc可以更新多行,但loc不能

当使用 Series 对象为数据框分配新值时,iloc可以一次更新多行,而loc仅删除那里的内容。

在下面的代码中,我们使用new_valuesSeries 更新第一行和第三行的值。使用时,它按预期工作,ilocloc只是破坏了已经存在的内容。

df = pd.DataFrame({'A': [1, 2, 3], 'B': ['a', 'b', 'c']})
new_values = pd.Series({'C2': 100, 'C1': 'new'})
index = [0, 2]

df.iloc[index] = new_values    # <--- OK

# the result
     A    B
0  100  new
1    2    b
2  100  new


df.loc[index] = new_values     # <--- not OK

# the result
     A    B
0  NaN  NaN
1  2.0    b
2  NaN  NaN

切线相关,但如果我们转换index成布尔数组,我们也可以在这里使用[]aka :;但在底层,这也使用,所以有那个。__setitem__`df[df.index.isin(index)] = new_values`iloc

解决方案 6:

.loc.iloc用于索引,即提取部分数据。本质上,区别在于.loc允许基于标签的索引,而.iloc允许基于位置的索引。

.loc如果您对和感到困惑.iloc,请记住.iloc基于索引(以i开头)位置,而.loc基于标签(以l开头)。

.loc

.loc应该基于索引标签而不是位置,因此它类似于基于 Python 字典的索引。但是,它可以接受布尔数组、切片和标签列表(这些都不适用于 Python 字典)。

iloc

.iloc根据索引位置进行查找,即,pandas其行为类似于 Python 列表。如果该位置没有索引,pandas则会引发。IndexError

示例

下面的例子说明了.iloc和之间的区别.loc。让我们考虑以下系列:

>>> s = pd.Series([11, 9], index=["1990", "1993"], name="Magic Numbers")
>>> s
1990    11
1993     9
Name: Magic Numbers , dtype: int64

.iloc示例

>>> s.iloc[0]
11
>>> s.iloc[-1]
9
>>> s.iloc[4]
Traceback (most recent call last):
    ...
IndexError: single positional indexer is out-of-bounds
>>> s.iloc[0:3] # slice
1990 11
1993  9
Name: Magic Numbers , dtype: int64
>>> s.iloc[[0,1]] # list
1990 11
1993  9
Name: Magic Numbers , dtype: int64

.loc示例

>>> s.loc['1990']
11
>>> s.loc['1970']
Traceback (most recent call last):
    ...
KeyError: ’the label [1970] is not in the [index]’
>>> mask = s > 9
>>> s.loc[mask]
1990 11
Name: Magic Numbers , dtype: int64
>>> s.loc['1990':] # slice
1990    11
1993     9
Name: Magic Numbers, dtype: int64

因为s具有字符串索引值,所以.loc使用整数索引时会失败:

>>> s.loc[0]
Traceback (most recent call last):
    ...
KeyError: 0

解决方案 7:

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

  • DataFrame.iloc():按行数选择行

例子:

选择表格的前 5 行,df1即您的数据框

df1.iloc[:5]

选择表的前 A、B 行,df1即您的数据框

df1.loc['A','B']
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   609  
  在现代项目管理中,资源的有效利用是确保项目成功的关键因素之一。随着技术的不断进步,越来越多的工具和软件被开发出来,以帮助项目经理和团队更高效地管理资源。本文将介绍10款工具,这些工具可以帮助项目团队提升资源利用效率,从而实现项目目标。禅道项目管理软件禅道项目管理软件是一款开源的项目管理工具,广泛应用于软件开发和其他行业...
项目管理系统   3  
  在项目管理领域,软件工具的不断升级和创新是推动效率和协作的关键。2024年,众多项目管理软件将迎来一系列令人期待的升级功能,这些新特性不仅将提升团队的工作效率,还将增强用户体验和数据分析能力。本文将详细介绍10款项目管理软件的最新升级功能,帮助项目经理和团队成员更好地规划和执行项目。禅道项目管理软件禅道项目管理软件一直...
开源项目管理工具   2  
  信创国产系统的10个关键厂商及其技术生态随着全球信息技术格局的不断演变,信创(信息技术应用创新)产业作为国产化替代的重要阶段,正逐步成为推动我国信息技术自主可控、安全可靠的核心力量。信创产业不仅关乎国家信息安全,也是数字经济高质量发展的关键支撑。本文将深入探讨信创国产系统中的10个关键厂商及其技术生态,分析它们在信创浪...
项目管理流程   0  
  在探讨项目管理的广阔领域中,成功并非偶然,而是精心策划、高效执行与持续优化的结果。项目管理的成功之道,可以从明确的目标设定与规划、高效的团队协作与沟通、以及灵活的风险管理与适应变化这三个核心方面进行深入解析。每个方面都是项目成功的基石,它们相互交织,共同支撑起项目的顺利推进与最终成就。明确的目标设定与规划项目管理的首要...
建筑工程项目管理规范   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用