广告
返回顶部
首页 > 资讯 > 后端开发 > Python >pandas读取excel时获取读取进度的实现
  • 168
分享到

pandas读取excel时获取读取进度的实现

2024-04-02 19:04:59 168人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

写在前面 QQ群里偶然看到群友问这个问题, pandas读取大文件时怎么才能获取进度? 我第一反应是: 除非pandas的read_excel等函数提供了回调函数的接口, 否

写在前面

QQ群里偶然看到群友问这个问题, pandas读取大文件时怎么才能获取进度? 我第一反应是: 除非pandas的read_excel等函数提供了回调函数的接口, 否则应该没办法做到. 搜索了一下官方文档和网上的帖子, 果然是没有现成的方案, 只能自己动手.

准备工作

确定方案

一开始我就确认了实现方案, 那就是增加回调函数. 这里现学现卖科普一下什么是回调函数. 简单的说就是:

所使用的模块里面, 会调用一个你给定的外部方法/函数, 就是回调函数. 拿本次的尝试作为例子, 我会编写一个"显示进度函数", 通过传参的方式传入pd.read_excel, 这样pd在读取excel时, 会边读取边调用"显示进度函数". 为什么不直接在pd里面增加? 因为pd读取excel文件时是阻塞的, 内部方法在被调用时无法抛出进度信息. (如有谬误请指正)

理解读取方式

先得了解一下pandas是怎么读取excel的. 在PyCharm里面按住control点击read_excel, 再浏览一下代码根据关键的函数继续跳转, 还是挺容易得到调用的路径的.

在这里插入图片描述

最后OpenpyxlReader读取excel的方法代码如下. 很明显重点就在其中的for循环里. 调用get_sheet_data时, 已经通过一系列方法获得了目标sheet(这里细节不赘述), 然后在for循环里逐行读取数据并返回data最后生成dataframe.


def get_sheet_data(self, sheet, convert_float: bool) -> List[List[Scalar]]:
        # GH 39001
        # Reading of excel file depends on dimension data being correct but
        # writers sometimes omit or get it wrong
        import openpyxl

        version = LooseVersion(get_version(openpyxl))

        # There is no Good way of determining if a sheet is read-only
        # https://foss.heptapod.net/openpyxl/openpyxl/-/issues/1605
        is_readonly = hasattr(sheet, "reset_dimensions")

        if version >= "3.0.0" and is_readonly:
            sheet.reset_dimensions()

        data: List[List[Scalar]] = []
        last_row_with_data = -1
        for row_number, row in enumerate(sheet.rows):
            converted_row = [self._convert_cell(cell, convert_float) for cell in row]
            if not all(cell == "" for cell in converted_row):
                last_row_with_data = row_number
            data.append(converted_row)

        # Trim trailing empty rows
        data = data[: last_row_with_data + 1]

        if version >= "3.0.0" and is_readonly and len(data) > 0:
            # With dimension reset, openpyxl no longer pads rows
            max_width = max(len(data_row) for data_row in data)
            if min(len(data_row) for data_row in data) < max_width:
                empty_cell: List[Scalar] = [""]
                data = [
                    data_row + (max_width - len(data_row)) * empty_cell
                    for data_row in data
                ]

        return data

开始改动

这里直接暴力更改pandas库源文件!(仅用于调试, 注意备份和保护自己的工作环境)

主程序代码

编写main.py, 代码比较简单, 相关功能我都用注释作为解释. 其中show_pd_read_excel_progress就是我编写的回调函数, 通过命令行的方式输出实时的读取进度. 当然你如果编写的是GUI程序比如PYQt5, 也可以在这个回调函数中发送signal给main UI, 做成progress bar或者其他的GUI样式.


import pandas as pd
from datetime import datetime

'''
定义回调函数
cur: 读取时的当前行数
tt: 读取文件的总行数
'''
def show_pd_read_excel_progress(cur, tt):
    # 进度数值
    progress = " {:.2f}%".fORMat(cur/tt*100)
    # 进度条
    bar = " ".join("█" for _ in range(int(cur/tt*100/10)))
    # 显示进度
    print("\r进度:" + bar + progress, end="", flush=True)

