摘要

本文介绍了使用 Pandas 进行数据挖掘时常用的加速技巧。

实验环境

import numpy as np
import pandas as pd
print(np.__version__)
print(pd.__version__)
1.16.5
0.25.2

性能分析工具

本文使用到的性能分析工具,参考:Python 性能评估 学习笔记

数据准备

tsdf = pd.DataFrame(np.random.randint(1, 1000, (1000, 3)), columns=['A', 'B', 'C'],
index=pd.date_range('1/1/1900', periods=1000))
tsdf['D'] = np.random.randint(1, 3, (1000, ))
tsdf.head(3)
			A	B	C
1900-01-01 820 827 884 1
1900-01-02 943 196 513 1
1900-01-03 693 194 6 2

使用 numpy 数组加速运算

map, applymap, apply 之间的区别,参考:Difference between map, applymap and apply methods in Pandas

apply(func, raw=True)

Finally, apply() takes an argument raw which is False by default, which converts each row or column into a Series before applying the function. When set to True, the passed function will instead receive an ndarray object, which has positive performance implications if you do not need the indexing functionality.

Pandas 官方文档

DataFrame.apply() 支持参数 raw,为 True 时,直接将 ndarray 输入函数,利用 numpy 并行化加速。

有多快?

%%timeit
tsdf.apply(np.mean) # raw=False (default)
# 740 µs ± 28.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%%timeit
tsdf.apply(np.mean, raw=True)
# 115 µs ± 2.76 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

由 740 微秒降低到 115 微秒。

什么条件下可以使用?

  1. 只有 DataFrame.apply() 支持,Series.apply() 和 Series.map() 均不支持;
  2. func 不使用 Series 索引时。
tsdf.apply(np.argmax)  # raw=False, 保留索引
A   2019-12-08
B 2021-03-14
C 2020-04-09
D 2019-11-30
dtype: datetime64[ns]
tsdf.apply(np.argmax, raw=True)  # 索引丢失
A      8
B 470
C 131
D 0
dtype: int64

.values

多个 Series 计算时,可以使用 .values 将 Series 转换为 ndarray 再计算。

%%timeit
tsdf.A * tsdf.B
# 123 µs ± 2.86 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%%timeit
tsdf.A.values * tsdf.B.values
# 11.1 µs ± 1.09 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)

由 123 微秒降低到 11 微秒。

补充说明

注意到 Pandas 0.24.0 引入了 .array 和 .to_numpy(),参考。但这两种方法的速度不如 values,建议在数据为数值的情况下继续使用 values。

%%timeit
tsdf.A.array * tsdf.B.array
# 37.9 µs ± 938 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%%timeit
tsdf.A.to_numpy() * tsdf.B.to_numpy()
# 15.6 µs ± 110 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

可见两种方法均慢于 values 的 11 微秒。

字符串操作优化

数据准备

tsdf['S'] = tsdf.D.map({1: '123_abc', 2: 'abc_123'})
%%timeit
tsdf.S.str.split('_', expand=True)[0] # 得到'_'之前的字符串
# 1.44 ms ± 97.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

一种优化思路是:针对特定场景,不需要使用 split,可以改用 partition:

%%timeit
tsdf.S.str.partition('_', expand=True)[0]
# 1.39 ms ± 44.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

速度略有提升。试试 apply :

%%timeit
tsdf.S.apply(lambda a: a.partition('_')[0])
# 372 µs ± 8.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

可见使用 apply 速度反而比 Pandas 自带的字符串处理方法要快,这可能是因为 Pandas 支持的数据类型多,处理过程中存在一些冗余的判断。

注意到原有数据只有2种,理论上对每一种数据取值只需要计算一次,其它值直接 map 就行。因此考虑转换为 Categorical 类型:

tsdf['S_category'] = tsdf.S.astype('category')
%%timeit
tsdf.S_category.apply(lambda a: a.partition('_')[0])
# 246 µs ± 3.36 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

耗时降低至 246 微秒。

IO 优化

