降低计算精度以加快执行速度

时间:2018-05-24 22:57:02

标签: python csv decimal

我有一个数据采集系统,可以测量几分钟并生成一个包含1000万行和10列的csv文件。然后我用Python(csv.reader)导入这个csv文件,对获取的数值数据执行一系列操作(但是'一次'只有'10000行,否则计算机内存将被淹没)。最后,我将结果导出到另一个小得多的csv文件(csv.writer)中。 问题是运行时很长,我想加快速度。当我用记事本打开原始csv文件时,我发现每个数字最多有16位数字,如0.0015800159870059,12.0257771094508等。我知道DAQ的准确度最多为0.1%,大多数尾随数字都是噪音。是否有一种优雅的方式迫使Python从头到尾只用7-8位数来操作全球,以加快计算速度?我知道错误传播,我将尝试不同的数字设置,以查看最佳情况。 请注意,仅使用“截断”数据构建临时csv文件(例如包含0.0015800,12.0257771等)并将其导入Python中是不够的。 Python中的计算也应该使用降低的精度。我查看了 decimal 模块,到目前为止没有成功。

with open(‘datafile’,newline='') as DAQfile:
    reader=csv.reader(DAQfile,delimiter=',')
    for row in reader:
       … calculate stuff…

with open('results.csv','w',newline='') as myfile:
    mywriter = csv.writer(myfile)
    …write stuff…

根据迄今为止的评论添加一些细节: 该程序计算“瞬时功率”的移动平均值的峰值。 csv文件中的数据可以这样描述,其中'col'表示列,V表示电压,I表示电流:col1 = time,col2 = V1,col3 = I1,col4 = V2,col5 = I2,依此类推col11 = V10,col12 = I10。因此每行代表DAQ采集的数据样本。 瞬时功率是Pi = V1 * I1 + V2 * I2 + ... + V11 * I11 为了一次计算超过10000行的移动平均值,我构建了一个缓冲区(用Buffer = [0] * 10000初始化)。此缓冲区将存储连续10000行的Pi,并在每次csv.reader移动到下一行时更新。缓冲区与移位寄存器完全相同。 这样,内存使用量无关紧要(已验证)。总之,计算是乘法,加法,min(a,b)函数(以检测移动平均值的峰值)和del / append以刷新缓冲区。移动平均线本身也是迭代的,类似于newavg = oldavg +(newlast-oldfirst)/ bufsize。 我的想法是,当我知道大多数尾随数字都是垃圾时,让Python使用所有这些小数都没有任何意义。  忘记提到来自DAQ的csv文件的大小刚好低于1Gb。

2 个答案:

答案 0 :(得分:1)

是的,有办法 - 使用NumPy。首先,有大量的矢量/矢量运算,可以用一个命令执行

a = b + c

将有效地求和两个向量。

其次,这是你的问题的答案,你可以指定4bytes浮点类型,大大减少内存需求和提高速度。

您应该使用

直接阅读您的文件
from numpy import genfromtxt
data = genfromtxt('datafile.csv', dtype=numpy.float32, delimiter=',')
...

data将由标准的32位浮点数组成,大约精度为7位。

CSV文件可以通过部件/串读取

numpy.genfromtxt(fname, dtype=<class 'float'>, comments='#', delimiter=None,
skip_header=0, skip_footer=0, converters=None, missing_values=None, filling_values=None,
usecols=None, names=None, excludelist=None, deletechars=None, replace_space='_',
autostrip=False, case_sensitive=True, defaultfmt='f%i',
unpack=None, usemask=False, loose=True, invalid_raise=True, max_rows=None,
encoding='bytes')

这里是完整的参数列表。如果将max_rows设置为10,则只会读取10行。默认是读取整个文件。您可以通过skip_header选项跳过一些初始记录来读取文件中间的任何内容。

答案 1 :(得分:0)

使用DyZ的评论。如果有办法加速计算,(如果第二个操作数或被除数是2的幂,则使用&lt;&lt;&gt;&gt;进行乘法或除法,你应该接受它。 例如:

>>> 22 * 16
352
>>> 22 << 4
352

在那种情况下,我做了完全相同的操作,时间略有减少。但是,如果这相当于100万亿次计算,那么差异就更明显了。