# 记录开始时间
t = datetime.now()
# 开始读取excel
print("pd.read_excel: test_4.xlsx...")
xl_data = pd.read_excel("test_4.xlsx", callback=show_pd_read_excel_progress)
# 打印excel头几行
print(xl_data.head())
print("\n")
# 显示花费的时间
print("Time spent:", datetime.now()-t)

修改pandas源码

再自己观察一下, 我在pd.read_excel方法的参数里增加了callback参数, 这个参数是原版read_excel方法里没有的. 所以我们需要处理pandas源码, 这个源码在…/pandas/io/excel/_base.py中, pycharm中按住control点击read_excel可以快速跳转. 这个地方我增加了一个参数callback, 默认值为None. 下方io.parse同样把callback参数传递给ExcelFile类.


def read_excel(
    io,
    sheet_name=0,
    header=0,
    names=None,
    index_col=None,
    usecols=None,
    squeeze=False,
    dtype=None,
    engine=None,
    converters=None,
    true_values=None,
    false_values=None,
    skiprows=None,
    nrows=None,
    na_values=None,
    keep_default_na=True,
    na_filter=True,
    verbose=False,
    parse_dates=False,
    date_parser=None,
    thousands=None,
    comment=None,
    skipfooter=0,
    convert_float=True,
    mangle_dupe_cols=True,
    storage_options: StorageOptions = None,
    callback = None, # 增加callback参数
):

    should_close = False
    if not isinstance(io, ExcelFile):
        should_close = True
        io = ExcelFile(io, storage_options=storage_options, engine=engine)
    elif engine and engine != io.engine:
        raise ValueError(
            "Engine should not be specified when passing "
            "an ExcelFile - ExcelFile already has the engine set"
        )

    try:
        data = io.parse(
            sheet_name=sheet_name,
            header=header,
            names=names,
            index_col=index_col,
            usecols=usecols,
            squeeze=squeeze,
            dtype=dtype,
            converters=converters,
            true_values=true_values,
            false_values=false_values,
            skiprows=skiprows,
            nrows=nrows,
            na_values=na_values,
            keep_default_na=keep_default_na,
            na_filter=na_filter,
            verbose=verbose,
            parse_dates=parse_dates,
            date_parser=date_parser,
            thousands=thousands,
            comment=comment,
            skipfooter=skipfooter,
            convert_float=convert_float,
            mangle_dupe_cols=mangle_dupe_cols,
            callback = callback, # 增加callback参数
        )
    finally:
        # make sure to close opened file handles
        if should_close:
            io.close()
    return data
... # 省略代码

浏览一下ExcelFile类(还在_base.py中)的代码, 这个类会根据文件类型选择引擎, 我读取的是xlsx文件, 所以会跳转到openpyxl并把所有的参数传递过去, 这个类不用处理. 下面跳转到_openpyxl.py中看一下OpenpyxlReader类, 这个类是继承BaseExcelReader类(在_base.py中)的, 所以还是得回去看一下BaseExcelReader, 并修改一下参数, 增加callback(如下2处).


def parse(
        self,
        sheet_name=0,
        header=0,
        names=None,
        index_col=None,
        usecols=None,
        squeeze=False,
        dtype=None,
        true_values=None,
        false_values=None,
        skiprows=None,
        nrows=None,
        na_values=None,
        verbose=False,
        parse_dates=False,
        date_parser=None,
        thousands=None,
        comment=None,
        skipfooter=0,
        convert_float=True,
        mangle_dupe_cols=True,
        callback = None, # 增加callback参数
        **kwds,
    ):
... # 省略代码

for asheetname in sheets:
            if verbose:
                print(f"Reading sheet {asheetname}")

            if isinstance(asheetname, str):
                sheet = self.get_sheet_by_name(asheetname)
            else:  # assume an integer if not a string
                sheet = self.get_sheet_by_index(asheetname)

            data = self.get_sheet_data(sheet, convert_float, callback) # 传递callback参数给get_sheet_data方法
            usecols = maybe_convert_usecols(usecols)
... # 省略代码

好了, 终于到重点了, 我们跳转到get_sheet_data方法, 并做对应修改(方法参数, 获取总行数, 调用回调函数). 思路非常清晰, 通过一顿操作, 终于千里迢迢把callback给一层层传递过来了, 所以在一行行读取excel时, 可以调用并显示进度了.


