pandas apply 函数 实现多进程的示例讲解


Posted in Python onApril 20, 2018

前言: 在进行数据处理的时候,我们经常会用到 pandas 。但是 pandas 本身好像并没有提供多进程的机制。本文将介绍如何来自己实现 pandas (apply 函数)的多进程执行。其中,我们主要借助 joblib 库,这个库为python 提供了一个非常简洁方便的多进程实现方法。

所以,本文将按照下面的安排展开,前面可能比较??拢?糁皇窍胫?涝趺从每芍苯涌吹谌?糠郑?/strong>

- 首先简单介绍 pandas 中的分组聚合操作 groupby。

- 然后简单介绍 joblib 的使用方法。

- 最后,通过一个去停用词的实验详细介绍如何实现 pandas 中 apply 函数多进程执行。

注意:本文说的都是多进程而不是多线程。

1. DataFrame.groupby 分组聚合操作

# groupby 操作
df1 = pd.DataFrame({'a':[1,2,1,2,1,2], 'b':[3,3,3,4,4,4], 'data':[12,13,11,8,10,3]})
df1

pandas apply 函数 实现多进程的示例讲解

按照某列分组

grouped = df1.groupby('b')
# 按照 'b' 这列分组了,name 为 'b' 的 key 值,group 为对应的df_group
for name, group in grouped:
 print name, '->'
 print group
3 ->
 a b data
0 1 3 12
1 2 3 13
2 1 3 11
4 ->
 a b data
3 2 4  8
4 1 4 10
5 2 4  3

按照多列分组

grouped = df1.groupby(['a','b'])
# 按照 'b' 这列分组了,name 为 'b' 的 key 值,group 为对应的df_group
for name, group in grouped:
 print name, '->'
 print group
(1, 3) ->
 a b data
0 1 3 12
2 1 3 11
(1, 4) ->
 a b data
4 1 4 10
(2, 3) ->
 a b data
1 2 3 13
(2, 4) ->
 a b data
3 2 4  8
5 2 4  3

若 df.index 为[1,2,3…]这样一个 list, 那么按照 df.index分组,其实就是每组就是一行,在后面去停用词实验中,我们就用这个方法把 df_all 处理成每行为一个元素的 list, 再用多进程处理这个 list。

grouped = df1.groupby(df1.index)
# 按照 index 分组,其实每行就是一个组了
print len(grouped), type(grouped)
for name, group in grouped:
 print name, '->'
 print group
6 <class 'pandas.core.groupby.DataFrameGroupBy'>
0 ->
 a b data
0 1 3 12
1 ->
 a b data
1 2 3 13
2 ->
 a b data
2 1 3 11
3 ->
 a b data
3 2 4  8
4 ->
 a b data
4 1 4 10
5 ->
 a b data
5 2 4  3

2. joblib 用法

refer: https://pypi.python.org/pypi/joblib

# 1. Embarrassingly parallel helper: to make it easy to write readable parallel code and debug it quickly:
from joblib import Parallel, delayed
from math import sqrt

处理小任务的时候,多进程并没有体现出优势。

%time result1 = Parallel(n_jobs=1)(delayed(sqrt)(i**2) for i in range(10000))
%time result2 = Parallel(n_jobs=8)(delayed(sqrt)(i**2) for i in range(10000))
CPU times: user 316 ms, sys: 0 ns, total: 316 ms
Wall time: 309 ms
CPU times: user 692 ms, sys: 384 ms, total: 1.08 s
Wall time: 1.03 s

当需要处理大量数据的时候,并行处理就体现出了它的优势

%time result = Parallel(n_jobs=1)(delayed(sqrt)(i**2) for i in range(1000000))
CPU times: user 3min 43s, sys: 5.66 s, total: 3min 49s
Wall time: 3min 33s
%time result = Parallel(n_jobs=8)(delayed(sqrt)(i**2) for i in range(1000000))
CPU times: user 50.9 s, sys: 12.6 s, total: 1min 3s
Wall time: 52 s

3. apply 函数的多进程执行(去停用词)

多进程的实现主要参考了 stack overflow 的解答: Parallelize apply after pandas groupby

pandas apply 函数 实现多进程的示例讲解

上图中,我们要把 AbstractText 去停用词, 处理成 AbstractText1 那样。首先,导入停用词表。

# 读入所有停用词
with open('stopwords.txt', 'rb') as inp:
 lines = inp.read()