Pandas 性能优化 学习笔记的更多相关文章

  1. KVM性能优化学习笔记

    本学习笔记系列都是采用CentOS6.x操作系统,KVM虚拟机的管理也是采用virsh方式,网上的很多的文章都基于ubuntu高版本内核下,KVM的一些新的特性支持更好,本文只是记录了CentOS6. ...

  2. 深挖计算机基础:Linux性能优化学习笔记

    参考极客时间专栏<Linux性能优化实战>学习笔记 一.CPU性能:13讲 Linux性能优化实战学习笔记:第二讲 Linux性能优化实战学习笔记:第三讲 Linux性能优化实战学习笔记: ...

  3. mysql性能优化学习笔记-参数介绍及优化建议

    MySQL服务器参数介绍 mysql参数介绍(客户端中执行),尽量只修改session级别的参数. 全局参数(新连接的session才会生效,原有已经连接的session不生效) set global ...

  4. mysql性能优化学习笔记

    mysql性能优化 硬件对数据库的影响 CPU资源和可用内存大小 服务器硬件对mysql性能的影响 我们的应用是CPU密集型? 我们的应用的并发量如何? 数量比频率更好 64位使用32位的服务器版本 ...

  5. js性能优化--学习笔记

    <高性能网站建设进阶指南>: 1.使用局部变量,避免深入作用域查找,局部变量是读写速度最快的:把函数中使用次数超过一次的对象属性和数组存储为局部变量是一个好方法:比如for循环中的.len ...

  6. mysql性能优化学习笔记(1)优化目的、方向及数据库准备

    前言: 最近参加面试,问到了很多关于mysql的优化方面的问题,回答的不是很好,也是因为原先做的项目流量不是很大,所以对mysql优化不是太了解,所以趁着周末,恶补一下. 本文来源于慕课网sqlerc ...

  7. php性能优化学习笔记

    编写代码 1.尽可能多的使用内置函数2.比对内置函数的时间复杂度,选择复杂度低的 比如 循环20万次-测试isset 和 array_key_exists 耗时 对比isset.php , array ...

  8. Java性能优化学习笔记

    1. 尽量在合适的场合使用单例 使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例,简单来说,单例主要适用于以下三个方面: 第一,控制资源的使用,通过线程同步来控 ...

  9. PHP性能优化学习笔记--PHP周边性能优化--来自慕课网Pangee http://www.imooc.com/learn/205

    PHP一般运行于Linux服务器中,周边主要包括:Linux运行环境.文件存储.数据库.缓存.网络 常见PHP场景的开销次序: 读写内存<<读写数据库(使用内存作为缓存.异步处理)< ...

随机推荐

  1. 版本控制gitlab

    目录 1. 版本控制介绍 2. gitlab部署 3. gitlab管理 1. 版本控制介绍 版本控制是指对软件开发过程中各种程序代码.配置文件及说明文档等文件变更的管理,是软件配置管理的核心思想之一 ...

  2. OO博客作业-《JML之卷》

    OO第三单元小结 一.JML语言理论基础以及应用工具链情况梳理 一句话来说,JML就是用于对JAVA程序设计逻辑的预先约定的一种语言,以便正确严格高效地完成程序以及展开测试,这在不能容忍细微错误的工程 ...

  3. Python - Git for windows 下使用 交互式命令行

    1. 概述 尝试在 windows 环境的 git 命令行使用 python3 的交互模式 2. 环境 OS win10 1905 git 2.20.1 mintty 2.9.4 python 3.7 ...

  4. Go递归函数

    package main import "fmt" func main() { /* 递归函数(recursion):一个函数自己调用自己,就叫做递归函数. 递归函数要有一个出口, ...

  5. MSComm控件进行串口编程的基本步骤

    Visual C++为我们提供了一种好用的ActiveX控件Microsoft Communications Control(即MSComm)来支持应用程序对串口的访问,在应用程序中插入MSComm控 ...

  6. ios开源

    a http://code.cocoachina.com b http://code4app.com c http://www.oschina.net/ios/codingList/ d github ...

  7. 分享Linux系统快速入门法

    相信看到这篇文章的你一定是想要学习Linux,或者已经在学习Linux的人了,那我们就可以一起探讨一下,学习Linux如何快速入门呢? 首先,希望大家弄清楚自己为什么要学习Linux,有的人是因为兴趣 ...

  8. 怎么拆分一个Excel工作簿中的多个工作表?

    打开需要编辑的Excel文档.如图所示,工作簿下方有很多工作表.现在需要将这些工作表单独拆分开成一个个工作簿.   右键任意一个工作表标签,在弹出的下拉列表中选择查看代码.即弹出代码窗口.如下图所示. ...

  9. 分布式系统(二) --SOA 以及一些网络通信协议TCP/UDP SYN攻击

    SOA(面向服务的架构):Service Oriented Architecture面向服务的架构.也就是把工程拆分成服务层.表现层两个工程.服务层中包含业务逻辑,只需要对外提供服务即可.表现层只需要 ...

  10. 强化学习-Q-learning学习笔记

    Q学习动作探索策略中的ep-greepy,以ep的概率进行随机探索,以1-ep的概率以最大值策略进行开发,因为设定的迭代次数比较多,所以肯定存在一定的次数去搜索不同的动作. 1)Python版本 b站 ...