def get_sheet_data(self, sheet, convert_float: bool, callback) -> List[List[Scalar]]: # 传递参数增加callback
        # GH 39001
        # Reading of excel file depends on dimension data being correct but
        # writers sometimes omit or get it wrong
        import openpyxl
				# 获取sheet的总行数
        max_row = sheet.max_row
        print("sheet_max_row:", sheet.max_row)

        version = LooseVersion(get_version(openpyxl))

        # There is no good way of determining if a sheet is read-only
        # Https://foss.heptapod.net/openpyxl/openpyxl/-/issues/1605
        is_readonly = hasattr(sheet, "reset_dimensions")

        if version >= "3.0.0" and is_readonly:
            sheet.reset_dimensions()

        data: List[List[Scalar]] = []
        last_row_with_data = -1
        for row_number, row in enumerate(sheet.rows):
						# 调用回调函数
            if callback is not None:
                callback(row_number+1, max_row)
            converted_row = [self._convert_cell(cell, convert_float) for cell in row]
            if not all(cell == "" for cell in converted_row):
                last_row_with_data = row_number
            data.append(converted_row)

        # Trim trailing empty rows
        data = data[: last_row_with_data + 1]

        if version >= "3.0.0" and is_readonly and len(data) > 0:
            # With dimension reset, openpyxl no longer pads rows
            max_width = max(len(data_row) for data_row in data)
            if min(len(data_row) for data_row in data) < max_width:
                empty_cell: List[Scalar] = [""]
                data = [
                    data_row + (max_width - len(data_row)) * empty_cell
                    for data_row in data
                ]

        return data

运行测试

运行一下main.py, 效果如下, 实时显示进度功能已经实现, 且会计算出读取所花费的时间. 如果你是要读取csv或者sql之类的, 也可以照猫画虎.

在这里插入图片描述

优化和应用

  • 前面也说过直接修改pandas源码是非常不科学的操作, 这会破坏已有的编程环境, 且源码换到别的机器上还得重新在修改一遍
  • 也尝试过用继承+重写pandas, 不过水平有限没有成功, 希望大家指点
  • 实测print进度条会非常费时间, 当然也不需要每读一行excel都更新一次进度条, 定时(比如每秒刷一次)或者定量(每n行, 或者每1%进度刷新一次)比较合理
  • 读取大规模数据时, 频繁调用回调函数肯定会耽误效率, 不过如果是GUI程序或者给其他人使用的, 有实时进度肯定会改善用户体验, 其中优劣需要coder自己权衡

到此这篇关于pandas读取excel时获取读取进度的实现的文章就介绍到这了,更多相关pandas读取excel读取内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: pandas读取excel时获取读取进度的实现