stopwords = re.findall('"(.*?)"', lines)
print len(stopwords)
print stopwords[:10]
692
['a', "a's", 'able', 'about', 'above', 'according', 'accordingly', 'across', 'actually', 'after']
# 对 AbstractText 去停用词
# 方法一:暴力法,对每个词进行判断
def remove_stopwords1(text):
 words = text.split(' ')
 new_words = list()
 for word in words:
  if word not in stopwords:
   new_words.append(word)
 return new_words
# 方法二:先构建停用词的映射
for word in stopwords:
 if word in words_count.index:
  words_count[word] = -1
def remove_stopwords2(text):
 words = text.split(' ')
 new_words = list()
 for word in words:
  if words_count[word] != -1:
   new_words.append(word)
 return new_words
%time df_all['AbstractText1'] = df_all['AbstractText'].apply(remove_stopwords1)
%time df_all['AbstractText2'] = df_all['AbstractText'].apply(remove_stopwords2)
CPU times: user 8min 56s, sys: 2.72 s, total: 8min 59s
Wall time: 8min 48s
CPU times: user 1min 2s, sys: 4.12 s, total: 1min 6s
Wall time: 1min 2s

上面我尝试了两种不同的方法来去停用词:

方法一中使用了比较粗暴的方法:首先用一个 list 存储所有的 stopwords,然后对于每一个 text 中的每一个 word,我们判断它是否出现在 stopwords 的list中(复杂度 O(n)O(n) ), 若为 stopword 则去掉。

方法二中我用 一个Series(words_count) 对所有的词进行映射,如果该词为 stopword, 则把它的值修改为 -1。这样,对于 text 中的每个词 ww, 我们只需要判断它的值是否为 -1 即可判定是否为 stopword (复杂度 O(1)O(1))。

所以,在这两个方法中,我们都是采用单进程来执行,方法二的速度(1min 2s)明显高于方法一(8min 48s)。

from joblib import Parallel, delayed
import multiprocessing
# 方法三:对方法一使用多进程
def tmp_func(df):
 df['AbstractText3'] = df['AbstractText'].apply(remove_stopwords1)
 return df
def apply_parallel(df_grouped, func):
 """利用 Parallel 和 delayed 函数实现并行运算"""
 results = Parallel(n_jobs=-1)(delayed(func)(group) for name, group in df_grouped)
 return pd.concat(results)
if __name__ == '__main__':
 time0 = time.time()
 df_grouped = df_all.groupby(df_all.index)
 df_all =applyParallel(df_grouped, tmp_func)
 print 'time costed {0:.2f}'.format(time.time() - time0)
time costed 150.81
# 方法四:对方法二使用多进程
def tmp_func(df):
 df['AbstractText3'] = df['AbstractText'].apply(remove_stopwords2)
 return df
def apply_parallel(df_grouped, func):
 """利用 Parallel 和 delayed 函数实现并行运算"""
 results = Parallel(n_jobs=-1)(delayed(func)(group) for name, group in df_grouped)
 return pd.concat(results)
if __name__ == '__main__':
 time0 = time.time()
 df_grouped = df_all.groupby(df_all.index)
 df_all =applyParallel(df_grouped, tmp_func)
 print 'time costed {0:.2f}'.format(time.time() - time0)
time costed 123.80

上面方法三和方法四分别对应于前面方法一和方法二,但是都是用了多进程操作。结果是方法一使用多进程以后,速度一下子提高了好几倍,但是方法二的多进程速度不升反降。这是不是有问题?的确,但是首先可以肯定,我们的代码没有问题。下图显示了我用 top 命令看到各个方法的进程执行情况。可以看出,在方法三和方法四中,的的确确是 12 个CPU核都跑起来了。只是在方法四中,每个核占用的比例都是比较低的。

pandas apply 函数 实现多进程的示例讲解

fig1. 单进程 cpu 使用情况

pandas apply 函数 实现多进程的示例讲解

fig2. 方法三 cpu 使用情况

pandas apply 函数 实现多进程的示例讲解

fig3. 方法四 cpu 使用情况

一个直观的解释就是,当我们开启多进程的时候,进程开启和最后结果合并,进程结束,这些操作都是要消耗时间的。如果我们执行的任务比较小,那么进程开启等操作所消耗的时间可能就要比执行任务本身消耗的时间还多。这样就会出现多进程的方法四比单进程的方法二耗时更多的情况了。

