利用pandas进行大文件计数处理的方法


Posted in Python onJuly 25, 2018

Pandas读取大文件

要处理的是由探测器读出的脉冲信号,一组数据为两列,一列为时间,一列为脉冲能量,数据量在千万级,为了有一个直接的认识,先使用Pandas读取一些

import pandas as pd
data = pd.read_table('filename.txt', iterator=True)
chunk = data.get_chunk(5)

而输出是这样的:

Out[4]: 
332.977889999979 -0.0164794921875 
0 332.97790 -0.022278 
1 332.97791 -0.026855 
2 332.97792 -0.030518 
3 332.97793 -0.045776 
4 332.97794 -0.032654

DataFram基本用法

这里,data只是个容器,pandas.io.parsers.TextFileReader。

使用astype可以实现dataframe字段类型转换

输出数据中,每组数据会多处一行,因为get_chunk返回的是pandas.core.frame.DataFrame格式, 而data在读取过程中并没有指定DataFrame的columns,因此在get_chunk过程中,默认将第一组数据作为columns。因此需要在读取过程中指定names即DataFrame的columns。

import pandas as pd
data = pd.read_table('filename.txt', iterator=True, names=['time', 'energe'])
chunk = data.get_chunk(5) 
data['energe'] = df['energe'].astype('int')

输出为

Out[6]:

index time energe
0 332.97789 -0.016479
1 332.97790 -0.022278
2 332.97791 -0.026855
3 332.97792 -0.030518
4 332.97793 -0.045776

DataFram存储和索引

这里讲一下DataFrame这个格式,与一般二维数据不同(二维列表等),DataFrame既有行索引又有列索引,因此在建立一个DataFrame数据是

