这两种方法之间的主要区别在于:
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
之间的一些区别/相似之处:<object> | 描述 | s.loc[<object>] | s.iloc[<object>] |
---|---|---|---|
0 | 单个项目 | 位于索引标签 0 (字符串'd' )处的值 | 位于位置 0 的值(字符串'a' ) |
0:1 | 切片 | 两行(标签0 和1 ) | 一行(位置为 0 的第一行) |
1:47 | 带越界结尾的片段 | 零行(空系列) | 五行(从位置 1 开始) |
1:47:-1 | 带有负步长的切片 | 三行(标签从1 到47 ) | 零行(空系列) |
[2, 0] | 整数列表 | 两行,带有给定标签 | 两行,带有给定位置 |
s > 'e' | 布尔序列(指示哪些值具有此属性) | 一行(包含'f' ) | NotImplementedError |
(s>'e').values | 布尔数组 | 一行(包含'f' ) | 与loc 相同 |
999 | 不在索引中的int对象 | KeyError | IndexError (越界) |
-1 | 不在索引中的int对象 | 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
在DataFrame中的使用方式与它们在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
的功能。
例如,考虑以下数据框。如何最好地切片包括行到'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。
loc
,iloc
和 ix
,仍然可能触发警告。在链接文档中的示例数据帧上执行 dfmi.loc[:, 'one'].loc[:, 'second']
就像 dfmi['one']['second']
一样会触发警告,因为第一个索引操作可能返回数据的副本(而不是视图)。请注意,这里的警告是指可能会影响代码性能和正确性的潜在问题。 - Alex Rileydf.ix[date, 'Cash']
的内容,您会使用什么? - cjm2671loc
或ix
都应该可以使用。例如,df.loc['2016-04-29', 'Cash']
将返回所有具有该特定日期的行索引从'Cash'列中。(在检索带有字符串的索引时,您可以尽可能具体,例如,'2016-01'
将选择所有在2016年1月份的日期时间,'2016-01-02 11'
将选择2016年1月2日时间为11:??:??的日期时间。) - Alex Rileyiloc
是基于整数位置进行定位的。因此,无论你的行标签是什么,你总可以通过以下方式获取第一行:
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]
等等。现在值得指出的是,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]
将返回df
的第1行和第3行。这等同于使用选择操作符df[b]
,但也可用于通过布尔向量进行赋值:
df.loc[b, 'name'] = 'Mary', 'John'
df.loc[:, :]
一样。它可以用于重新分配整个DataFrame的值或创建其视图。 - JoeCondron我认为,被接受的答案很令人困惑,因为它使用了只有缺失值的DataFrame。我也不喜欢用基于位置来表示.iloc
,而更喜欢整数位置,因为这更具描述性,也正是.iloc
的精确含义。关键词是INTEGER-.iloc
需要整数。
关于子集选择的更多信息,请参见我极其详细的博客系列。
由于.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中选择特定行的主要方法是使用.loc
和.iloc
索引器。每个索引器也可以同时选择列,但现在我们只关注行。此外,每个索引器都使用紧随其名称的一组方括号来进行选择。
首先讨论只按索引或列标签选择数据的.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
。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
的一个优点是它们可以同时选择行和列。在上面的例子中,每个选择都返回了所有列。我们可以像选择行一样选择列。只需要用逗号将行和列的选择分开即可。
例如,我们可以选择行Jane和Dean,并只选取height、score和state这三列,如下所示:
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的行,并仅返回food
和score
列,我们可以执行以下操作:
df.loc[df['age'] > 30, ['food', 'score']]
您可以使用 .iloc
复制此操作,但是您无法将布尔序列传递给它。您必须像这样将布尔序列转换为numpy数组:
您可以使用.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'
loc
而不是 label
?这种命名方式似乎只会让人感到困惑。 - ericdf = 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
df.loc[0, 'col1':'col2']
col1 1
col2 foo
Name: 0, dtype: object
.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
DataFrame.loc()
:通过索引值选择行DataFrame.iloc()
:通过行号选择行示例:
选择表格的前5行,df1
是您的数据框
df1.iloc[:5]
从表格中选择第一个A、B行,df1
是您的数据框。
df1.loc['A','B']
loc
和iloc
之间的区别。另一个区别是loc
可以扩大一个Series/数据框,而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