所以总结来说,在处理小任务的时候没有必要开启多进程。借助joblib (Parallel, delayed 两个函数) ,我们能够很方便地实现 python 多进程。

以上这篇pandas apply 函数 实现多进程的示例讲解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
在PyCharm中批量查找及替换的方法
Jan 20 Python
python selenium 弹出框处理的实现
Feb 26 Python
python实现爬山算法的思路详解
Apr 09 Python
详解Python中的内建函数,可迭代对象,迭代器
Apr 29 Python
python使用 request 发送表单数据操作示例
Sep 25 Python
基于python3抓取pinpoint应用信息入库
Jan 08 Python
解决python -m pip install --upgrade pip 升级不成功问题
Mar 05 Python
Python 实现使用空值进行赋值 None
Mar 12 Python
Django-rest-framework中过滤器的定制实例
Apr 01 Python
基于Python词云分析政府工作报告关键词
Jun 02 Python
Python数据清洗工具之Numpy的基本操作
Apr 22 Python
Django利用AJAX技术实现博文实时搜索
May 06 Python
python3+PyQt5图形项的自定义和交互 python3实现page Designer应用程序
Jul 20 #Python
Python查找两个有序列表中位数的方法【基于归并算法】
Apr 20 #Python
pandas 使用apply同时处理两列数据的方法
Apr 20 #Python
Python之pandas读写文件乱码的解决方法
Apr 20 #Python
python3+PyQt5实现自定义窗口部件Counters
Apr 20 #Python
Python cookbook(字符串与文本)在字符串的开头或结尾处进行文本匹配操作
Apr 20 #Python
python3+PyQt5实现支持多线程的页面索引器应用程序
Apr 20 #Python
You might like
关于我转生变成史莱姆这档事:第二季PV上线,萌王2021年回归
2020/05/06 日漫
PHP 网页过期时间的控制代码
2009/06/29 PHP
克隆一个新项目的快捷方式
2013/04/10 PHP
js控制frameSet示例
2013/09/10 Javascript
点击A元素触发B元素的事件在IE8下会识别成A元素
2014/09/04 Javascript
jquery向上向下取整适合分页查询
2014/09/06 Javascript
jQuery中animate用法实例分析
2015/03/09 Javascript
jQuery实现精美的多级下拉菜单特效
2015/03/14 Javascript
基于jquery实现智能提示控件intellSeach.js
2016/03/17 Javascript
分享10个优化代码的CSS和JavaScript工具
2016/05/11 Javascript
关于JS变量和作用域详解
2016/07/28 Javascript
AngularJS 执行流程详细介绍
2016/08/18 Javascript
video.js使用改变ui过程
2017/03/05 Javascript
Bootstrap 响应式实用工具实例详解
2017/03/29 Javascript
layui前段框架日期控件使用方法详解
2017/05/19 Javascript
一个Vue视频媒体多段裁剪组件的实现示例
2018/08/09 Javascript
解决angularJS中input标签的ng-change事件无效问题
2018/09/13 Javascript
Vue高版本中一些新特性的使用详解
2018/09/25 Javascript
vue配置文件实现代理v2版本的方法
2019/06/21 Javascript
小程序和web画三角形实现解析
2019/09/02 Javascript
layui 点击重置按钮, select 并没有被重置的解决方法
2019/09/03 Javascript
通过实例了解Nodejs模块系统及require机制
2020/07/16 NodeJs
[01:22:19]EG vs TNC Supermajor小组赛B组败者组第一轮 BO3 第二场 6.2
2018/06/03 DOTA
在windows下快速搭建web.py开发框架方法
2016/04/22 Python
Python3.6笔记之将程序运行结果输出到文件的方法
2018/04/22 Python
Pycharm 文件更改目录后,执行路径未更新的解决方法
2019/07/19 Python
python plotly绘制直方图实例详解
2019/07/22 Python
Django+Uwsgi+Nginx如何实现生产环境部署
2020/07/31 Python
使用Python绘制台风轨迹图的示例代码
2020/09/21 Python
Skip Hop官网:好莱坞宝宝挚爱品牌
2018/06/17 全球购物
文员岗位职责范本
2014/03/08 职场文书
给学校的建议书
2014/03/12 职场文书
二年级班级文化建设方案
2014/05/10 职场文书
初中生物教学随笔
2015/08/15 职场文书
优秀家长事迹材料(2016推荐版)
2016/02/29 职场文书
详解Laravel制作API接口
2021/05/31 PHP