pandas .at与.loc

piR*_*red 49 python dataframe pandas

我一直在探索如何优化我的代码并运行pandas .at方法.根据文档

基于标签的快速标量访问器

与loc类似,at提供基于标签的标量查找.您也可以使用这些索引器进行设置.

所以我跑了一些样品:

建立

import pandas as pd
import numpy as np
from string import letters, lowercase, uppercase

lt = list(letters)
lc = list(lowercase)
uc = list(uppercase)

def gdf(rows, cols, seed=None):
    """rows and cols are what you'd pass
    to pd.MultiIndex.from_product()"""
    gmi = pd.MultiIndex.from_product
    df = pd.DataFrame(index=gmi(rows), columns=gmi(cols))
    np.random.seed(seed)
    df.iloc[:, :] = np.random.rand(*df.shape)
    return df

seed = [3, 1415]
df = gdf([lc, uc], [lc, uc], seed)

print df.head().T.head().T
Run Code Online (Sandbox Code Playgroud)

df 好像:

            a                                        
            A         B         C         D         E
a A  0.444939  0.407554  0.460148  0.465239  0.462691
  B  0.032746  0.485650  0.503892  0.351520  0.061569
  C  0.777350  0.047677  0.250667  0.602878  0.570528
  D  0.927783  0.653868  0.381103  0.959544  0.033253
  E  0.191985  0.304597  0.195106  0.370921  0.631576
Run Code Online (Sandbox Code Playgroud)

让我们使用.at.loc确保我得到同样的东西

print "using .loc", df.loc[('a', 'A'), ('c', 'C')]
print "using .at ", df.at[('a', 'A'), ('c', 'C')]

using .loc 0.37374090276
using .at  0.37374090276
Run Code Online (Sandbox Code Playgroud)

测试速度使用 .loc

%%timeit
df.loc[('a', 'A'), ('c', 'C')]

10000 loops, best of 3: 180 µs per loop
Run Code Online (Sandbox Code Playgroud)

测试速度使用 .at

%%timeit
df.at[('a', 'A'), ('c', 'C')]

The slowest run took 6.11 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 8 µs per loop
Run Code Online (Sandbox Code Playgroud)

这看起来是一个巨大的速度增长.即使在缓存阶段6.11 * 8也要快得多180

有什么限制.at?我有动力去使用它.文档说它类似,.loc但它的行为并不相似.例:

# small df
sdf = gdf([lc[:2]], [uc[:2]], seed)

print sdf.loc[:, :]

          A         B
a  0.444939  0.407554
b  0.460148  0.465239
Run Code Online (Sandbox Code Playgroud)

print sdf.at[:, :]结果在哪里TypeError: unhashable type

即使意图相似,显然也不一样.

也就是说,谁可以提供有关该.at方法可以做什么和不可以做什么的指导?

unu*_*tbu 46

更新:df.get_value自版本0.21.0起不推荐使用.使用df.at或是df.iat推荐的方法.


df.at 只能一次访问一个值.

df.loc 可以选择多个行和/或列.

请注意,还df.get_value可以更快地访问单个值:

In [25]: %timeit df.loc[('a', 'A'), ('c', 'C')]
10000 loops, best of 3: 187 µs per loop

In [26]: %timeit df.at[('a', 'A'), ('c', 'C')]
100000 loops, best of 3: 8.33 µs per loop

In [35]: %timeit df.get_value(('a', 'A'), ('c', 'C'))
100000 loops, best of 3: 3.62 µs per loop
Run Code Online (Sandbox Code Playgroud)

在引擎盖下,df.at[...] 调用df.get_value,但它也对键进行了一些类型检查.

  • 请注意,自版本0.21.0起,不推荐使用`get_value`. (3认同)
  • 您可能想再次测试一下。已经没有太大区别了。%timeit df.at[100, ['A']] = 10 661 µs ± 2.91 µs 每个循环(平均值 ± 标准偏差,7 次运行,每次 1000 次循环) %timeit df.loc[100, ['A' ]] = 10 645 µs ± 3.21 µs 每个循环(7 次运行的平均值 ± 标准差,每次 1000 个循环) (2认同)

Cle*_*leb 25

当你问到限制时.at,我最近遇到过一件事(使用pandas 0.22).让我们使用文档中的示例:

