Python 读取特定块pandas/不读取pandas中的所有块

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文件并对其进行处理。因为我不是python的本地人,所以我遇到了一个优化问题,并在这里寻找更好的解决方案


我的代码的作用:

我在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>!!])