如何为从大型xlsx文件加载pandas DataFrame制作进度条?

30

来源:https://pypi.org/project/tqdm/

import pandas as pd
import numpy as np
from tqdm import tqdm

df = pd.DataFrame(np.random.randint(0, 100, (100000, 6)))
tqdm.pandas(desc="my bar!")p`
df.progress_apply(lambda x: x**2)

我拿了这段代码并进行了编辑,以便从load_excel创建一个DataFrame而不是使用随机数字:

import pandas as pd
from tqdm import tqdm
import numpy as np

filename="huge_file.xlsx"
df = pd.DataFrame(pd.read_excel(filename))
tqdm.pandas()
df.progress_apply(lambda x: x**2)

这个操作导致了错误,所以我将df.progress_apply更改为:

df.progress_apply(lambda x: x)

这是最终代码:

import pandas as pd
from tqdm import tqdm
import numpy as np

filename="huge_file.xlsx"
df = pd.DataFrame(pd.read_excel(filename))
tqdm.pandas()
df.progress_apply(lambda x: x)

这会生成一个进度条,但它实际上不会显示任何进度,而是加载进度条,在操作完成时跳到100%,从而失去了目的。

我的问题是:如何使这个进度条起作用?
progress_apply内部的函数实际上是做什么的?
是否有更好的方法?也许是tqdm的替代方案?

非常感谢任何帮助。


1
tqdm会跟踪遍历可迭代对象所花费的时间。如果想要一个状态栏,你需要了解pandas如何将文件加载到数据帧中,并编写自己的代码来实现(如果可能的话)。如果加载时间是问题所在,为什么不只对几行长度进行粗略估计呢? - DJK
旋转的轮子足够吗? - rocksportrocker
6个回答

8
下面是一个使用tqdm的一行代码解决方案:
import pandas as pd
from tqdm import tqdm

df = pd.concat([chunk for chunk in tqdm(pd.read_csv(file_name, chunksize=1000), desc='Loading data')])

如果您知道要加载的总行数,可以使用参数 total 将该信息添加到 tqdm 函数中,从而得到百分比输出。

1
问题明确地说了“xlsx文件”。XLSX不是CSV。 - Sheldore

7
不会起作用。pd.read_excel将阻塞,直到文件读取完成,在执行期间无法从该函数获取有关其进度的信息。
对于可以分块进行的读操作,它是有效的,例如:
chunks = []
for chunk in pd.read_csv(..., chunksize=1000):
    update_progressbar()
    chunks.append(chunk)

但据我了解,tqdm也需要提前知道块数,因此为了得到适当的进度报告,您需要先读取完整个文件....


4
更新进度条(progress bar)是一个函数吗?如果是,我可以用哪个库来访问它? - Kathiravan Natarajan

3
这可能对于有类似问题的人会有所帮助。这里可以获取帮助。
例如:
for i in tqdm(range(0,3), ncols = 100, desc ="Loading data.."): 
    df=pd.read_excel("some_file.xlsx",header=None)
    LC_data=pd.read_excel("some_file.xlsx",'Sheet1', header=None)
    FC_data=pd.read_excel("some_file.xlsx",'Shee2', header=None)    
print("------Loading is completed ------")

2

免责声明:这只适用于xlrd引擎,且未经过彻底测试!

它是如何工作的?我们对xlrd.xlsx.X12Sheet.own_process_stream方法进行了猴子补丁,该方法负责从文件流中加载工作表。我们提供自己的流,其中包含我们的进度条。每个工作表都有自己的进度条。

当我们需要进度条时,我们使用load_with_progressbar()上下文管理器,然后执行pd.read_excel('<FILE.xlsx>')

import xlrd
from tqdm import tqdm
from io import RawIOBase
from contextlib import contextmanager


class progress_reader(RawIOBase):
    def __init__(self, zf, bar):
        self.bar = bar
        self.zf = zf

    def readinto(self, b):
        n = self.zf.readinto(b)
        self.bar.update(n=n)
        return n


@contextmanager
def load_with_progressbar():

    def my_get_sheet(self, zf, *other, **kwargs):
        with tqdm(total=zf._orig_file_size) as bar:
            sheet = _tmp(self, progress_reader(zf, bar), **kwargs)
        return sheet

    _tmp = xlrd.xlsx.X12Sheet.own_process_stream

    try:
        xlrd.xlsx.X12Sheet.own_process_stream = my_get_sheet
        yield
    finally:
        xlrd.xlsx.X12Sheet.own_process_stream = _tmp


import pandas as pd

with load_with_progressbar():
    df = pd.read_excel('sample2.xlsx')

print(df)

进度条截图:

图片描述在此输入


这给了我以下错误: “ZipExtFile”对象没有属性“_orig_file_size” - Imad

1

以下内容基于用户rocksportrocker的精彩回答。

  • 我是 Python 初学者!
  • 请查看下方,这是我根据用户rocksportrocker的建议编写的第一个版本。

import pandas as pd

print("Info: Loading starting.")

# https://dev59.com/UFQK5IYBdhLWcg3wO9ip
temp = [];
myCounter = 1;
myChunksize = 10000;
# https://dev59.com/vmAf5IYBdhLWcg3w0VUf
for myChunk in pd.read_csv('YourFileName.csv', chunksize = myChunksize, low_memory = False):
    print('# of rows processed: ', myCounter*myChunksize)
    myCounter = myCounter + 1;
    temp.append(myChunk)
    
print("Info: Loading complete.")

# https://dev59.com/jlwX5IYBdhLWcg3wlgTl
df = pd.concat(temp, ignore_index = True)
df.head()

enter image description here


0

这是基于之前许多回复的建议。我使用此方法加载一个包含注释行(#)的大型TSV文件。它通过百分比值更新tqdm进度条。

from tqdm import tqdm
import pandas as pd

        # Get number of lines in file.
        with open(file, 'r') as fp:
            lines = len(fp.readlines())
        # Read file in chunks, updating progress bar after each chunk.
        listdf = []
        with tqdm(total=lines) as bar:
            for chunk in pd.read_csv(file,chunksize=1000,comment='#',sep='\t'):
                listdf.append(chunk)
                bar.update(chunk.shape[0])

        df = pd.concat(listdf,ignore_index=True)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接