写CSV文件在处理过程中减少它/s

qacovj5a  于 2023-06-19  发布在  其他
关注(0)|答案(2)|浏览(139)

我有一个CSV文件,我想修改里面的值。此文件超过100万行。
在文件开始时,脚本以5000 lines per seconds的速度运行,但随后它减少到400 lines per seconds

我想知道为什么它是慢下来,以及如何提高这个脚本的性能

txt = ""
data = open(path + "_mag.csv").readlines()
i = 0
for line in tqdm.tqdm(data):
    if i == 0:
        txt += line + "\n"
        i += 1
        continue
    values = line.split(";")
    for j, value in enumerate(mag_rotated[i-1]):  # 15 values in float type
        index = j + 5
        values[index] = str(value)
    new_line = ";".join(values)
    txt += new_line + "\n"
    i += 1

下面是一个小数据行的例子:

Timestamp [µs];Temp ADC1 [°C];Temp ADC2 [°C];Temp ADC3 [°C];Temp ADC4 [°C];X0 [µT];Y0 [µT];Z0 [µT];X1 [µT];Y1 [µT];Z1 [µT];X2 [µT];Y2 [µT];Z2 [µT];X3 [µT];Y3 [µT];Z3 [µT];X4 [µT];Y4 [µT];Z4 [µT];unused;X5 [µT];Y5 [µT];Z5 [µT];X6 [µT];Y6 [µT];Z6 [µT];X7 [µT];Y7 [µT];Z7 [µT];X8 [µT];Y8 [µT];Z8 [µT];X9 [µT];Y9 [µT];Z9 [µT];unused
911532093;30.563;30.313;;;-1.62919885e+01;1.86305991e+01;3.93283914e+01;-1.59370440e+01;1.88661384e+01;3.93722822e+01;-1.60104993e+01;1.89392587e+01;3.93954596e+01;-1.63657738e+01;1.86798405e+01;3.93386700e+01;-1.65630085e+01;1.78254986e+01;3.95608333e+01;;;;;;;;;;;;;;;;;
911533093;30.563;30.313;;;-1.62927678e+01;1.86261966e+01;3.93056706e+01;-1.59385424e+01;1.88634411e+01;3.93504949e+01;-1.60110385e+01;1.89362330e+01;3.93737558e+01;-1.63657738e+01;1.86764223e+01;3.93170219e+01;-1.65643876e+01;1.78232520e+01;3.95398268e+01;;;;;;;;;;;;;;;;;
911534093;30.563;30.313;;;-1.62899203e+01;1.86278438e+01;3.93394221e+01;-1.59340472e+01;1.88623921e+01;3.93840899e+01;-1.60095108e+01;1.89366524e+01;3.94075406e+01;-1.63627492e+01;1.86763323e+01;3.93510360e+01;-1.65617493e+01;1.78224132e+01;3.95712317e+01;;;;;;;;;;;;;;;;;

有关上下文:我的脚本旨在替换这15个值:X0 [µT] Y0 [µT] Z0 [µT] X1 [µT] Y1 [µT] Z1 [µT] X2 [µT] Y2 [µT] Z2 [µT] X3 [µT] Y3 [µT] Z3 [µT] X4 [µT] Y4 [µT] Z4 [µT]

uwopmtnx

uwopmtnx1#

我想有两个原因导致了速度的下降。
1.是因为您试图将所有修改的数据存储到单个字符串变量txt中。
1.您使用readlines()将整个CSV文件一次性读入内存,由于文件很大,这会消耗大量内存。
您应该直接写入输出文件,而不是将其全部存储在内存中。
一个很好的方法是打开两个文件,输入和输出文件。然后从输入文件中一次读取一行,并将修改后的行直接写入输出文件

import tqdm

with open(path + "_mag.csv", "r") as fin, open(path + "_mag_modified.csv", "w") as fout:
    for i, line in enumerate(tqdm.tqdm(fin)):
        if i == 0:
            fout.write(line)
            continue
        values = line.strip().split(";")
        for j, value in enumerate(mag_rotated[i-1]):  # 15 values in float type
            index = j + 5
            values[index] = str(value)
        new_line = ";".join(values)
        fout.write(new_line + "\n")
vawmfj5a

vawmfj5a2#

就像Obaskly在第2条中指出的那样,在一百万次迭代中附加字符串是灾难性的慢。

x = "a" * 50
s = ""
for _ in tqdm(range(1_000_000)):
    s += x

在我的机器上,开始大约5000它/秒,并稳步下降。
既然你标记了python和csv,我建议使用Python的标准csv模块:它只比手动解析稍微慢一点(在我的机器上,读/写1 M+行需要4秒,比1秒),并且使代码更简单:

import csv
from tqdm import tqdm

f_in = open("input.csv", newline="")
f_out = open("output.csv", "w", newline="")

reader = csv.reader(f_in, delimiter=";")
writer = csv.writer(f_out, delimiter=";")

writer.writerow(next(reader))  # transfer header

for i, row in tqdm(enumerate(reader)):
    row[5:20] = mag_rotated[i]
    writer.writerow(row)

因为我用next(reader)手动迭代了header,所以当我开始枚举for循环中的行时,它自然会从i = 0开始,我相信它会与mag_rotated完美匹配;没有更多[i - 1]。此外,由于您知道只需要更改从字段5开始的15个字段,因此可以使用Python的切片表示法row[5:20] = mag_rotated[i]来更新这些字段;不再迭代带偏移量的字段。
如果你想使用manualally-parse-CSV路径,你可以使用上面的一些技巧来清理你已经拥有的代码:

DELIM = ";"

f_in = open("input.csv")
f_out = open("output.csv", "w")

f_out.write(next(f_in))

for i, line in tqdm(enumerate(f_in)):
    fields = line.strip().split(DELIM)
    fields[5:] = mag_rotated[i]
    f_out.write(DELIM.join(fields) + "\n")

相关问题