Python利用多进程将大量数据放入有限内存的教程


Posted in Python onApril 01, 2015

简介

这是一篇有关如何将大量的数据放入有限的内存中的简略教程。

与客户工作时,有时会发现他们的数据库实际上只是一个csv或Excel文件仓库,你只能将就着用,经常需要在不更新他们的数据仓库的情况下完成工作。大部分情况下,如果将这些文件存储在一个简单的数据库框架中或许更好,但时间可能不允许。这种方法对时间、机器硬件和所处环境都有要求。

下面介绍一个很好的例子:假设有一堆表格(没有使用Neo4j、MongoDB或其他类型的数据库,仅仅使用csvs、tsvs等格式存储的表格),如果将所有表格组合在一起,得到的数据帧太大,无法放入内存。所以第一个想法是:将其拆分成不同的部分,逐个存储。这个方案看起来不错,但处理起来很慢。除非我们使用多核处理器。
目标

这里的目标是从所有职位中(大约1万个),找出相关的的职位。将这些职位与政府给的职位代码组合起来。接着将组合的结果与对应的州(行政单位)信息组合起来。然后用通过word2vec生成的属性信息在我们的客户的管道中增强已有的属性。

这个任务要求在短时间内完成,谁也不愿意等待。想象一下,这就像在不使用标准的关系型数据库的情况下进行多个表的连接。
数据

Python利用多进程将大量数据放入有限内存的教程

示例脚本

下面的是一个示例脚本,展示了如何使用multiprocessing来在有限的内存空间中加速操作过程。脚本的第一部分是和特定任务相关的,可以自由跳过。请着重关注第二部分,这里侧重的是multiprocessing引擎。

#import the necessary packages
import pandas as pd
import us
import numpy as np
from multiprocessing import Pool,cpu_count,Queue,Manager
 
# the data in one particular column was number in the form that horrible excel version
# of a number where '12000' is '12,000' with that beautiful useless comma in there.
# did I mention I excel bothers me?
# instead of converting the number right away, we only convert them when we need to
def median_maker(column):
  return np.median([int(x.replace(',','')) for x in column])
 
# dictionary_of_dataframes contains a dataframe with information for each title; e.g title is 'Data Scientist'
# related_title_score_df is the dataframe of information for the title; columns = ['title','score']
### where title is a similar_title and score is how closely the two are related, e.g. 'Data Analyst', 0.871
# code_title_df contains columns ['code','title']
# oes_data_df is a HUGE dataframe with all of the Bureau of Labor Statistics(BLS) data for a given time period (YAY FREE DATA, BOO BAD CENSUS DATA!)
 
def job_title_location_matcher(title,location):
  try:
    related_title_score_df = dictionary_of_dataframes[title]
    # we limit dataframe1 to only those related_titles that are above
    # a previously established threshold
    related_title_score_df = related_title_score_df[title_score_df['score']>80]
 
    #we merge the related titles with another table and its codes
    codes_relTitles_scores = pd.merge(code_title_df,related_title_score_df)
    codes_relTitles_scores = codes_relTitles_scores.drop_duplicates()
 
    # merge the two dataframes by the codes
    merged_df = pd.merge(codes_relTitles_scores, oes_data_df)
    #limit the BLS data to the state we want
    all_merged = merged_df[merged_df['area_title']==str(us.states.lookup(location).name)]
 
    #calculate some summary statistics for the time we want
    group_med_emp,group_mean,group_pct10,group_pct25,group_median,group_pct75,group_pct90 = all_merged[['tot_emp','a_mean','a_pct10','a_pct25','a_median','a_pct75','a_pct90']].apply(median_maker)
    row = [title,location,group_med_emp,group_mean,group_pct10,group_pct25, group_median, group_pct75, group_pct90]
    #convert it all to strings so we can combine them all when writing to file
    row_string = [str(x) for x in row]
    return row_string
  except:
    # if it doesnt work for a particular title/state just throw it out, there are enough to make this insignificant
    'do nothing'

这里发生了神奇的事情:

#runs the function and puts the answers in the queue
def worker(row, q):
    ans = job_title_location_matcher(row[0],row[1])
    q.put(ans)
 
# this writes to the file while there are still things that could be in the queue
# this allows for multiple processes to write to the same file without blocking eachother
def listener(q):
  f = open(filename,'wb')
  while 1:
    m = q.get()
    if m =='kill':
        break
    f.write(','.join(m) + 'n')
    f.flush()
  f.close()
 
def main():
  #load all your data, then throw out all unnecessary tables/columns
  filename = 'skill_TEST_POOL.txt'
 
  #sets up the necessary multiprocessing tasks
  manager = Manager()
  q = manager.Queue()
  pool = Pool(cpu_count() + 2)
  watcher = pool.map_async(listener,(q,))
 
  jobs = []
  #titles_states is a dataframe of millions of job titles and states they were found in
  for i in titles_states.iloc:
    job = pool.map_async(worker, (i, q))
    jobs.append(job)
 
  for job in jobs:
    job.get()
  q.put('kill')
  pool.close()
  pool.join()
 
if __name__ == "__main__":
  main()

