[英]How to improve performance of this script?
在python社区的帮助下,我开始学习python来处理大约5亿(40G)数据,并编写了以下脚本。
输入文件格式 -
Studentid,Subject,DateTime,Grade
001,Biology,Mon Apr 25 19:32:00 PDT 2013,B
001,Literature,Wed Apr 10 15:31:00 PST 2013,B
001,Math,Mon Apr 22 01:32:00 PDT 2013,A
002,Biology,Mon Apr 25 19:32:00 PDT 2013,A
002,Math,Mon Apr 22 16:31:14 PDT 2013,C
002,Math,Wed Apr 10 15:31:00 PST 2013,C
003,Biology,Mon Apr 22 13:31:00 PDT 2013,A
003,Irdu,Wed Apr 10 15:31:00 PST 2013,A
输出报告
003,Irdu;Wed Apr 10 15:31:00 PST 2013;A#Biology;Mon Apr 22 13:31:00 PDT 2013;A
002,Math;Wed Apr 10 15:31:00 PST 2013;C#Math;Mon Apr 22 16:31:14 PDT 2013;C#Biology;Mon Apr 25 19:32:00 PDT 2013;A
001,Literature;Wed Apr 10 15:31:00 PST 2013;B#Math;Mon Apr 22 01:32:00 PDT 2013;A#Biology;Mon Apr 25 19:32:00 PDT 2013;B
Python脚本
import csv
import time
import operator
import sys, getopt
import os
from collections import defaultdict
from datetime import datetime
from operator import itemgetter
start = time.time()
def elapsed():
return time.time() - start
def date_key(row):
try:
formatRow = row[1].replace('PDT ','')
formatRow = formatRow.replace('PST ','')
return datetime.strptime(formatRow, "%a %b %d %X %Y")
except Exception, e:
print ("Error in sorting the date: %s \nRow : %s" % (e, row))
pass
def processRecords(accountsData, fileName):
for v in accountsData.itervalues():
try:
v.sort(key=date_key)
except Exception, e:
pass
with open(fileName, 'a') as writer:
for pid,v in accountsData.iteritems():
csv = '#'.join([';'.join(t) for t in v])
writer.write("%s,%s\n" % (pid, csv))
def main(argv):
inputFile = ''
outputFile = ''
batchsize = 20000000
try:
opts, args = getopt.getopt(argv,"hi:o:b:",["ifile=","ofile=","bsize="])
except getopt.GetoptError:
print 'ReportToFileBatches.py -i <inputfile> -o <outputfile> -b<batchsize>[default=20000000]'
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print 'ReportToFileBatches.py -i <inputfile> -o <outputfile> -b<batchsize>[default=20000000]'
sys.exit()
elif opt in ("-i", "--ifile"):
inputFile = arg
elif opt in ("-o", "--ofile"):
outputFile = arg
elif opt in ("-b", "--bsize"):
batchsize = int(arg)
if not (os.path.isfile(inputFile)):
print ("\nError : File - %s does not exist." % (inputFile))
sys.exit(2)
#print "Batch Size %s " % batchsize
linenumb = 0
with open(inputFile,'r') as data:
accounts = defaultdict(list)
for line in data:
linenumb = linenumb + 1
line = line.rstrip('\r\n')
try:
sid, subject, datetime, grade = line.split(',')
accounts[sid].append((subject, datetime, grade))
if (linenumb == batchsize):
linenumb = 0
processRecords(accounts, outputFile)
accounts = defaultdict(list)
else: continue
except Exception, e:
print ("Error : %s \nRow : %s" % (e, line))
if(linenumb > 0):
processRecords(accounts, outputFile)
print("Total time taken - %.3fs" % elapsed())
if __name__ == "__main__":
main(sys.argv[1:])
您可以看到输出文件(报告)是按日期排序的,还可以是字段的串联。 我花更多时间在排序datetime列上(也许)。 我是Python的新手。 我非常感谢改善脚本以减少处理时间的任何帮助。 希望我有道理。
仅供参考:我确保输入文件按学生ID排序并进行批量处理。
我什至无法想象要通过大量分析或算法优化来做到这一点。
这让我震惊,因为它是数据库问题。
python是执行格式化和解析的粘合剂语言。 不是您自己管理40G数据的语言。
我认为您能做的最好的事情是放鸽子 。 如果您知道时间数据的范围和分布(即最大和最小时间),则此方法有效。 Pigeonholing通过将您的数据隔离到离散的Pigeonhole中来工作。 例如,如果您的数据分布在一个月左右,那么您可以拥有一个数组,其中每个索引都是一个代表该月每天的1小时的数组。 您遍历列表,将数据放入该数组。 将数据放入该数组时,可以将其排序到该子列表中。
如果正确选择鸽洞,此算法将非常有效。 例如,如果您的所有数据都在同一天之内,而您的鸽子洞每天都在,那么该算法的性能就不会比您的好。 另一个注意事项是,不必将鸽窝均匀地散开。 如果几乎所有数据都在不同日期的同一小时内,则请在该小时内添加较小的时间步长,然后为其余时间添加较大的时间步长。
计数排序是另一种选择(也具有更好的运行时),但是由于文件太大,我认为您可能会遇到内存问题或由于不断进行磁盘写入而导致的滞后。 值得一看,但要小心那些延误。
编辑:刚意识到您的文件大40克,以便解决该内存问题,而不是一个数组的数组,您可以有一系列文件的已知名称包含您的鸽子列表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.