最近关于毕业设计遇到了第一个小难题,那就是读取一个将近1G的文件,并对其进行数据预处理工作。
意图是将数据打散,对于每个mac地址对其分配对应的时间戳和地点id(第二列)
数据集长这样:
2017/8/28 23:37:00,14,84742aa602e4
2017/8/29 04:38:00,13,000000000000
2017/8/29 04:46:00,13,000000000000
2017/8/29 04:47:00,13,000000000000
2017/8/29 05:16:00,13,84742ab11871
2017/8/29 05:17:00,13,84742ab11871
2017/8/29 05:18:00,13,b0e235c0398a,84742ab11871
2017/8/29 05:19:00,13,b0e235c0398a,84742ab11871
2017/8/29 05:20:00,13,b0e235c0398a,84742ab11871
2017/8/29 05:21:00,13,b0e235c0398a,84742ab11871
2017/8/29 05:22:00,13,b0e235c0398a,84742ab11871
2017/8/29 05:23:00,13,b0e235c0398a,84742ab11871
2017/8/29 05:24:00,13,b0e235c0398a,84742ab11871
2017/8/29 05:25:00,13,b0e235c0398a,84742ab11871
2017/8/29 05:26:00,13,b0e235c0398a
2017/8/29 05:27:00,13,b0e235c0398a
2017/8/29 06:53:00,18,84742aac34d7
2017/8/29 06:54:00,18,84742aac34d7
2017/8/29 06:55:00,18,84742aac34d7
2017/8/29 07:10:00,13,84742ab11871
2017/8/29 07:11:00,12,742344af2efd
2017/8/29 07:11:00,13,84742ab11871
2017/8/29 07:12:00,12,742344af2efd
2017/8/29 07:12:00,13,84742ab11871
2017/8/29 07:12:00,18,84742aac34f3
2017/8/29 07:13:00,12,742344af2efd,acc1eef136c1
2017/8/29 07:13:00,13,84742ab11871
2017/8/29 07:13:00,18,000000000000,84742aac34f3
2017/8/29 07:14:00,12,a4717460508e,742344af2efd,acc1eef136c1
2017/8/29 07:14:00,13,84742ab11871
2017/8/29 07:14:00,18,84742aac34f3,000000000000
2017/8/29 07:15:00,12,a4717460508e,742344af2efd,a8c83abd75f6,acc1eef136c1
2017/8/29 07:15:00,13,84742ab11871
2017/8/29 07:15:00,18,000000000000,84742aac34f3
2017/8/29 07:16:00,12,a4717460508e,742344af2efd,a8c83abd75f6,acc1eef136c1
2017/8/29 07:16:00,13,84742ab11871
2017/8/29 07:16:00,18,84742aac34f3,000000000000
2017/8/29 07:17:00,12,a4717460508e,742344af2efd,a8c83abd75f6,acc1eef136c1
2017/8/29 07:17:00,13,84742ab11871
2017/8/29 07:17:00,18,000000000000,84742aac34f3
2017/8/29 07:18:00,12,a4717460508e,acc1eef136c1,a8c83abd75f6
2017/8/29 07:18:00,13,84742ab11871
2017/8/29 07:18:00,18,84742aac34f3,000000000000
2017/8/29 07:19:00,12,a4717460508e,acc1eef136c1,a8c83abd75f6
2017/8/29 07:19:00,18,84742aac34f3,000000000000
......
现在准备对以上数据进行预处理,规整后的数据集:
2017/8/28 23:37:00,14,84742aa602e4
2017/8/28 23:38:00,14,84742aa602e4
2017/8/28 23:39:00,14,84742aa602e4
2017/8/28 23:40:00,14,84742aa602e4
2017/8/28 23:41:00,14,84742aa602e4
2017/8/28 23:42:00,14,84742aa602e4
2017/8/28 23:43:00,14,84742aa602e4
2017/8/28 23:44:00,14,84742aa602e4
2017/8/29 04:38:00,13,000000000000
2017/8/29 04:39:00,13,000000000000
2017/8/29 04:40:00,13,000000000000
2017/8/29 04:41:00,13,000000000000
2017/8/29 04:42:00,13,000000000000
2017/8/29 04:43:00,13,000000000000
2017/8/29 04:44:00,13,000000000000
2017/8/29 04:45:00,13,000000000000
2017/8/29 04:46:00,13,000000000000
2017/8/29 04:47:00,13,000000000000
2017/8/29 05:16:00,13,84742ab11871
2017/8/29 05:17:00,13,84742ab11871
2017/8/29 05:18:00,13,b0e235c0398a
2017/8/29 05:18:00,13,84742ab11871
2017/8/29 05:19:00,13,b0e235c0398a
2017/8/29 05:19:00,13,84742ab11871
2017/8/29 05:20:00,13,b0e235c0398a
2017/8/29 05:20:00,13,84742ab11871
2017/8/29 05:21:00,13,b0e235c0398a
2017/8/29 05:21:00,13,84742ab11871
2017/8/29 05:22:00,13,b0e235c0398a
2017/8/29 05:22:00,13,84742ab11871
2017/8/29 05:23:00,13,b0e235c0398a
2017/8/29 05:23:00,13,84742ab11871
2017/8/29 05:24:00,13,b0e235c0398a
2017/8/29 05:24:00,13,84742ab11871
2017/8/29 05:25:00,13,b0e235c0398a
2017/8/29 05:25:00,13,84742ab11871
2017/8/29 05:26:00,13,b0e235c0398a
2017/8/29 05:27:00,13,b0e235c0398a
2017/8/29 06:53:00,18,84742aac34d7
2017/8/29 06:54:00,18,84742aac34d7
之所以要这样处理源数据,是因为规整后的数据易于group,方便统计学操作,充分挖掘每个mac地址的数据信息。
以下列出三种文件处理的python代码,都是力求减少系统内存,其中以第三种方式处理大文件最为有效。
代码1:
理论上来说,总体上file.readlines()可以(取决于实现)不慢于你自己手动的一次次调用file.readline(),因为前者的循环在C语言层面,而你的循环是在Python语言层面。但是在内存占用上前者可能是后者的好几十百倍,因为前者会一次性把所有数据读取到内存中,而后者只每次读取一行。更好的写法是:
with open('filename') as file:
for line in file:
do_things(line)
# -*- coding: UTF-8 -*-
import csv
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
# csv_reader = csv.reader(open('./macdata/origin_info.csv'))
new_line =[]
with open('./macdata/origin_info.csv') as file:
for line in file:
# print line.split(',')[0]
# print len(line)
# print len(line.split(','))
line = line.split(',')
line[2] = line[2].strip('\n')
if len(line) ==0:
continue
if len(line)==3:
new_line.append(line)
if len(line) >3:
for i in xrange(2,len(line)):
new_line.append([line[0], line[1] , line[i].strip('\n')])
file=open('./macdata/normal_origin_info.txt','w')
file.write(str(new_line))
file.close()
# df = DataFrame(new_line)
# print df
代码2
使用python linecache
在python中,有个好用的模块linecache,该模块允许从任何文件里得到任何的行,并且使用缓存进行优化,常见的情况是从单个文件读取多行。
linecache.getlines(filename) 从名为filename的文件中得到全部内容,输出为列表格式,以文件每行为列表中的一个元素,并以linenum-1为元素在列表中的位置存储
linecache.getline(filename,lineno) 从名为filename的文件中得到第lineno行。这个函数从不会抛出一个异常–产生错误时它将返回”(换行符将包含在找到的行里)。
如果文件没有找到,这个函数将会在sys.path搜索。
linecache.clearcache() 清除缓存。如果你不再需要先前从getline()中得到的行
linecache.checkcache(filename) 检查缓存的有效性。如果在缓存中的文件在硬盘上发生了变化,并且你需要更新版本,使用这个函数。如果省略filename,将检查缓存里的所有条目。
linecache.updatecache(filename) 更新文件名为filename的缓存。如果filename文件更新了,使用这个函数可以更新linecache.getlines(filename)返回的列表。
# -*- coding: UTF-8 -*-
import csv
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
import linecache
new_line=[]
file = linecache.getlines('./macdata/origin_info.csv')
for line in file:
line = line.split(',')
line[2] = line[2].strip('\n')
if len(line) == 0:
continue
if len(line) == 3:
new_line.append(line)
if len(line) > 3:
for i in xrange(2, len(line)):
new_line.append([line[0], line[1], line[i].strip('\n')])
file=open('./macdata/normal_origin_info.txt','w')
file.write(str(new_line))
file.close()
不幸的是,以上两种代码最终都把主机内存跑爆炸了(TAT、
反省了一下,不是说withopen和linecache不好,而是new_line变量的创建过程过于消耗内存,因此第三种方法里,我选择每读取一行,便写一行到新文件中去,这样就解决了内存爆炸的问题
在这里含泪介绍方法三(自己摸索出来的(。
代码3
# -*- coding: UTF-8 -*-
import csv
import numpy as np
import pandas as pd
from pandas import Series, DataFrame
# csv_reader = csv.reader(open('./macdata/origin_info.csv'))
rs = open('./macdata/normal_origin_info.txt', 'w')
with open('./macdata/origin_info.csv') as file:
for line in file:
# print line.split(',')[0]
# print len(line)
# print len(line.split(','))
line = line.split(',')
if len(line) == 0:
continue
if len(line) == 3:
# line[2] = line[2].strip('\n')
rs.write(str(line[0]) + ',' + str(line[1]) + ',' + str(line[2].strip('\n')) + '\n')
# rs.write(str(line)+'\n')
# new_line.append(line)
if len(line) > 3:
for i in xrange(2, len(line)):
rs.write(str(line[0]) + ',' + str(line[1]) + ',' + str(line[i].strip('\n')) + '\n')
rs.close()
以上就是关于python处理大文件的一点小心得
实在是很微小的心得