pandas 本地对比伊洛克对比和对比什么?

pandas loc vs. iloc vs. at vs. iat?

最近开始从我的安全位置 (R) 分支到 Python 并且对 Pandas 中的单元格 localization/selection 有点困惑。我已经阅读了文档,但我很难理解各种 localization/selection 选项的实际含义。

为什么我应该在 atiat 上使用 .loc.iloc,反之亦然? 什么情况下应该使用哪种方法?


Note: future readers be aware that this question is old and was written before pandas v0.20 when there used to exist a function called .ix. This method was later split into two - loc and iloc - to make the explicit distinction between positional and label based indexing. Please beware that ix was discontinued due to inconsistent behavior and being hard to grok, and no longer exists in current versions of pandas (>= 1.0).

loc: 仅适用于索引
iloc: 工作位置
at: 获取标量值。这是一个非常快的 loc
iat: 获取标量值。这是一个非常快的 iloc

此外,

at and iat are meant to access a scalar, that is, a single element in the dataframe, while loc and iloc are ments to access several elements at the same time, potentially to perform vectorized operations.

http://pyciencia.blogspot.com/2015/05/obtener-y-filtrar-datos-de-un-dataframe.html

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

针对 pandas 0.20 进行了更新,因为 ix 已弃用。这不仅演示了如何使用 locilocatiatset_value,还演示了如何完成基于混合 positional/label 的索引.


loc - 基于标签
允许您将一维数组作为索引器传递。数组可以是索引或列的切片(子集),也可以是长度等于索引或列的布尔数组。

特别注意:当传递标量索引器时,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 没有做大量的安全检查。 使用风险自负。此外,这不适合 public 使用。

# 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 with takable=True - 基于位置
iloc 类似。 不能 在数组索引器中工作。 不能! 分配新的索引和列。

优点超级快,因为开销很小!
缺点 开销很小,因为 pandas 没有做大量的安全检查。 使用风险自负。此外,这不适合 public 使用。

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

pandas 从 DataFrame 生成select离子的主要方式有两种。

  • 标签
  • 整数位置

文档使用术语 position 来指代 integer location。我不喜欢这个术语,因为我觉得它很混乱。整数位置更具描述性,正是 .iloc 所代表的。这里的关键词是 INTEGER - 当按整数位置 selecting 时必须使用整数。

在显示摘要之前,让我们都确保...

.ix 已弃用且不明确,永远不应使用

pandas 有三个主要 索引器 。我们有索引运算符本身(方括号 [])、.loc.iloc。让我们总结一下:

  • [] - 主要是 selects 列的子集,但也可以是 select 行。不能同时 select 行和列。
  • .loc - selects 行和列的子集仅按标签
  • .iloc - selects 仅按整数位置排列的行和列的子集

我几乎从不使用 .at.iat 因为它们没有添加额外的功能,只有一个小的性能提升。除非您的应用程序对时间非常敏感,否则我不鼓励使用它们。无论如何,我们有他们的总结:

  • .at selectDataFrame 中的单个标量值仅按标签
  • .iat select仅按整数位置在 DataFrame 中提供单个标量值

除了 selection by label 和 integer location,boolean selection 也称为 boolean indexing 存在。


解释 .loc.iloc、布尔值 selection 和 .at.iat 的示例如下所示

我们将首先关注.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 用作标签行。这些行标签统称为 index.


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

.loc selects data only by labels

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

many different inputs 个可以用于 .loc 其中三个是

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

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

对于select单行数据,将索引标签放在.loc.

后面的括号内
df.loc['Penelope']

这 return 将数据行作为一个系列

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

使用带有字符串列表的 .loc 选择多行

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

这 return 是一个 DataFrame,其中的行按列表中指定的顺序排列:

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

切片符号由开始值、停止值和步长值定义。按标签切片时,pandas 将停止值包含在 return 中。以下是从 Aaron 到 Dean 的片段,包括在内。它的步长没有明确定义,但默认为 1。

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

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

.iloc selects data only by integer location

现在让我们转向.iloc。 DataFrame 中的每一行和每一列数据都有一个定义它的整数位置。这是在输出中直观显示的标签的补充。整数位置只是 rows/columns 从 top/left 从 0 开始的数字。

many different inputs 个可以用于 .iloc 其中三个是

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

使用带整数的 .iloc 选择单行

df.iloc[4]

这 return 作为系列的第 5 行(整数位置 4)

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

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

df.iloc[[2, -2]]

这return是倒数第三行和倒数第二行的数据帧:

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

df.iloc[:5:3]


同时 select行和列的离子与 .loc 和 .iloc

.loc/.iloc 两者的一项出色能力是它们能够同时 select 行和列。在上面的示例中,所有列都是从每个 select 离子中 return 编辑的。我们可以选择具有与行相同输入类型的列。我们只需要用 逗号.

分隔行和列 selection

例如,我们可以 select 行 Jane 和 Dean 仅包含高度、得分和状态列,如下所示:

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

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

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

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

同时select带有标签和整数位置的离子

.ix 用于同时生成带有标签和整数位置的 select 离子,这很有用,但有时令人困惑和模棱两可,幸好它已被弃用。如果您需要制作一个混合了标签和整数位置的 selection,则必须同时制作 selections 标签或整数位置。

例如,如果我们想要 select 行 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 索引器也可以做布尔值 selection。例如,如果我们有兴趣查找年龄大于 30 的所有行并且 return 只是 foodscore 列,我们可以执行以下操作:

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

您可以使用 .iloc 复制它,但不能将其传递给布尔系列。您必须像这样将布尔系列转换为 numpy 数组:

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

选择所有行

可以仅对 selection 列使用 .loc/.iloc。您可以 select 通过使用这样的冒号来显示所有行:

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


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

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

df['food']

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

使用列表 select 多列

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

人们不太熟悉的是,当使用切片符号时,select离子按行标签或整数位置发生。这非常令人困惑,我几乎从不使用它,但它确实有效。

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

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

对于 selecting 行 .loc/.iloc 的明确性是首选。仅索引运算符无法同时 select 行和列。

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

选择 .at.iat

使用 .at 的选择与 .loc 几乎相同,但它在您的 DataFrame 中只有 select 一个 'cell'。我们通常将此单元格称为标量值。要使用 .at,请向其传递以逗号分隔的行和列标签。

df.at['Christina', 'color']
'black'

使用 .iat 的选择与 .iloc 几乎相同,但它只有 select 一个标量值。您必须为行和列位置传递一个整数

df.iat[2, 5]
'FL'

让我们从这个小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 select 并检查速度 ...

# -*- 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('\nloc:%f at:%f prc:%f' %(loc,at,prc))

loc:10.485600 at:7.395423 prc:141.784987

因此,使用 .loc 我们可以管理子集,而使用 .at 只能管理一个标量,但 .at 比 .loc 快

:-)

需要注意的是,仅访问一个列,.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