超级干货:Python优化之使用pandas读取千万级数据

环境:Linux-cenos5

processor : 31

model : 62

model name : Intel(R) Xeon(R) CPU E5-2640 v2 @ 2.00GHz

cpu MHz : 2000.066

cache size : 20480 KB

memory : 125G

在如上所述的单机环境中,使用一些优化可以使基于pandas数据格式的模型训练数据容量由600W增长为至少2000W,训练时间减少为1/5。具体方案如下:

数据读取优化

数据量4200W行,193列,每列存储为string类型的单精度浮点数,文件表由csv格式存储,总大小16GB+。通过如下语句读取到dataframe中去:

1

2

df_train = pd.read_csv(path,header=None,sep=',',nrows=40000000,error_bad_lines=False,delimiter="\t",lineterminator="\n",keep_default_na=True)

  经过测试,当nrows读取行数超过800W条时,df_train占内存超过80G,在后续的步骤中涉及到切片和数据集复制时会直接崩溃,超过1200W条时会直接无法读取。首先考虑优化读取方式:

1

2

3

4

5

6

7

8

9

10

na_vals = ["\\N"," ","","NULL"]

df_tmp = []

df_train = pd.DataFrame(index=["0"],dtype=np.float32)

count = 0

for chunk in pd.read_csv(path,header=None,sep=',',chunksize=200000,nrows=10000000,error_bad_lines=False,delimiter="\t",lineterminator="\n",keep_default_na=True, na_values=na_vals):

    df_tmp.append(chunk[1:])

    del chunk

    print("the chunk " + str(count) + " has been stored...")

    print("the mem-cost is now: "str(sys.getsizeof(df_tmp)/(1) ), "MB \n")

可以分为以下几个点解释

  • 使用na_values进行读取时的空值替换,代替了读取全部数据后的空值replace方式替换,减少了后续的处理时间
  • 使用chunksize进行数据读取,read_csv()方法中有一个参数chunksize可以指定一个CHUNKSIZE分块大小来读取文件。与直接使用DF进行遍历不同的是,此时它是一个TextFileReader类型的对象。
  1. 通过循环每次读取分块数据,再通过list拼接起来。

为什么不直接用concat进行迭代拼接?

因为concat只能使用值语义赋值,每次concat时都会先创建一个临时副本,再赋值给对应变量,这个过程中当数据量很大时,内存占用在赋值完成,删除原有dataframe前会造成极高的内存占用峰值。而python的list可以进行连续内存块的直接追加,不会产生额外的内存开销。

     2. 每次读取完一个chunk,都进行删除,释放对应内存。

数据转换优化

经过读取优化后,脚本最多可读取超过2000W的数据量,是之前读取数据量的三倍以上。但是此时读取完成后,在后续的处理中仍然会产生内存报错,首先报错的就是

df_X = pd.DataFrame(data=df_tmp, dtype=np.float)

内存报错原因:

当我们将读取的数据list经由pandas的构造函数进行类型转换时,会产生两个超大的dataframe/list一个是等号右边的临时表,一个是df_tmp本身,此时内存超过限制,程序崩溃。

经过分析采用如下方案可避免此部分报错

1

2

3

4

5

6

7

8

idx = 0

for in  range(len(df_tmp)):

    tmp = pd.DataFrame(data=df_tmp[idx], dtype=np.float)

    df_train = pd.concat([df_train,tmp], ignore_index=True)

    del df_tmp[idx],tmp

    print(i)

    print("the remaining chunk is: ", count)

    print("the frame size is: ", df_train.memory_usage().sum() / (1024 ** 2), "MB")    count -= 1

同样通过循环,每次只处理df_tmp这个存储了所有数据的临时list中的一个chunk,并在数据转换期间进行迭代拼接,每次增量更新df_train主表。在更新完成后立即释放该list中对应的内存。经过优化,此部分内存占用减半

数据类型优化

pandas中的许多数据类型具有多个子类型,它们可以使用较少的字节去表示不同数据,比如,float型就有float16、float32和float64这些子类型。这些类型名称的数字部分表明了这种类型使用了多少比特来表示数据,比如刚才列出的子类型分别使用了2、4、8个字节。下面这张表列出了pandas中常用类型的子类型:

一个int8类型的数据使用1个字节(8位比特)存储一个值,可以表示256(2^8)个二进制数值。这意味着我们可以用这种子类型去表示从-128到127(包括0)的数值。原始数据表基本都是由浮点数组成,因此可以考虑使用数据类型进行优化。

1

2

3

4

5

6

tmp0 = pd.DataFrame(data=df_tmp[idx])

tmp1 = pd.DataFrame(data=df_tmp[idx], dtype=object)

tmp2 = pd.DataFrame(data=df_tmp[idx], dtype=np.float)

tmp3 = pd.DataFrame(data=df_tmp[idx], dtype=np.float32)

# print("the remaining chunk is: ", count)

print("the frame size is: ", df_train.memory_usage().sum() / (1024 ** 2), "MB")

数据量为2W的情况下,pandas内存占用情况如下(默认类型为str)

一开始的代码中没有进行类型的转换,因此默认根据csv的格式进行初始化,所以Dataframe的数据类型全都是str,在读取之后的存储开销非常大,16G的csv读取进来后直接变成120G。使用数据类型优化后,结合之前的分块迭代读取,2000W的数据(8G)读取由60G的内存占用减少为不到15G,且省去了后续直接的类型转换。

小技巧