DataFrame(data, columns=[‘year', ‘month', ‘day'], 
index=[‘one', ‘two', ‘three'])

year month day
0 2010 4 1
1 2011 5 2
2 2012 6 3
3 2013 7 5
4 2014 8 9

而pd.read_table中的names就是指定DataFrame的columns,而index自动设置。 而DataFrame的索引格式有很多

类型 说明 例子
obj[val] 选取单列或者一组列
obj.ix[val] 选取单个行或者一组行
obj.ix[:,val] 选取单个列或列子集
obj.ix[val1, val2] 同时选取行和列
reindex方法 将一个或多个轴匹配到新索引
xs方法 根据标签选取单行或单列,返回一个Series
icol,lrow方法 根据整数位置选取单列或单行,返回一个Series
get_value,set_value 根据行标签列标签选取单个值

exp: In[1]:data[:2]

Out[2]:

year month day
0 2010 4 1
1 2011 5 2

In[2]:data[data[‘month']>5]

Out[2]:

year month day
2 2012 6 3
4 2014 8 9

如果我们直接把data拿来比较的话,相当于data中所有的标量元素

In[3]:data[data<6]=0

Out[3]:

year month day
0 2010 0 0
1 2011 0 0
2 2012 6 0
3 2013 7 0
4 2014 8 9

Pandas运算

series = data.ix[0]
data - series

Out:

year month day
0 0 0 0
1 1 1 1
2 2 2 2
3 3 3 4
4 4 4 8

DataFrame与Series之间运算会将Series索引匹配到DataFrame的列,然后沿行一直向下广播

如果令series1 = data[‘year']

data.sub(series1,axis=0)

则每一列都减去该series1,axis为希望匹配的轴,=0行索引,即匹配列,=1列索引,则按行匹配。

DataFrame的一些函数方法

这个就有很多了,比如排序和排名;求和、平均数以及方差、协方差等数学方法;还有就是唯一值(类似于集合)、值计数和成员资格等方法。

当然还有一些更高级的属性,用的时候再看吧

数据处理

在得到数据样式后我们先一次性读取数据

start = time.time()
data = pd.read_table('Eu155_Na22_K40_MR_0CM_3Min.csv', names=['time', 'energe'])
end = time.time()
data.index
print("The time is %f s" % (end - start))
plus = data['energe']
plus[plus < 0] = 0
The time is 29.403917 s 
RangeIndex(start=0, stop=68319232, step=1)

对于一个2G大小,千万级的数据,这个读取速度还是挺快的。之前使用matlab load用时160多s,但是不知道这个是否把数据完全读取了。然后只抽取脉冲信号,将负值归0,因为会出现一定的电子噪声从而产生一定负值。

然后就需要定位脉冲信号中的能峰了,也就是findpeaks

这里用到了scipy.signal中的find_peaks_cwt,具体用法可以参见官方文档

peaks = signal.find_peaks_cwt(pluse, np.arange(1, 10)),它返回找到的peaks的位置,输入第一个为数据,第二个为窗函数,也就是在这个宽度的能窗内寻找峰,我是这样理解的。刚开始以为是数据的另一维坐标,结果找了半天没结果。不过事实上这个找的确定也挺慢的。

50w条的数据,找了足足7分钟,我这一个数据3000w条不得找半个多小时,而各种数据有好几十,恩。。这样是不行的,于是想到了并行的方法。这个下篇文章会讲到,也就是把数据按照chunksize读取,然后同时交给(map)几个进程同时寻峰,寻完后返回(reduce)一起计数,计数的同时,子进程再此寻峰。

在处理的时候碰到我自己的破 笔记本由于内存原因不能load这个数据,并且想着每次copy这么大数据好麻烦,就把一个整体数据文件分割成了几个部分,先对方法进行一定的实验,时间快,比较方便。

import pandas as pd


def split_file(filename, size):
 name = filename.split('.')[0]
 data = pd.read_table(filename, chunksize=size, names=['time', 'intension'])
 i = 1
 for piece in data:
 outname = name + str(i) + '.csv'
 piece.to_csv(outname, index=False, names = ['time', 'intension'])
 i += 1

def split_csvfile(filename, size):
 name = filename.split('.')[0]
 data = pd.read_csv(filename, chunksize=size, names=['time', 'intension'])
 i = 1
 for piece in data:
 outname = name + str(i) + '.csv'
 piece = piece['intension']
 piece.to_csv(outname, index=False)
 i += 1

额..使用并行寻峰通过map/reduce的思想来解决提升效率这个想法,很早就实现了,但是,由于效果不是特别理想,所以放那也就忘了,今天整理代码来看了下当时记的些笔记,然后竟然发现有个评论…..我唯一收到的评论竟然是“催稿”=。=。想一想还是把下面的工作记录下来,免得自己后来完全忘记了。

rom scipy import signal
import os
import time
import pandas as pd
import numpy as np
from multiprocessing import Pool
import matplotlib.pylab as plt
from functools import partial


def findpeak(pluse):
 pluse[pluse < 0.05] = 0
 print('Sub process %s.' % os.getpid())
 start = time.time()
 peaks = signal.find_peaks_cwt(pluse, np.arange(1, 10)) # 返回一个列表
 end = time.time()
 print("The time is %f s" % (end - start))
 pks = [pluse[x] for x in peaks]
 return pks


def histcnt(pks, edge=None, channel=None):
 cnt = plt.hist(pks, edge)
 res = pd.DataFrame(cnt[0], index=channel, columns=['cnt'])
 return res


if __name__ == '__main__':
 with Pool(processes=8) as p:
 start = time.time()
 print('Parent process %s.' % os.getpid())
 pluse = pd.read_csv('data/samples.csv', chunksize=50000, names=['time', 'energe'])
 channel = pd.read_csv('data/channels.txt', names=['value'])
 edges = channel * 2
 edges = pd.DataFrame({'value': [0]}).append(edges, ignore_index=True)
 specal = []
 for data in pluse:
 total = p.apply_async(findpeak, (data['energe'],),
   callback=partial(histcnt, edge=edges['value'], channel=channel['value']))
 specal.append(total)
 print('Waiting for all subprocesses done...')
 p.close()
 p.join()
 print('All subprocesses done.')
 spec = sum(specal)
 plt.figure()
 plt.plot(spec['cnt'])
 spec.to_csv('data/spec1.csv', header=False)
 print('every is OK')
 end = time.time()
 print("The time is %f s" % (end - start))

由于对对进程线程的编程不是很了解,其中走了很多弯路,尝试了很多方法也,这个是最终效果相对较好的。

首先,通过 pd.readtable以chunksize=50000分块读取,edges为hist过程中的下统计box。

然后,apply_async为非阻塞调用findpeak,然后将结果返回给回调函数histcnt,但是由于回调函数除了进程返回结果还有额外的参数,因此使用partial,对特定的参数赋予固定的值(edge和channel)并返回了一个全新的可调用对象,这个新的可调用对象仍然需要通过制定那些未被赋值的参数(findpeak返回的值)来调用。这个新的课调用对象将传递给partial()的固定参数结合起来,同一将所有参数传递给原始函数(histcnt)。(至于为啥不在histcnt中确定那两个参数,主要是为了避免一直打开文件。。当然,有更好的办法只是懒得思考=。=),还有个原因就是,apply_async返回的是一个对象,需要通过该对象的get方法才能获取值。。

对于 apply_async官方上是这样解释的

Apply_async((func[, args[, kwds[, callback[, error_callback]]]])),apply()方法的一个变体,返回一个结果对象

如果指定回调,那么它应该是一个可调用的接受一个参数。结果准备好回调时,除非调用失败,在这种情况下,应用error_callback代替。

如果error_callback被指定,那么它应该是一个可调用的接受一个参数。如果目标函数失败,那么error_callback叫做除了实例。

回调应立即完成以来,否则线程处理结果将被封锁。

不使用回调函数的版本如下,即先将所有子进程得到的数据都存入peaks列表中,然后所有进程完毕后在进行统计计数。

import pandas as pd
import time
import scipy.signal as signal
import numpy as np
from multiprocessing import Pool
import os
import matplotlib.pyplot as plt


def findpeak(pluse):
 pluse[pluse < 0] = 0
 pluse[pluse > 100] = 0
 print('Sub process %s.' % os.getpid())
 start = time.time()
 peaks = signal.find_peaks_cwt(pluse, np.arange(1, 10))
 end = time.time()
 print("The time is %f s" % (end - start))
 res = [pluse[x] for x in peaks]
 return res


if __name__ == '__main__':
 with Pool(processes=8) as p:
 start = time.time()
 print('Parent process %s.' % os.getpid())
 pluse = pd.read_csv('data/sample.csv', chunksize=200000, names=['time', 'energe'])
 pks = []
 for data in pluse:
 pks.append(p.apply_async(findpeak, (data['energe'],)))
 print('Waiting for all subprocesses done...')
 p.close()
 p.join()
 print('All subprocesses done.')
 peaks = []
 for i, ele in enumerate(pks):
 peaks.extend(ele.get())
 peaks = pd.DataFrame(peaks, columns=['energe'])
 peaks.to_csv('peaks.csv', index=False, header=False, chunksize=50000)
 channel = pd.read_csv('data/channels.txt', names=['value'])
 channel *= 2
 channel = pd.DataFrame({'value': [0]}).append(channel, ignore_index=True)
 plt.figure()
 spec = plt.hist(peaks['energe'], channel['value'])
 # out.plot.hist(bins=1024)
 # print(out)
 # cnt = peaks.value_counts(bins=1024)
 # cnt.to_csv('data/cnt.csv', index=False, header=False)
 print('every is OK')
 end = time.time()
 print("The time is %f s" % (end - start))

以上这篇利用pandas进行大文件计数处理的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
phpsir 开发 一个检测百度关键字网站排名的python 程序
Sep 17 Python
举例讲解Python程序与系统shell交互的方式
Apr 09 Python
python编程之requests在网络请求中添加cookies参数方法详解
Oct 25 Python
python通过socket实现多个连接并实现ssh功能详解
Nov 08 Python
python编程通过蒙特卡洛法计算定积分详解
Dec 13 Python
python opencv将表格图片按照表格框线分割和识别
Oct 30 Python
Win下PyInstaller 安装和使用教程
Dec 25 Python
pytorch 实现打印模型的参数值
Dec 30 Python
Iconfont(矢量图标)+iconmoon(图标svg互转)配合javascript实现社交分享系统
Apr 21 Python
Django中ORM找出内容不为空的数据实例
May 20 Python
详解使用Python写一个向数据库填充数据的小工具(推荐)
Sep 11 Python
python playwright之元素定位示例详解
Jul 23 Python
使用python验证代理ip是否可用的实现方法
Jul 25 #Python
Python+Pandas 获取数据库并加入DataFrame的实例
Jul 25 #Python
python requests 测试代理ip是否生效
Jul 25 #Python
Python使用pymysql从MySQL数据库中读出数据的方法
Jul 25 #Python
Python统计python文件中代码,注释及空白对应的行数示例【测试可用】
Jul 25 #Python
Pandas读取MySQL数据到DataFrame的方法
Jul 25 #Python
python中的常量和变量代码详解
Jul 25 #Python
You might like
php权重计算方法代码分享
2014/01/09 PHP
初识PHP中的Swoole
2016/04/05 PHP
php-fpm开启状态统计的方法详解
2017/06/23 PHP
ThinkPHP5&amp;5.1框架关联模型分页操作示例
2019/08/03 PHP
HTML TO JavaScript 转换
2006/06/26 Javascript
jquery复选框CHECKBOX全选、反选
2008/08/30 Javascript
关于jQuery参考实例 1.0 jQuery的哲学
2013/04/07 Javascript
Jquery uploadify图片上传插件无法上传的解决方法
2013/12/16 Javascript
基于jQuery实现鼠标点击导航菜单水波动画效果附源码下载
2016/01/06 Javascript
jQuery获取table行数并输出单元格内容的实现方法
2016/06/30 Javascript
jQuery操作cookie
2016/08/08 Javascript
angular+ionic 的app上拉加载更新数据实现方法
2017/01/16 Javascript
Web 开发中Ajax的Session 超时处理方法
2017/01/19 Javascript
VUE页面中加载外部HTML的示例代码
2017/09/20 Javascript
布同 Python中文问题解决方法(总结了多位前人经验,初学者必看)
2011/03/13 Python
Python 用Redis简单实现分布式爬虫的方法
2017/11/23 Python
python OpenCV学习笔记之绘制直方图的方法
2018/02/08 Python
python的staticmethod与classmethod实现实例代码
2018/02/11 Python
Python实现删除排序数组中重复项的两种方法示例
2019/01/31 Python
使用python搭建服务器并实现Android端与之通信的方法
2019/06/28 Python
python 字符串常用函数详解
2019/09/11 Python
使用TensorFlow搭建一个全连接神经网络教程
2020/02/06 Python
python字符串替换re.sub()实例解析
2020/02/09 Python
python实现跨excel sheet复制代码实例
2020/03/03 Python
python使用列表的最佳方案
2020/08/12 Python
Python爬虫Scrapy框架CrawlSpider原理及使用案例
2020/11/20 Python
aden + anais英国官网:美国婴儿贴身用品品牌
2019/09/08 全球购物
荷兰睡眠专家:Beter Bed
2020/11/23 全球购物
保险专业大专生求职信
2013/10/26 职场文书
建筑设计师岗位职责
2013/11/18 职场文书
自我介绍演讲稿
2014/01/15 职场文书
商业企业管理专业求职信
2014/07/10 职场文书
公务员中国梦演讲稿
2014/08/19 职场文书
领导班子四风表现材料
2014/08/23 职场文书
安全教育观后感
2015/06/17 职场文书
什么是css原子化,有什么用?
2022/04/24 HTML / CSS