df = pd.DataFrame([[0, 2, 3], [0, 4, 1], [10, 20, 30]], index=[4, 5, 6], columns=['A', 'B', 'C'])
df2 = df.copy()

    A   B   C
4   0   2   3
5   0   4   1
6  10  20  30
Run Code Online (Sandbox Code Playgroud)

如果我现在这样做

df.at[4, 'B'] = 100
Run Code Online (Sandbox Code Playgroud)

结果看起来像预期的那样

    A    B   C
4   0  100   3
5   0    4   1
6  10   20  30
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试做的时候

 df.at[4, 'C'] = 10.05
Run Code Online (Sandbox Code Playgroud)

似乎.at尝试保护的数据类型(这里int):

    A    B   C
4   0  100  10
5   0    4   1
6  10   20  30
Run Code Online (Sandbox Code Playgroud)

这似乎是一个区别.loc:

df2.loc[4, 'C'] = 10.05
Run Code Online (Sandbox Code Playgroud)

产生所需的

    A   B      C
4   0   2  10.05
5   0   4   1.00
6  10  20  30.00
Run Code Online (Sandbox Code Playgroud)

上面示例中的风险是它以静默方式发生(从转换float为int`).当一个人尝试相同的字符串时,它会抛出一个错误:

df.at[5, 'A'] = 'a_string'
Run Code Online (Sandbox Code Playgroud)

ValueError:基数为10的int()的无效文字:'a_string'

  • 好点子!我一直在争论我应该把它带到哪里. (3认同)
  • @piRSquared:是的,如果在任何地方都进行了记录(这可能会忽略了它,我应该尝试使用0.23)会很好。 (2认同)
  • 谢谢您,它确实确实尝试保留数字数据类型。我正在尝试df.at [1,'test'] ='string'`,但它不起作用。`.loc`解决了问题 (2认同)
  • 因此,如果你传递 `int()` 能够使用的任何内容,它将起作用......这意味着你可以这样做: `df.at[5, "A"] = "123"` 并且它将分配字符串,一路将其转换为 int 。 (2认同)

Vik*_*nti 5

.at与 相比,是一种优化的数据访问方法.loc

.loc数据框的选择由其参数中给定的indexed_rows和labeled_columns定位的所有元素。相反,.at选择位于给定indexed_row 和labeled_column 处的数据帧的特定元素。

此外,.at采用一行和一列作为输入参数,而.loc可能采用多行和列。输出使用的.at是单个元素,并且.loc可能使用 Series 或 DataFrame。


eme*_*mem 5

除上述内容外,该at函数的Pandas文档指出:

访问行/列标签对的单个值。

与 loc 类似,两者都提供基于标签的查找。如果您只需要在 DataFrame 或 Series 中获取或设置单个值,请使用 at。

对于设置数据locat是类似的,例如:

df = pd.DataFrame({'A': [1,2,3], 'B': [11,22,33]}, index=[0,0,1])
Run Code Online (Sandbox Code Playgroud)

双方locat会产生相同的结果

df.at[0, 'A'] = [101,102]
df.loc[0, 'A'] = [101,102]

    A   B
0   101 11
0   102 22
1   3   33

df.at[0, 'A'] = 103
df.loc[0, 'A'] = 103

    A   B
0   103 11
0   103 22
1   3   33
Run Code Online (Sandbox Code Playgroud)

此外,对于访问单个值,两者是相同的

df.loc[1, 'A']   # returns a single value (<class 'numpy.int64'>)
df.at[1, 'A']    # returns a single value (<class 'numpy.int64'>)

3
Run Code Online (Sandbox Code Playgroud)

但是,当匹配多个值时,loc将从 DataFrame 返回一组行/列,同时at返回一组值

df.loc[0, 'A']  # returns a Series (<class 'pandas.core.series.Series'>)

0    103
0    103
Name: A, dtype: int64

df.at[0, 'A']   # returns array of values (<class 'numpy.ndarray'>)

array([103, 103])
Run Code Online (Sandbox Code Playgroud)

更重要的是,loc可用于匹配一组行/列,并且只能给出一个索引,而at必须接收列

df.loc[0]  # returns a DataFrame view (<class 'pandas.core.frame.DataFrame'>)

    A   B
0   103 11
0   103 22


# df.at[0]  # ERROR: must receive column
Run Code Online (Sandbox Code Playgroud)