使用Python Pandas处理亿级数据的方法


Posted in Python onJune 24, 2019

在数据分析领域,最热门的莫过于Python和R语言,此前有一篇文章《别老扯什么Hadoop了,你的数据根本不够大》指出:只有在超过5TB数据量的规模下,Hadoop才是一个合理的技术选择。这次拿到近亿条日志数据,千万级数据已经是关系型数据库的查询分析瓶颈,之前使用过Hadoop对大量文本进行分类,这次决定采用Python来处理数据:

硬件环境

  • CPU:3.5 GHz Intel Core i7
  • 内存:32 GB HDDR 3 1600 MHz
  • 硬盘:3 TB Fusion Drive

数据分析工具

  • Python:2.7.6
  • Pandas:0.15.0
  • IPython notebook:2.0.0

源数据如下表所示:

  Table Size Desc
ServiceLogs 98,706,832 rows x 14 columns 8.77 GB 交易日志数据,每个交易会话可以有多条交易
ServiceCodes 286 rows × 8 columns 20 KB 交易分类的字典表

数据读取

启动IPython notebook,加载pylab环境:

ipython notebook --pylab=inline

Pandas提供了IO工具可以将大文件分块读取,测试了一下性能,完整加载9800万条数据也只需要263秒左右,还是相当不错了。

import pandas as pd
reader = pd.read_csv('data/servicelogs', iterator=True)
try:
  df = reader.get_chunk(100000000)
except StopIteration:
  print "Iteration is stopped."

  1百万条 1千万条 1亿条
ServiceLogs 1 s 17 s 263 s

使用不同分块大小来读取再调用pandas.concat连接DataFrame,chunkSize设置在1000万条左右速度优化比较明显。

loop = True
chunkSize = 100000
chunks = []
while loop:
  try:
    chunk = reader.get_chunk(chunkSize)
    chunks.append(chunk)
  except StopIteration:
    loop = False
    print "Iteration is stopped."
df = pd.concat(chunks, ignore_index=True)

下面是统计数据,Read Time是数据读取时间,Total Time是读取和Pandas进行concat操作的时间,根据数据总量来看,对5~50个DataFrame对象进行合并,性能表现比较好。

Chunk Size Read Time (s) Total Time (s) Performance100,000224.418173261.358521200,000232.076794256.6741541,000,000213.128481234.934142√√2,000,000208.410618230.006299√√√5,000,000209.460829230.939319√√√10,000,000207.082081228.135672√√√√20,000,000209.628596230.775713√√√50,000,000222.910643242.405967100,000,000263.574246263.574246

使用Python Pandas处理亿级数据的方法

如果使用Spark提供的Python Shell,同样编写Pandas加载数据,时间会短25秒左右,看来Spark对Python的内存使用都有优化。

数据清洗

Pandas提供了DataFrame.describe方法查看数据摘要,包括数据查看(默认共输出首尾60行数据)和行列统计。由于源数据通常包含一些空值甚至空列,会影响数据分析的时间和效率,在预览了数据摘要后,需要对这些无效数据进行处理。

首先调用DataFrame.isnull()方法查看数据表中哪些为空值,与它相反的方法是DataFrame.notnull(),Pandas会将表中所有数据进行null计算,以True/False作为结果进行填充,如下图所示:

使用Python Pandas处理亿级数据的方法

Pandas的非空计算速度很快,9800万数据也只需要28.7秒。得到初步信息之后,可以对表中空列进行移除操作。尝试了按列名依次计算获取非空列,和DataFrame.dropna()两种方式,时间分别为367.0秒和345.3秒,但检查时发现 dropna() 之后所有的行都没有了,查了Pandas手册,原来不加参数的情况下, dropna() 会移除所有包含空值的行。如果只想移除全部为空值的列,需要加上 axis 和 how 两个参数:

df.dropna(axis=1, how='all')

共移除了14列中的6列,时间也只消耗了85.9秒。

接下来是处理剩余行中的空值,经过测试,在DataFrame.replace()中使用空字符串,要比默认的空值NaN节省一些空间;但对整个CSV文件来说,空列只是多存了一个“,”,所以移除的9800万 x 6列也只省下了200M的空间。进一步的数据清洗还是在移除无用数据和合并上。

对数据列的丢弃,除无效值和需求规定之外,一些表自身的冗余列也需要在这个环节清理,比如说表中的流水号是某两个字段拼接、类型描述等,通过对这些数据的丢弃,新的数据文件大小为4.73GB,足足减少了4.04G!

数据处理

使用DataFrame.dtypes可以查看每列的数据类型,Pandas默认可以读出int和float64,其它的都处理为object,需要转换格式的一般为日期时间。DataFrame.astype()方法可对整个DataFrame或某一列进行数据格式转换,支持Python和NumPy的数据类型。

df['Name'] = df['Name'].astype(np.datetime64)

对数据聚合,我测试了 DataFrame.groupby 和 DataFrame.pivot_table 以及 pandas.merge ,groupby 9800万行 x 3列的时间为99秒,连接表为26秒,生成透视表的速度更快,仅需5秒。

