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

是否有一个原因,为什么我应该使用。loc或。iloc在,和iat或反之亦然?在什么情况下我应该使用哪种方法?


注意:以后的读者注意,这个问题很老了,是在pandas v0.20之前写的,当时存在一个叫.ix的函数。这种方法后来被分为two - loc和iloc -,以明确区分基于位置和基于标签的索引。请注意,由于不一致的行为和难以grok, ix已被终止,并且在当前版本的pandas(>= 1.0)中不再存在。


Loc:只在索引上工作 Iloc:在职工作 At:获取标量值。这是一个非常快的loc iat:获取标量值。这是一个非常快的iloc

同时,

At和iat意味着访问一个标量,即单个元素 在数据帧中,而loc和iloc是用来访问几个的 元素的同时,可能要执行向量化 操作。

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

鉴于ix已弃用,为pandas 0.20更新。这不仅演示了如何使用loc, iloc, at, iat, 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

基于标签的 工作原理与用于标量索引器的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非常相似。不能操作数组索引器。可以!分配新的索引和列

优势超快,因为开销很小! 缺点:由于熊猫没有做一堆安全检查,所以开销很小。使用风险自负。此外,这不是为公共用途。

# 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。不能在数组索引器中工作。不能!分配新的索引和列。

优势超快,因为开销很小! 缺点:由于熊猫没有做一堆安全检查,所以开销很小。使用风险自负。此外,这不是为公共用途。

# 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中进行选择有两种主要方式。

通过标签 按整型位置

本文档使用术语position来表示整数位置。我不喜欢这个术语,因为我觉得它令人困惑。整数位置更具有描述性,这正是.iloc所代表的。这里的关键字是INTEGER—在按整数位置选择时必须使用整数。

在展示摘要之前,让我们确认一下…

.ix已弃用且具有歧义,永远不应该使用

有三个主要的熊猫索引器。我们有索引操作符本身(括号[])、.loc和.iloc。让我们来总结一下:

[] -主要选择列的子集,但也可以选择行。不能同时选择行和列。 .loc -仅通过标签选择行和列的子集 .iloc -仅通过整数位置选择行和列的子集

我几乎从不使用.at或.iat,因为它们不会增加额外的功能,而且只会增加少量的性能。我不建议使用它们,除非您的应用程序对时间非常敏感。无论如何,我们有他们的总结:

.at仅通过标签选择DataFrame中的单个标量值 .iat仅通过整数位置在DataFrame中选择单个标量值

除了根据标签和整数位置进行选择外,还有布尔选择,也称为布尔索引。


下面是解释.loc, .iloc,布尔选择和.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'])

所有加粗的字都是标签。这些列使用标签、年龄、颜色、食物、身高、分数和状态。其他标签,Jane, Nick, Aaron, Penelope, Dean, 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在返回值中包含停止值。以下是艾伦写给迪恩的片段,包括在内。它的步长没有明确定义,但默认为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]]

返回第三行和倒数第二行的数据帧:

使用.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用于同时使用标签和整数定位进行选择,这很有用,但有时会令人困惑和模糊,幸运的是,它已经被弃用了。如果需要混合使用标签和整数位置进行选择,则必须同时使用标签或整数位置。

例如,如果我们想选择行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岁的所有行,只返回食物和分数列,我们可以这样做:

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'

我们从这个小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('\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