Python 读取特定块pandas/不读取pandas中的所有块
我正试图使用相应的方法来读取一个大的csv文件并对其进行处理。因为我不是python的本地人,所以我遇到了一个优化问题,并在这里寻找更好的解决方案Python 读取特定块pandas/不读取pandas中的所有块,python,pandas,for-loop,Python,Pandas,For Loop,我正试图使用相应的方法来读取一个大的csv文件并对其进行处理。因为我不是python的本地人,所以我遇到了一个优化问题,并在这里寻找更好的解决方案 我的代码的作用: 我在csv的行计数中读取 with open(file) as f: row_count = sum(1 for line in f) 之后,我将数据“切片”为30个大小相等的块,并使用for循环和pd.read\u csv(file,chunksize)对其进行相应的处理,以得到链接的答案。由于在一个图中绘制30个图是
我的代码的作用: 我在csv的行计数中读取
with open(file) as f:
row_count = sum(1 for line in f)
之后,我将数据“切片”为30个大小相等的块,并使用for循环和pd.read\u csv(file,chunksize)
对其进行相应的处理,以得到链接的答案。由于在一个图中绘制30个图是非常不清楚的,我用模(可能是可变的)每5步绘制一次。为此,我使用一个外部计数器
chunksize = row_count // 30
counter = 0
for chunk in pd.read_csv(file, chunksize=chunksize):
df = chunk
print(counter)
if ((counter % 5) == 0 | (counter == 0):
plt.plot(df["Variable"])
counter = counter +1
plt.show()
现在回答我的问题: 看起来,这个循环在处理循环之前读取块大小,这是合理的。我可以看到这一点,因为
打印(计数器)
步骤也相当慢。因为我读了几百万行csv,所以每一步都需要一些时间。在读取for循环之前,是否有方法跳过for循环中不需要的块?我尝试了一些类似于:
wanted_plts <- [1,5,10,15,20,25,30]
for i in wanted_plts:
for chunk[i] in pd.read_csv(file, chunksize=chunksize):
.
.
wanted\u plts我玩弄了你的设置,试图找到一种跳过块的方法,使用另一个渲染库,如pyqtgraph
,或者使用matplotlib.pyplot
子例程,而不是plot()
,所有这些都是徒劳的
因此,我能给您的唯一合理建议是通过传递usecols
参数将read\u csv
的范围限制在您感兴趣的数据上
而不是:
for chunk in pd.read_csv(file, chunksize=chunksize):
plt.plot(chunk['Variable'])
使用:
而且,如果您还没有这样做,通过尽可能使用最大的chunksize
来限制迭代次数(因此在您的情况下,使用最小的行计数
除法器)
我还没有量化它们各自的权重,但是您将在csv\u read()
和plot()
方法上增加开销,即使是因为您当前的块已经相当大,所以开销也非常小
使用我的测试数据,将chunksize
翻四番可以将处理时间减少一半:
chunksize=1000
=>在12.7秒内执行
chunksize=2000
=>在9.06秒内执行
chunksize=3000
=>在7.68s中执行
chunksize=4000
=>以6.94秒执行
在读取时指定usecols
,也可以将处理时间减少一半:
chunksize=1000+usecols=['Variable']
=>在8.33s中执行
chunksize=2000+usecols=['Variable']
=>在5.27s中执行
chunksize=3000+usecols=['Variable']
=>在4.39s中执行
chunksize=4000+usecols=['Variable']
=>在3.54s中执行
据我所知,pandas不支持跳过文件块。至少我从未在文档中找到任何关于它的信息
通常,从文件中跳过行(根本不读取它们)是很困难的,除非您事先知道要跳过多少行以及每行中有多少个字符。在这种情况下,您可以尝试使用并将流位置移动到下一次迭代所需的确切位置。
但这似乎不是你的情况
我认为,要提高效率,最好的办法是使用标准IO读取行,并仅将需要/想要绘制的行转换为数据帧
例如,考虑以下自定义迭代器。
实例化时,它会保存标题(第一行)。每次迭代它都从文件中读取一段行,然后跳过以下n*chunksize
行。它返回标题行,后跟读取行,包装在io.StringIO
对象中(因此它是一个流,可以直接馈送到pandas.read\u csv
)
使用此类,您可以从文件中读取:
reader = DfReaderChunks(file, chunksize, 4)
for dfst in reader:
df = pd.read_csv(dfst)
print(df) #here I print to stdout, you can plot
reader.close()
这与您的设置“等效”:
for chunk in pd.read_csv(file, chunksize=chunksize):
df = chunk
if (counter % 5 == 0):
print(df) #again I print, you can plot
counter += 1
我使用39MB的数据帧(100000行或随机数)测试了上述两个代码段所用的时间
在我的机器上,前者需要0.458秒,后者需要0.821秒
唯一的缺点是前一个代码段无法跟踪行索引(每次都是一个新的数据帧,因此索引总是从0开始),但打印的数据块是相同的。如果不使用它将CSV解析为数据帧
,将浪费大量资源。为了避免这种情况,您可以在第一次过程中创建线索引:
fp = open(file_name)
row_count = 0
pos = {0: 0}
line = fp.readline()
while line:
row_count += 1
pos[row_count] = fp.tell()
line = fp.readline()
不要处理文件句柄!由于read\u csv()
接受流,因此可以根据需要移动文件指针:
chunksize = row_count // 30
wanted_plts = [1,5,10,15,20,25,30]
for i in wanted_plts:
fp.seek(pos[i*chunksize]) # this will bring you to the first line of the desired chunk
obj = pd.read_csv(fp, chunksize=chunksize) # read your chunk lazily
df = obj.get_chunk() # convert to DataFrame object
plt.plot(df["Variable"]) # do something
fp.close() # Don't forget to close the file when finished.
最后还有一个警告:以这种方式读取CSV时,您将丢失列名。因此,进行调整:
obj = pd.read_csv(fp, chunksize=chunksize, names=[!!<column names you have>!!])
obj=pd.read\u csv(fp,chunksize=chunksize,names=[!!])
请注意,文件
是一个保留字,请避免使用它来防止不必要的副作用。您可以改用文件
或文件名
chunksize = row_count // 30
wanted_plts = [1,5,10,15,20,25,30]
for i in wanted_plts:
fp.seek(pos[i*chunksize]) # this will bring you to the first line of the desired chunk
obj = pd.read_csv(fp, chunksize=chunksize) # read your chunk lazily
df = obj.get_chunk() # convert to DataFrame object
plt.plot(df["Variable"]) # do something
fp.close() # Don't forget to close the file when finished.
obj = pd.read_csv(fp, chunksize=chunksize, names=[!!<column names you have>!!])