在每次使用完某个对象后,如果其在后续的建模过程中没有别的用处,可以手动删除,或者删除变量引用,触发GC机在读入数据集的时候指定列的最优数据类型。pandas.read_csv()函数有一些参数可以做到这一点。dtype参数接受一个 以列名(string型)为键字典、以Numpy类型对象为值的字典

1

2

3

4

dict = {x:np.float16 for in col}

df_train = pd.read_csv(path,header=None,sep=',',error_bad_lines=False,delimiter="\t",lineterminator="\n",

                       keep_default_na=True, converters=dict, na_vals=na_vals)

  可以考虑使用开源的pandas分布式机器学习库dask,在单机环境下运行即可

内存优化——使用pandas读取千万级数据相关推荐

  1. php超大树形分页,PHP+MySql千万级数据limit分页优化方案

    PHP+MySql千万级数据limit分页优化方案 1年前 阅读 2750 评论 0 喜欢 0 ### 原因 徒弟突然有个需求,就是他发现limit分页,页数越大之后,mysql的消耗越大,查询时间越 ...

  2. Pandas读取和将数据存储到多个sheet的excel以及read_excel函数常用参数详解

    Pandas读取和将数据存储到多个sheet的excel以及read_excel函数常用参数详解 Excel数据显示: read_excel函数常用参数详解 1.io 读取路径 个人比较喜欢第一种(r ...

  3. 排序千万级数据_MySQL 对于千万级的大表要怎么优化?我写了6000字的深度解读...

    千万级大表如何优化,这是一个很有技术含量的问题,通常我们的直觉思维都会跳转到拆分或者数据分区,在此我想做一些补充和梳理,想和大家做一些这方面的经验总结,也欢迎大家提出建议. 从一开始脑海里开始也是火光 ...

  4. 单表千万级数据 count() 统计优化

    1. 创建一张测试表: DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` bigint(20) PRIMARY key not null ...

  5. 分页查询千万级数据慢

    mysql查询千万级数据越来越慢优化: 1.分表:(固定某个表存多少数量的数据:例如:一张表存100w的数据量); 2.优化sql和建立适合的索引(复合索引); 3.使用redis缓存.(redis存 ...

  6. 如何设计千万级数据的java对账系统之一

    本篇文章主要聊聊如何设计千万级别的对账系统.其他一些业务问题可以参看对账清分设计总概览. 目前系统运行的对账总情况:对账日交易量两千万,交易金额50亿,对账时间5分钟以内 本篇文章分两个模块 第一个模 ...

  7. 手把手教你用Pandas读取所有主流数据存储

    导读:从常见的Excel和CSV到JSON及各种数据库,Pandas几乎支持市面上所有的主流数据存储形式. 作者:李庆辉 来源:大数据DT(ID:hzdashuju) Pandas提供了一组顶层的I/ ...

  8. 【python 处理亿级数据】使用 Pandas 处理亿级数据

    此前有一篇文章<别老扯什么Hadoop了,你的数据根本不够大>指出:只有在超过5TB数据量的规模下,Hadoop才是一个合理的技术选择.事实确实如此,在数据分析领域,那么如何处理亿级数据呢 ...

  9. MySQL limit 优化,百万至千万级快速分页:复合索引

    2019独角兽企业重金招聘Python工程师标准>>> MySQL 性能到底能有多高?用了php半年多,真正如此深入的去思考这个问题还是从前天开始.有过痛苦有过绝望,到现在充满信心! ...

  10. 手把手教你使用Pandas读取结构化数据

    导读:Pandas是一个基于Numpy库开发的更高级的结构化数据分析工具,提供了Series.DataFrame.Panel等数据结构,可以很方便地对序列.截面数据(二维表).面板数据进行处理. 作者 ...

最新文章

  1. 终于有人把Python讲清楚了!
  2. 马斯克的火箭,这次没!爆!炸!
  3. 双系统 win10 时间不对
  4. Linux编程下open()函数的用法
  5. 120. 三角形最小路径和
  6. Linux下各文件夹的含义和用途
  7. python ghost.py使用笔记
  8. LaTeX入门学习(6)(字体)
  9. android虚拟摇杆
  10. ubuntu上安装 ibus Google拼音输入法解决中文输入问题
  11. matlab绘制不同线性的直方图,matlab绘制直方图
  12. Python学习笔记-基础篇
  13. 浅析软文标题写作的三个问题
  14. 对OMAP-L138的PSC模块的理解
  15. Qt之获取屏幕分辨率
  16. 网站页面篡改及挂马的应急处置
  17. 三星性能测试软件,13款软件压力测试 Galaxy S4性能体验
  18. 装X神器,让你的grafana看板变得炫酷起来
  19. 阿里云 vs Azure-安全
  20. SEO搜狗批量查询收录工具

热门文章

  1. 如何正确地将Blender模型导入进Unity3D
  2. 夏普红外测距模块使用笔记
  3. 机器人动力学与控制_快速搭建“机器人动力学-参数辨识-轨迹规划-运动控制”的完整框架...
  4. excel连接64位oracle数据库,excel表格oracle数据库-excel怎样连接oracle数据库(白痴级提问)...
  5. 蘑菇丁周记范文计算机销售40篇,毕业生实习周记及销售实习周记范文 毕业生蘑菇钉周记范文(最新)...
  6. 分析EOF究竟是什么
  7. SORPAS-焊接仿真模拟软件
  8. 惠普win7驱动_win7怎么样打开无线网卡开关
  9. hourstracker 考勤表软件下载
  10. 推荐一款PDF阅读工具Apabi Reader