pandas loc vs. iloc vs. at vs. iat?
- 2024-12-26 08:43:00
- admin 原创
- 128
问题描述:
最近开始从我的安全区(R)扩展到 Python,并且对中的细胞定位/选择有点困惑Pandas
。我已经阅读了文档,但我很难理解各种定位/选择选项的实际含义。
是否有理由我应该使用.loc
或而.iloc
不是at
,iat
反之亦然? 在什么情况下我应该使用哪种方法?
注意:未来的读者请注意,这个问题很老了,是在 pandas v0.20 之前编写的,当时存在一个名为 的函数
.ix
。此方法后来被拆分为两个 -loc
和iloc
- 以明确区分位置和基于标签的索引。请注意,ix
由于行为不一致且难以理解,已停用,并且在当前版本的 pandas(>= 1.0)中不再存在。
解决方案 1:
loc:仅对索引起作用
iloc:对位置起作用
at:获取标量值。这是一个非常快的 loc
iat:获取标量值。这是一个非常快的 iloc
还,
at
和iat
用于访问标量,即数据框中的单个元素,而loc
和iloc
用于同时访问多个元素,可能执行矢量化操作。
http://pyciencia.blogspot.com/2015/05/obtener-y-filtrar-datos-de-un-dataframe.html
解决方案 2:
鉴于已弃用pandas
0.20
,已更新ix
。这不仅演示了如何使用、、、、,loc
还演示了如何实现基于位置/标签的混合索引。iloc
`atiat
set_value`
loc
-基于标签
允许您传递 1-D 数组作为索引器。数组可以是索引或列的切片(子集),也可以是长度等于索引或列的布尔数组。
特别注意:当传递标量索引器时,loc
可以分配一个以前不存在的新索引或列值。
# label based, but we can use position values
# to get the labels from the index object
df.loc[df.index[2], 'ColName'] = 3
df.loc[df.index[1:3], 'ColName'] = 3
iloc
-基于位置
与 类似,loc
但使用位置而不是索引值。但是,您不能分配新列或索引。
# position based, but we can get the position
# from the columns object via the `get_loc` method
df.iloc[2, df.columns.get_loc('ColName')] = 3
df.iloc[2, 4] = 3
df.iloc[:3, 2:4] = 3
at
-基于标签的
工作方式与标量索引器非常相似loc
。 无法对数组索引器进行操作。 可以!分配新索引和列。
优点是loc
速度更快。
缺点是不能使用数组作为索引器。
# label based, but we can use position values
# to get the labels from the index object
df.at[df.index[2], 'ColName'] = 3
df.at['C', 'ColName'] = 3
iat
-基于位置
工作原理与 类似iloc
。 无法在数组索引器中工作。 不能!分配新索引和列。
优点是iloc
速度更快。
缺点是不能使用数组作为索引器。
# position based, but we can get the position
# from the columns object via the `get_loc` method
IBM.iat[2, IBM.columns.get_loc('PNL')] = 3
set_value
-基于标签的
工作原理与标量索引器非常相似loc
。 无法对数组索引器进行操作。 可以!分配新索引和列
优点超级快,因为开销很少!
缺点开销很少,因为pandas
没有进行大量安全检查。 使用风险自负。此外,这不适合公众使用。
# label based, but we can use position values
# to get the labels from the index object
df.set_value(df.index[2], 'ColName', 3)
set_value
withtakable=True
-基于位置
工作原理与 类似iloc
。 无法在数组索引器中工作。 不能!分配新索引和列。
优点超级快,因为开销很少!
缺点开销很少,因为pandas
没有进行大量安全检查。 使用风险自负。此外,这不适合公众使用。
# position based, but we can get the position
# from the columns object via the `get_loc` method
df.set_value(2, df.columns.get_loc('ColName'), 3, takable=True)
解决方案 3:
Pandas 从 DataFrame 中进行选择的主要方式有两种。
按标签
按整数位置
文档使用术语“位置”来指代整数位置。我不喜欢这个术语,因为我觉得它令人困惑。整数位置更具描述性,并且正是所代表.iloc
的。这里的关键词是INTEGER - 按整数位置选择时必须使用整数。
在显示摘要之前,让我们先确保......
.ix 已弃用且含义模糊,不应使用
Pandas有三个主要索引器。我们有索引运算符本身(括号[]
)、.loc
和.iloc
。让我们总结一下:
[]
- 主要选择列的子集,但也可以选择行。不能同时选择行和列。.loc
- 仅按标签选择行和列的子集.iloc
- 仅按整数位置选择行和列的子集
我几乎从不使用它们.at
,.iat
因为它们没有增加任何额外的功能,而且性能提升很小。除非你的应用程序对时间非常敏感,否则我不建议使用它们。无论如何,我们有它们的摘要:
.at
仅通过标签选择 DataFrame 中的单个标量值.iat
仅按整数位置选择 DataFrame 中的单个标量值
除了通过标签和整数位置进行选择之外,还存在布尔选择(也称为布尔索引)。
下面的示例解释了.loc
、.iloc
、布尔选择和.at
和.iat
我们首先关注.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'])
所有粗体字都是标签。标签 、、age
、color
和food
用于列。其他标签 、、、、、height
用作行的标签。这些行标签统称为索引。score
`stateJane
NickAaron
PenelopeDean
Christina`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
是它们能够同时选择行和列。在上面的示例中,每次选择都会返回所有列。我们可以选择与行相同的输入类型的列。我们只需用逗号分隔行和列选择即可。
例如,我们可以选择行 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 数组,如下所示:
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'
.at
由和选择.iat
使用 选择与.at
几乎相同.loc
,但它仅选择 DataFrame 中的单个“单元格”。我们通常将此单元格称为标量值。要使用.at
,请向其传递用逗号分隔的行和列标签。
df.at['Christina', 'color']
'black'
选择与.iat
几乎相同,.iloc
但它只选择一个标量值。您必须为行和列位置传递一个整数
df.iat[2, 5]
'FL'
解决方案 4:
df = pd.DataFrame({'A':['a', 'b', 'c'], 'B':[54, 67, 89]}, index=[100, 200, 300])
df
A B
100 a 54
200 b 67
300 c 89
In [19]:
df.loc[100]
Out[19]:
A a
B 54
Name: 100, dtype: object
In [20]:
df.iloc[0]
Out[20]:
A a
B 54
Name: 100, dtype: object
In [24]:
df2 = df.set_index([df.index,'A'])
df2
Out[24]:
B
A
100 a 54
200 b 67
300 c 89
In [25]:
df2.ix[100, 'a']
Out[25]:
B 54
Name: (100, a), dtype: int64
解决方案 5:
让我们从这个小的 df 开始:
import pandas as pd
import time as tm
import numpy as np
n=10
a=np.arange(0,n**2)
df=pd.DataFrame(a.reshape(n,n))
我们也会有
df
Out[25]:
0 1 2 3 4 5 6 7 8 9
0 0 1 2 3 4 5 6 7 8 9
1 10 11 12 13 14 15 16 17 18 19
2 20 21 22 23 24 25 26 27 28 29
3 30 31 32 33 34 35 36 37 38 39
4 40 41 42 43 44 45 46 47 48 49
5 50 51 52 53 54 55 56 57 58 59
6 60 61 62 63 64 65 66 67 68 69
7 70 71 72 73 74 75 76 77 78 79
8 80 81 82 83 84 85 86 87 88 89
9 90 91 92 93 94 95 96 97 98 99
由此,我们有:
df.iloc[3,3]
Out[33]: 33
df.iat[3,3]
Out[34]: 33
df.iloc[:3,:3]
Out[35]:
0 1 2 3
0 0 1 2 3
1 10 11 12 13
2 20 21 22 23
3 30 31 32 33
df.iat[:3,:3]
Traceback (most recent call last):
... omissis ...
ValueError: At based indexing on an integer index can only have integer indexers
因此我们不能对子集使用.iat,而只能使用.iloc。
但是让我们尝试从更大的 df 中进行选择,然后检查速度......
# -*- coding: utf-8 -*-
"""
Created on Wed Feb 7 09:58:39 2018
@author: Fabio Pomi
"""
import pandas as pd
import time as tm
import numpy as np
n=1000
a=np.arange(0,n**2)
df=pd.DataFrame(a.reshape(n,n))
t1=tm.time()
for j in df.index:
for i in df.columns:
a=df.iloc[j,i]
t2=tm.time()
for j in df.index:
for i in df.columns:
a=df.iat[j,i]
t3=tm.time()
loc=t2-t1
at=t3-t2
prc = loc/at *100
print('
loc:%f at:%f prc:%f' %(loc,at,prc))
loc:10.485600 at:7.395423 prc:141.784987
因此,使用 .loc 我们可以管理子集,使用 .at 只能管理单个标量,但 .at 比 .loc 更快
:-)
解决方案 6:
值得注意的是,仅访问一列,.loc
大约比以下慢 7-10 倍 []
:
测试脚本:
import os
import sys
from timeit import timeit
import numpy as np
import pandas as pd
def setup():
arr = np.arange(0, 10 ** 2)
return pd.DataFrame(arr.reshape(10, 10))
if __name__ == "__main__":
print(f"Python: {sys.version}")
print(f"Numpy: {np.__version__}")
print(f"Pandas: {pd.__version__}")
iters = 10000
print(
"[] Method:",
timeit(
"data = df[0]",
setup="from __main__ import setup; df = setup()",
number=iters,
),
)
print(
".loc() Method:",
timeit(
"data = df.loc[:, 0]",
setup="from __main__ import setup; df = setup()",
number=iters,
),
)
输出:
Python: 3.8.10 (tags/v3.8.10:3d8993a, May 3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)]
Numpy: 1.21.1
Pandas: 1.3.3
[] Method: 0.0923579000000001
.loc() Method: 0.6762988000000001