栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

Pandas的性能适用于vs.np.vectorize从现有列创建新列

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Pandas的性能适用于vs.np.vectorize从现有列创建新列

首先 ,我要说的是Pandas和NumPy数组的功能是从对数字数组的高性能 矢量化
计算中获得的。1向量化计算的全部目的是通过将计算移至高度优化的C代码并利用连续的内存块来避免Python级循环。2

Python级循环

现在我们来看一些时间。以下是 所有
的Python级环,其任一产生

pd.Series
np.ndarray
list
包含相同值的对象。为了分配给数据框内的序列,结果是可比较的。

# Python 3.6.5, NumPy 1.14.3, Pandas 0.23.0np.random.seed(0)N = 10**5%timeit list(map(divide, df['A'], df['B']))  # 43.9 ms%timeit np.vectorize(divide)(df['A'], df['B'])          # 48.1 ms%timeit [divide(a, b) for a, b in zip(df['A'], df['B'])]# 49.4 ms%timeit [divide(a, b) for a, b in df[['A', 'B']].itertuples(index=False)]     # 112 ms%timeit df.apply(lambda row: divide(*row), axis=1, raw=True)       # 760 ms%timeit df.apply(lambda row: divide(row['A'], row['B']), axis=1)   # 4.83 s%timeit [divide(row['A'], row['B']) for _, row in df[['A', 'B']].iterrows()]  # 11.6 s

一些要点:

  1. tuple
    基的方法(第一4)是一个因素比更有效的
    pd.Series
    基于方法(最后3)。
  2. np.vectorize
    ,列表理解+
    zip
    map
    方法(即前3名)的性能大致相同。这是因为它们使用
    tuple
    绕过了熊猫的一些开销
    pd.Dataframe.itertuples
  3. 使用
    raw=True
    with
    pd.Dataframe.apply
    和不使用时,速度显着提高。此选项将NumPy数组而不是
    pd.Series
    对象提供给自定义函数。

pd.Dataframe.apply
:只是另一个循环

确切地 查看Pandas传递的对象,可以对函数进行微不足道的修改:

def foo(row):    print(type(row))    assert False  # because you only need to see this oncedf.apply(lambda row: foo(row), axis=1)

输出:

<class'pandas.core.series.Series'>
。相对于NumPy数组,创建,传递和查询Pandas系列对象会带来大量开销。这不足为奇:Pandas系列包含相当数量的脚手架,用于存放索引,值,属性等。

再次进行相同的练习

raw=True
,您会看到
<class 'numpy.ndarray'>
。所有这些都在文档中进行了描述,但是看到它更具说服力。

np.vectorize
:假向量化

的文档

np.vectorize
有以下注意事项:

pyfunc
除了使用numpy的广播规则外,矢量化函数像python map函数一样对输入数组的连续元组求值。

这里的“广播规则”是无关紧要的,因为输入数组具有相同的尺寸。与之并行

map
是有启发性的,因为上述
map
版本具有几乎相同的性能。该源代码显示发生的事情:
np.vectorize
你的输入函数转换成通用的功能通过(“ufunc”)
np.frompyfunc
。有些优化,例如缓存,可以带来一些性能改进。

总之,

np.vectorize
做一个Python级环路什么 应该
做,但
pd.Dataframe.apply
增加了一个矮胖的开销。您不会看到任何JIT编译
numba
(请参见下文)。这只是一种方便。

真正的向量化:您 应该 使用什么

为什么在任何地方都没有提到上述差异?因为真正矢量化计算的性能使它们无关紧要:

%timeit np.where(df['B'] == 0, 0, df['A'] / df['B'])       # 1.17 ms%timeit (df['A'] / df['B']).replace([np.inf, -np.inf], 0)  # 1.96 ms

是的,这比上述循环式解决方案中最快的速度快40倍。这些都可以接受。我认为,第一个是简洁,可读和高效的。

numba
如果性能至关重要,这只是瓶颈,请仅查看其他方法,例如下面的方法。

numba.njit
:更高的效率

当循环 认为可行时,通常可以通过

numba
底层的NumPy数组对其进行优化,以尽可能多地移至C。

实际上,将

numba
性能提高到了 微秒 。没有一些繁琐的工作,将很难获得比这更高的效率。

from numba import njit@njitdef divide(a, b):    res = np.empty(a.shape)    for i in range(len(a)):        if b[i] != 0: res[i] = a[i] / b[i]        else: res[i] = 0    return res%timeit divide(df['A'].values, df['B'].values)  # 717 µs

使用

@njit(parallel=True)
可以为更大的阵列提供进一步的提升。


1种数字类型包括:

int
float
datetime
bool
category
。它们 不包含
object
dtype,可以保存在连续的内存块中。

2 NumPy操作相对于Python高效的原因至少有两个:

  • Python中的所有内容都是一个对象。与C不同,这包括数字。因此,Python类型具有本机C类型不存在的开销。
  • NumPy方法通常基于C。另外,在可能的情况下使用优化算法。


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/611973.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号