由于每个数据帧的大小都不同(总共约有100Gb),所以将所有数据都放入内存是不可能的。通过将最终的数据帧逐行写入内存,但从来不在内存中存储完整的数据帧。我们可以完成所有的计算和组合任务。这里的“标准方法”是,我们可以仅仅在“job_title_location_matcher”的末尾编写一个“write_line”方法,但这样每次只会处理一个实例。根据我们需要处理的职位/州的数量,这大概需要2天的时间。而通过multiprocessing,只需2个小时。

虽然读者可能接触不到本教程处理的任务环境,但通过multiprocessing,可以突破许多计算机硬件的限制。本例的工作环境是c3.8xl ubuntu ec2,硬件为32核60Gb内存(虽然这个内存很大,但还是无法一次性放入所有数据)。这里的关键之处是我们在60Gb的内存的机器上有效的处理了约100Gb的数据,同时速度提升了约25倍。通过multiprocessing在多核机器上自动处理大规模的进程,可以有效提高机器的利用率。也许有些读者已经知道了这个方法,但对于其他人,可以通过multiprocessing能带来非常大的收益。顺便说一句,这部分是skill assets in the job-market这篇博文的延续。

Python 相关文章推荐
Python的Django框架中settings文件的部署建议
May 30 Python
python实现对excel进行数据剔除操作实例
Dec 07 Python
Python 循环语句之 while,for语句详解
Apr 23 Python
用Python爬取QQ音乐评论并制成词云图的实例
Aug 24 Python
Python元组 tuple的概念与基本操作详解【定义、创建、访问、计数、推导式等】
Oct 30 Python
tensorflow 固定部分参数训练,只训练部分参数的实例
Jan 20 Python
详解Python的三种拷贝方式
Feb 11 Python
Jupyter Notebook输出矢量图实例
Apr 14 Python
python能否java成为主流语言吗
Jun 22 Python
python实现人性化显示金额数字实例详解
Sep 25 Python
python爬虫利用代理池更换IP的方法步骤
Feb 21 Python
python迷宫问题深度优先遍历实例
Jun 20 Python
python连接远程ftp服务器并列出目录下文件的方法
Apr 01 #Python
10种检测Python程序运行时间、CPU和内存占用的方法
Apr 01 #Python
深入Python解释器理解Python中的字节码
Apr 01 #Python
Python中的defaultdict模块和namedtuple模块的简单入门指南
Apr 01 #Python
Python进行数据科学工作的简单入门教程
Apr 01 #Python
10个易被忽视但应掌握的Python基本用法
Apr 01 #Python
用Python制作检测Linux运行信息的工具的教程
Apr 01 #Python
You might like
什么是MVC,好东西啊
2007/05/03 PHP
PHP中生成UUID自定义函数分享
2015/06/10 PHP
Yii框架用户登录session丢失问题解决方法
2017/01/07 PHP
PHP常用函数之根据生日计算年龄功能示例
2019/10/21 PHP
Laravel 模型使用软删除-左连接查询-表起别名示例
2019/10/24 PHP
15 个 JavaScript Web UI 库
2010/05/19 Javascript
JavaScript学习笔记记录我的旅程
2012/05/23 Javascript
js动画效果制件让图片组成动画代码分享
2014/01/14 Javascript
extjs 时间范围选择自动判断的实现代码
2014/06/24 Javascript
JS长整型精度问题实例分析
2015/01/13 Javascript
详解Angular开发中的登陆与身份验证
2016/07/27 Javascript
Json对象和字符串互相转换json数据拼接和JSON使用方式详细介绍(小结)
2016/10/25 Javascript
基于react组件之间的参数传递(详解)
2017/09/05 Javascript
基于Vue中点击组件外关闭组件的实现方法
2018/03/06 Javascript
默认浏览器设置及vue自动打开页面的方法
2018/09/21 Javascript
详解VSCode配置启动Vue项目
2019/05/14 Javascript
Vue自定义全局弹窗组件操作
2020/08/11 Javascript
[48:02]Ti4循环赛第三日 VG vs Liquid和NEWBEE vs DK
2014/07/12 DOTA
[44:40]Serenity vs Pain 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
python处理Excel xlrd的简单使用
2017/09/12 Python
Python3导入自定义模块的三种方法详解
2018/04/13 Python
PyQt5 pyqt多线程操作入门
2018/05/05 Python
python实现图片压缩代码实例
2019/08/12 Python
python中导入 train_test_split提示错误的解决
2020/06/19 Python
WatchShop法国:英国排名第一的独立手表零售商
2020/02/17 全球购物
俄罗斯在线购买飞机票、火车票、巴士票网站:Tutu.ru
2020/03/16 全球购物
美国名牌手表折扣网站:Jomashop
2020/05/22 全球购物
金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)-> (一千零一拾一元整)输出
2015/05/29 面试题
合同专员岗位职责
2013/12/18 职场文书
建筑工程管理专业自荐信范文
2013/12/28 职场文书
《珍珠泉》教学反思
2014/02/20 职场文书
公司门卫岗位职责
2014/03/15 职场文书
初中差生评语
2014/12/29 职场文书
2015年法务工作总结范文
2015/05/23 职场文书
开业典礼致辞
2015/07/29 职场文书
Python万能模板案例之matplotlib绘制甘特图
2022/04/13 Python