我需要读取一个大型 csv 数据文件,但是该文件充满了换行符,而且通常非常困惑。因此,我不是使用 pandas 手动执行此操作,但是我遇到了奇怪的减速问题,这似乎取决于文件中出现的字符。
在尝试通过随机创建一个看起来相似的 csv 文件来重现问题时,我认为问题可能出在 count
函数中。
考虑这个示例,它创建一个包含混沌随机数据的大文件,读取该文件,然后使用计数对其进行排序,以便可以将其作为柱状数据读取。
请注意,在文件的第一次运行中,我仅使用 string.ascii_letters
作为随机数据,第二次运行时,我使用 string.printable
中的字符.
import os
import random as rd
import string
import time
# Function to create random data in a specific pattern with separator ";":
def createRandomString(num,io,fullLength):
lineFull = ''
nl = True
randstr = ''.join(rd.choice(string.ascii_letters) for _ in range(7))
for i in range(num):
if i == 0:
line = 'Start;'
else:
line = ''
bb = rd.choice([True,True,False])
if bb:
line = line+'\"\";'
else:
if rd.random() < 0.999:
line = line+randstr
else:
line = line+rd.randint(10,100)*randstr
if nl and i != num-1:
line = line+';\n'
nl = False
elif rd.random() < 0.04 and i != num-1:
line = line+';\n'
if rd.random() < 0.01:
add = rd.randint(1,10)*'\n'
line = line+add
else:
line = line+';'
lineFull = lineFull+line
return lineFull+'\n'
# Create file with random data:
outputFolder = "C:\\DataDir\\Output\\"
numberOfCols = 38
fullLength = 10000
testLines = [createRandomString(numberOfCols,i,fullLength) for i in range(fullLength)]
with open(outputFolder+"TestFile.txt",'w') as tf:
tf.writelines(testLines)
# Read in file:
with open(outputFolder+"TestFile.txt",'r') as ff:
lines = []
for line in ff.readlines():
lines.append(unicode(line.rstrip('\n')))
# Restore columns by counting the separator:
linesT = ''
lines2 = []
time0 = time.time()
for i in range(len(lines)):
linesT = linesT + lines[i]
count = linesT.count(';')
if count == numberOfCols:
lines2.append(linesT)
linesT = ''
if i%1000 == 0:
print time.time()-time0
time0 = time.time()
print time.time()-time0
打印语句输出如下:
0.0
0.0019998550415
0.00100016593933
0.000999927520752
0.000999927520752
0.000999927520752
0.000999927520752
0.00100016593933
0.0019998550415
0.000999927520752
0.00100016593933
0.0019998550415
0.00100016593933
0.000999927520752
0.00200009346008
0.000999927520752
0.000999927520752
0.00200009346008
0.000999927520752
0.000999927520752
0.00200009346008
0.000999927520752
0.00100016593933
0.000999927520752
0.00200009346008
0.000999927520752
始终如一的快速性能。
现在我将 createRandomString
中的第三行更改为 randstr = ''.join(rd.choice(string.printable) for _ in range(7))
,我的输出现在变成这样:
0.0
0.0759999752045
0.273000001907
0.519999980927
0.716000080109
0.919999837875
1.11500000954
1.25199985504
1.51200008392
1.72199988365
1.8820002079
2.07999992371
2.21499991417
2.37400007248
2.64800000191
2.81900000572
3.04500007629
3.20299983025
3.55500006676
3.6930000782
3.79499983788
4.13900017738
4.19899988174
4.58700013161
4.81799983978
4.92000007629
5.2009999752
5.40199995041
5.48399996758
5.70299983025
5.92300009727
6.01099991798
6.44200015068
6.58999991417
3.99399995804
不仅性能非常慢,而且随着时间的推移,它会持续变慢。
唯一的区别在于写入随机数据的字符范围。
我的真实数据中出现的完整字符集是这样的:
charSet = [' ','"','&',"'",'(',')','*','+',',','-','.','/','0','1','2','3','4','5','6',
'7','8','9',':',';','<','=','>','A','B','C','D','E','F','G','H','I','J','K',
'L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','\\','_','`','a',
'b','d','e','g','h','i','l','m','n','o','r','s','t','x']
让我们对 count
函数进行一些基准测试:
import random as rd
rd.seed()
def Test0():
randstr = ''.join(rd.choice(string.digits) for _ in range(10000))
randstr.count('7')
def Test1():
randstr = ''.join(rd.choice(string.ascii_letters) for _ in range(10000))
randstr.count('a')
def Test2():
randstr = ''.join(rd.choice(string.printable) for _ in range(10000))
randstr.count(';')
def Test3():
randstr = ''.join(rd.choice(charSet) for _ in range(10000))
randstr.count(';')
我仅测试数字、字母、可打印以及数据中的字符集。
%timeit
的结果:
%timeit(Test0())
100 loops, best of 3: 9.27 ms per loop
%timeit(Test1())
100 loops, best of 3: 9.12 ms per loop
%timeit(Test2())
100 loops, best of 3: 9.94 ms per loop
%timeit(Test3())
100 loops, best of 3: 8.31 ms per loop
性能是一致的,并且在某些字符集上没有出现任何count
问题。
我还测试了用 +
连接字符串是否会导致速度变慢,但情况也并非如此。
谁能解释一下或者给我一些提示吗?
编辑:使用Python 2.7.12
编辑2:在我的原始数据中发生了以下情况:
该文件大约有 550000 行,这些行经常被随机换行符中断,但始终由 38 个 ";"
分隔符定义。直到大约 300000 行时,性能很快,然后从该行开始,它突然开始变得越来越慢。我现在正在利用新线索进一步调查此事。
最佳答案
问题出在 count(';')
中。
string.printable
包含 ';'
,而 string.ascii_characters
则不包含。
然后,随着 linesT
长度的增加,执行时间也会增加:
0.000236988067627
0.0460968017578
0.145275115967
0.271568059921
0.435608148575
0.575787067413
0.750104904175
0.899538993835
1.08505797386
1.24447107315
1.34459710121
1.45430088043
1.63317894936
1.90502595901
1.92841100693
2.07722711563
2.16924905777
2.30753016472
特别是此代码对于 string.printable
存在问题:
numberOfCols = 38
if count == numberOfCols:
lines2.append(linesT)
linesT = ''
由于在刷新 linesT
之前,';'
可能会在第 37 行多次包含,因此 38
将是跳过并且 linesT
无限期增长。
您可以通过将初始设置保留为 string.ascii_characters
并将代码更改为 count('a')
来观察此行为。
要解决可打印的问题,您可以像这样修改代码:
if count > numberOfCols:
然后我们回到预期的运行时行为:
0.000234842300415
0.00233697891235
0.00247097015381
0.00217199325562
0.00262403488159
0.00262403488159
0.0023078918457
0.0024049282074
0.00231409072876
0.00233006477356
0.00214791297913
0.0028760433197
0.00241804122925
0.00250506401062
0.00254893302917
0.00266218185425
0.00236296653748
0.00201988220215
0.00245118141174
0.00206398963928
0.00219988822937
0.00230193138123
0.00205302238464
0.00230097770691
0.00248003005981
0.00204801559448
关于python - 当读取具有某些字符的某些数据时, string.count() 会大幅减慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40504611/