本文链接: https://www.lsjlt.com/news/123512.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • pandas读取excel时获取读取进度的实现
    写在前面 QQ群里偶然看到群友问这个问题, pandas读取大文件时怎么才能获取进度? 我第一反应是: 除非pandas的read_excel等函数提供了回调函数的接口, 否...
    99+
    2022-11-12
  • Python调用Pandas实现Excel读取
    目录开头先BB两句操作过程安装PythonPandas安装包上手使用创建Excel,写入数据完整代码开头先BB两句 基本上来说,每周五写的周报都是这个套路。 突然想用Python智...
    99+
    2022-11-10
  • Pandas读取csv的实现
    目录一、Pandas读取表头:二、读取具体数据:对于文件的操作中,读写csv操作是一个比较常见的操作,很多时候可能会选择使用python中的文件读取的方式对csv文件操作,这种方式并...
    99+
    2023-01-15
    Pandas读取csv Pandas csv读取
  • pandas读取Excel批量转换时间戳的实践
    目录一、安装二、 代码如下python将GPS时间戳批量转换为日期时间(年月日时分秒)一、安装 pip install pandas 如果出报错,不能运行,可以安装 pip ins...
    99+
    2023-02-28
    pandas Excel批量转换时间戳 pandas 转换时间戳
  • pandas读取Excel批量转换时间戳怎么实现
    这篇文章主要介绍“pandas读取Excel批量转换时间戳怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“pandas读取Excel批量转换时间戳怎么实现”文章能帮助大家解决问题。一、安装pi...
    99+
    2023-07-05
  • pandas 读取excel文件的操作代码
    目录一 read_excel() 的基本用法二 read_excel() 的常用的参数:三 示例1. IO:路径2. sheet_name:指定工作表名3. header :指定标题...
    99+
    2022-11-12
  • 用Python的pandas读取excel文件中的数据
    一、前言 hello呀!各位铁子们大家好呀,今天呢来和大家聊一聊用Python的pandas读取excel文件中的数据。 二、读取Excel文件 使用pandas的read_excel()方法,可通过文件路径直接读取。注意到,在一个exce...
    99+
    2023-09-01
    python excel 软件测试 自动化测试 测试工程师
  • PHP 转换 excel中读取的时间
    首先,我们需要知道PHPExcel的时间和日期格式是以Excel内部的“1900年1月1日”为基础,以天为单位来计算的。即Excel日期与PHP时间戳之间存在一个时间偏移量。通过查阅PHPExcel的...
    99+
    2023-09-08
    excel
  • Pandas实现Excel文件读取,增删,打开,保存操作
    目录前言一、Pandas 的主要函数包括二、使用步骤1.简单示例2.保存Excel操作3.删除和添加数据4.添加新的表单前言 Pandas 是一种基于 NumPy 的开源数据分析工具...
    99+
    2023-05-15
    Pandas读取Excel Pandas打开Excel Pandas增删Excel Pandas保存Excel Pandas Excel
  • python如何实现读取excel表格
    本篇内容介绍了“python如何实现读取excel表格”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、python读取excel表格数据1...
    99+
    2023-07-02
  • Pandas数据集的分块读取的实现
    目录一、直接用分块方式读取数据集文件(更直接)二、先将数据集读取为可迭代对象,再分块读取(更灵活)总结所谓“分块”,顾名思义,就是将数据集分成几块进行读取,比...
    99+
    2022-11-11
  • java读取文件进度条怎么实现
    要实现Java读取文件进度条,你可以使用Java的FileInputStream类来读取文件,并通过在读取文件时更新进度条来显示进度...
    99+
    2023-09-01
    java
  • Java怎么实现文件读取进度条
    要实现文件读取的进度条,可以使用java.io包中的FileInputStream类和BufferedInputStream类来读取...
    99+
    2023-08-17
    Java
  • java怎么实现读取文件进度条
    要实现读取文件的进度条,可以使用Java的FileInputStream来读取文件,然后通过获取文件的大小和当前读取的字节数来计算读...
    99+
    2023-08-20
    java
  • Python实现读取json文件到excel表
    本文实例为大家分享了Python实现读取json文件到excel表,供大家参考,具体内容如下 一、需求 1、'score.json' 文件内容: { "1":["小花",99,100,98.5], ...
    99+
    2022-06-04
    文件 Python json
  • Java利用poi读取Excel详解实现
    目录前言第一步导入依赖第二步实现测试类+测试实际应用前言 用户可以直接读取本地文件,也可以通过上传文件的形式读取excel 注意:poi对于读取到空白行的时候,会默认的认为是最后一行...
    99+
    2022-11-13
  • Java文件读取的进度条怎么实现
    本文小编为大家详细介绍“Java文件读取的进度条怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java文件读取的进度条怎么实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。运行截图相关代码读取文件类pa...
    99+
    2023-07-05
  • PHP实现读取Excel文件的记录(一)
    因为工作需要将Excel的文件记录读出再写入数据库中,之前使用的是VBS,可是那也不是正规的应用程序,使用PowerBuilder也可以,但是PowerBuilder毕竟只是临时使用...
    99+
    2022-11-13
  • PHP实现读取Excel文件的记录(二)
    《PHP实现读取Excel文件的记录(一)》 中有在PHP中读取Excel的例子,有些麻烦,因为必须要加载很多的文件。 应该有ODBC的读取方法,还没有试,今天的方法简单了...
    99+
    2022-11-13
  • Python实现读取excel中的图片功能
    目录一、读取excel文件二、读取excel中的图片(1)使用zipfile模块(2)使用openpyxl读取三、对读取的图片进行处理补充一、读取excel文件 我们先来看看如何读取...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作