df.groupby(['NO','TIME','SVID']).count() # 分组
fullData = pd.merge(df, trancodeData)[['NO','SVID','TIME','CLASS','TYPE']] # 连接
actions = fullData.pivot_table('SVID', columns='TYPE', aggfunc='count') # 透视表

根据透视表生成的交易/查询比例饼图:

使用Python Pandas处理亿级数据的方法

将日志时间加入透视表并输出每天的交易/查询比例图:

total_actions = fullData.pivot_table('SVID', index='TIME', columns='TYPE', aggfunc='count')
total_actions.plot(subplots=False, figsize=(18,6), kind='area')

使用Python Pandas处理亿级数据的方法

除此之外,Pandas提供的DataFrame查询统计功能速度表现也非常优秀,7秒以内就可以查询生成所有类型为交易的数据子表:

tranData = fullData[fullData['Type'] == 'Transaction']

该子表的大小为[10250666 rows x 5 columns]。在此已经完成了数据处理的一些基本场景。实验结果足以说明,在非“>5TB”数据的情况下,Python的表现已经能让擅长使用统计分析语言的数据分析师游刃有余。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
仅用500行Python代码实现一个英文解析器的教程
Apr 02 Python
使用PyInstaller将python转成可执行文件exe笔记
May 26 Python
python实现从pdf文件中提取文本,并自动翻译的方法
Nov 28 Python
python sklearn库实现简单逻辑回归的实例代码
Jul 01 Python
详解Python中的正斜杠与反斜杠
Aug 09 Python
python try except返回异常的信息字符串代码实例
Aug 15 Python
django项目用higcharts统计最近七天文章点击量
Aug 17 Python
python 协程中的迭代器,生成器原理及应用实例详解
Oct 28 Python
Python利用Scrapy框架爬取豆瓣电影示例
Jan 17 Python
使用Python打造一款间谍程序的流程分析
Feb 21 Python
使用Python发现隐藏的wifi
Mar 04 Python
CocosCreator ScrollView优化系列之分帧加载
Apr 14 Python
Python3批量生成带logo的二维码方法
Jun 24 #Python
解决python文件双击运行秒退的问题
Jun 24 #Python
对python中的控制条件、循环和跳出详解
Jun 24 #Python
django框架自定义模板标签(template tag)操作示例
Jun 24 #Python
解决Python内层for循环如何break出外层的循环的问题
Jun 24 #Python
Python 循环终止语句的三种方法小结
Jun 24 #Python
12个Python程序员面试必备问题与答案(小结)
Jun 24 #Python
You might like
DIY一个适配电脑声卡的动圈话筒放大器
2021/03/02 无线电
PHP Global定义全局变量使用说明
2013/08/15 PHP
CI框架AR数据库操作常用函数总结
2016/11/21 PHP
浅谈jQuery事件绑定原理
2015/01/02 Javascript
jQuery stop()用法实例详解
2016/07/28 Javascript
js实现随机抽选效果、随机抽选红色球效果
2017/01/13 Javascript
移动端手指放大缩小插件与js源码
2017/05/22 Javascript
vue中路由参数传递可能会遇到的坑
2017/12/07 Javascript
JavaScript循环遍历你会用哪些之小结篇
2018/09/28 Javascript
详解Vue.js自定义tipOnce指令用法实例
2018/12/19 Javascript
详解js常用分割取字符串的方法
2019/05/15 Javascript
Vue组件间通信 Vuex的用法解析
2019/08/05 Javascript
Vue的data、computed、watch源码浅谈
2020/04/04 Javascript
[15:57]教你分分钟做大人:斧王
2014/10/30 DOTA
[51:26]VP vs VG 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
使用python的chardet库获得文件编码并修改编码
2014/01/22 Python
python使用ctypes模块调用windowsapi获取系统版本示例
2014/04/17 Python
python正则表达式之作业计算器
2016/03/18 Python
Python中矩阵库Numpy基本操作详解
2017/11/21 Python
Python3转换html到pdf的不同解决方案
2019/03/11 Python
Python根据当前日期取去年同星期日期
2019/04/14 Python
python 实现返回一个列表中出现次数最多的元素方法
2019/06/11 Python
解决Python3 抓取微信账单信息问题
2019/07/19 Python
Django+uni-app实现数据通信中的请求跨域的示例代码
2019/10/12 Python
Pandas将列表(List)转换为数据框(Dataframe)
2020/04/24 Python
django正续或者倒序查库实例
2020/05/19 Python
python如何控制进程或者线程的个数
2020/10/16 Python
基于CSS3实现的漂亮Menu菜单效果代码
2015/09/10 HTML / CSS
《长城》教学反思
2014/02/14 职场文书
高中军训感言600字
2014/03/11 职场文书
观看《周恩来的四个昼夜》思想汇报
2014/09/12 职场文书
加强机关作风建设心得体会
2014/10/22 职场文书
离婚案件原告代理词
2015/05/23 职场文书
2015年小班保育员工作总结
2015/05/27 职场文书
在校大学生才艺比赛策划书怎么写?
2019/08/26 职场文书
德劲DE1108畅想
2021/04/22 无线电