最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

pandas讀取excel時獲取讀取進(jìn)度的實(shí)現(xiàn)

 更新時間:2021年04月14日 08:58:01   作者:THUNDER  
這篇文章主要介紹了pandas讀取excel時獲取讀取進(jìn)度的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

寫在前面

QQ群里偶然看到群友問這個問題, pandas讀取大文件時怎么才能獲取進(jìn)度? 我第一反應(yīng)是: 除非pandas的read_excel等函數(shù)提供了回調(diào)函數(shù)的接口, 否則應(yīng)該沒辦法做到. 搜索了一下官方文檔和網(wǎng)上的帖子, 果然是沒有現(xiàn)成的方案, 只能自己動手.

準(zhǔn)備工作

確定方案

一開始我就確認(rèn)了實(shí)現(xiàn)方案, 那就是增加回調(diào)函數(shù). 這里現(xiàn)學(xué)現(xiàn)賣科普一下什么是回調(diào)函數(shù). 簡單的說就是:

所使用的模塊里面, 會調(diào)用一個你給定的外部方法/函數(shù), 就是回調(diào)函數(shù). 拿本次的嘗試作為例子, 我會編寫一個"顯示進(jìn)度函數(shù)", 通過傳參的方式傳入pd.read_excel, 這樣pd在讀取excel時, 會邊讀取邊調(diào)用"顯示進(jìn)度函數(shù)". 為什么不直接在pd里面增加? 因?yàn)閜d讀取excel文件時是阻塞的, 內(nèi)部方法在被調(diào)用時無法拋出進(jìn)度信息. (如有謬誤請指正)

理解讀取方式

先得了解一下pandas是怎么讀取excel的. 在pycharm里面按住control點(diǎn)擊read_excel, 再瀏覽一下代碼根據(jù)關(guān)鍵的函數(shù)繼續(xù)跳轉(zhuǎn), 還是挺容易得到調(diào)用的路徑的.

在這里插入圖片描述

最后OpenpyxlReader讀取excel的方法代碼如下. 很明顯重點(diǎn)就在其中的for循環(huán)里. 調(diào)用get_sheet_data時, 已經(jīng)通過一系列方法獲得了目標(biāo)sheet(這里細(xì)節(jié)不贅述), 然后在for循環(huán)里逐行讀取數(shù)據(jù)并返回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庫源文件!(僅用于調(diào)試, 注意備份和保護(hù)自己的工作環(huán)境)

主程序代碼

編寫main.py, 代碼比較簡單, 相關(guān)功能我都用注釋作為解釋. 其中show_pd_read_excel_progress就是我編寫的回調(diào)函數(shù), 通過命令行的方式輸出實(shí)時的讀取進(jìn)度. 當(dāng)然你如果編寫的是GUI程序比如PYQT5, 也可以在這個回調(diào)函數(shù)中發(fā)送signal給main UI, 做成progress bar或者其他的GUI樣式.

import pandas as pd
from datetime import datetime

'''
定義回調(diào)函數(shù)
cur: 讀取時的當(dāng)前行數(shù)
tt: 讀取文件的總行數(shù)
'''
def show_pd_read_excel_progress(cur, tt):
    # 進(jìn)度數(shù)值
    progress = " {:.2f}%".format(cur/tt*100)
    # 進(jìn)度條
    bar = " ".join("█" for _ in range(int(cur/tt*100/10)))
    # 顯示進(jìn)度
    print("\r進(jìn)度:" + 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")
# 顯示花費(fèi)的時間
print("Time spent:", datetime.now()-t)

修改pandas源碼

再自己觀察一下, 我在pd.read_excel方法的參數(shù)里增加了callback參數(shù), 這個參數(shù)是原版read_excel方法里沒有的. 所以我們需要處理pandas源碼, 這個源碼在…/pandas/io/excel/_base.py中, pycharm中按住control點(diǎn)擊read_excel可以快速跳轉(zhuǎn). 這個地方我增加了一個參數(shù)callback, 默認(rèn)值為None. 下方io.parse同樣把callback參數(shù)傳遞給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參數(shù)
):

    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參數(shù)
        )
    finally:
        # make sure to close opened file handles
        if should_close:
            io.close()
    return data
... # 省略代碼

瀏覽一下ExcelFile類(還在_base.py中)的代碼, 這個類會根據(jù)文件類型選擇引擎, 我讀取的是xlsx文件, 所以會跳轉(zhuǎn)到openpyxl并把所有的參數(shù)傳遞過去, 這個類不用處理. 下面跳轉(zhuǎn)到_openpyxl.py中看一下OpenpyxlReader類, 這個類是繼承BaseExcelReader類(在_base.py中)的, 所以還是得回去看一下BaseExcelReader, 并修改一下參數(shù), 增加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參數(shù)
        **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參數(shù)給get_sheet_data方法
            usecols = maybe_convert_usecols(usecols)
... # 省略代碼

好了, 終于到重點(diǎn)了, 我們跳轉(zhuǎn)到get_sheet_data方法, 并做對應(yīng)修改(方法參數(shù), 獲取總行數(shù), 調(diào)用回調(diào)函數(shù)). 思路非常清晰, 通過一頓操作, 終于千里迢迢把callback給一層層傳遞過來了, 所以在一行行讀取excel時, 可以調(diào)用并顯示進(jìn)度了.

def get_sheet_data(self, sheet, convert_float: bool, callback) -> List[List[Scalar]]: # 傳遞參數(shù)增加callback
        # GH 39001
        # Reading of excel file depends on dimension data being correct but
        # writers sometimes omit or get it wrong
        import openpyxl
				# 獲取sheet的總行數(shù)
        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):
						# 調(diào)用回調(diào)函數(shù)
            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

運(yùn)行測試

運(yùn)行一下main.py, 效果如下, 實(shí)時顯示進(jìn)度功能已經(jīng)實(shí)現(xiàn), 且會計算出讀取所花費(fèi)的時間. 如果你是要讀取csv或者sql之類的, 也可以照貓畫虎.

在這里插入圖片描述

優(yōu)化和應(yīng)用

  • 前面也說過直接修改pandas源碼是非常不科學(xué)的操作, 這會破壞已有的編程環(huán)境, 且源碼換到別的機(jī)器上還得重新在修改一遍
  • 也嘗試過用繼承+重寫pandas, 不過水平有限沒有成功, 希望大家指點(diǎn)
  • 實(shí)測print進(jìn)度條會非常費(fèi)時間, 當(dāng)然也不需要每讀一行excel都更新一次進(jìn)度條, 定時(比如每秒刷一次)或者定量(每n行, 或者每1%進(jìn)度刷新一次)比較合理
  • 讀取大規(guī)模數(shù)據(jù)時, 頻繁調(diào)用回調(diào)函數(shù)肯定會耽誤效率, 不過如果是GUI程序或者給其他人使用的, 有實(shí)時進(jìn)度肯定會改善用戶體驗(yàn), 其中優(yōu)劣需要coder自己權(quán)衡

到此這篇關(guān)于pandas讀取excel時獲取讀取進(jìn)度的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)pandas讀取excel讀取內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python 讀取串口數(shù)據(jù)的示例

    python 讀取串口數(shù)據(jù)的示例

    這篇文章主要介紹了python 讀取串口數(shù)據(jù)的示例,幫助大家更好的理解和使用python,感興趣的朋友可以了解下
    2020-11-11
  • Python可變對象與不可變對象原理解析

    Python可變對象與不可變對象原理解析

    這篇文章主要介紹了Python可變對象與不可變對象原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02
  • Python?中的?Counter?模塊及使用詳解(搞定重復(fù)計數(shù))

    Python?中的?Counter?模塊及使用詳解(搞定重復(fù)計數(shù))

    Counter 是一個簡單的計數(shù)器,用于統(tǒng)計某些可哈希對象的數(shù)量。它以字典的形式存儲元素和它們的計數(shù),這篇文章主要介紹了Python?中的?Counter?模塊及使用詳解(搞定重復(fù)計數(shù)),需要的朋友可以參考下
    2023-04-04
  • Python+OpenCV實(shí)現(xiàn)信用卡數(shù)字識別的方法詳解

    Python+OpenCV實(shí)現(xiàn)信用卡數(shù)字識別的方法詳解

    這篇文章主要介紹了如何利用python?opencv實(shí)現(xiàn)信用卡數(shù)字識別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-09-09
  • 基于Python實(shí)現(xiàn)本地音樂播放器的制作

    基于Python實(shí)現(xiàn)本地音樂播放器的制作

    這篇文章主要介紹了如何利用Python實(shí)現(xiàn)本地音樂播放器的制作,并且可以選擇需要播放的音樂的路徑,選擇播放方式,感興趣的小伙伴可以了解一下
    2022-06-06
  • 運(yùn)用Python巧妙處理Word文檔的方法詳解

    運(yùn)用Python巧妙處理Word文檔的方法詳解

    大家平時在工作與學(xué)習(xí)中都會操作到Word文件格式,特別是很多數(shù)據(jù)的時候,靠人力去識別操作非常容易出錯。今天就帶大家用python來處理Word文件,感興趣的可以了解一下
    2022-05-05
  • 基于PyTorch的permute和reshape/view的區(qū)別介紹

    基于PyTorch的permute和reshape/view的區(qū)別介紹

    這篇文章主要介紹了基于PyTorch的permute和reshape/view的區(qū)別介紹,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-06-06
  • Pycharm及python安裝詳細(xì)步驟及PyCharm配置整理(推薦)

    Pycharm及python安裝詳細(xì)步驟及PyCharm配置整理(推薦)

    這篇文章主要介紹了Pycharm及python安裝詳細(xì)步驟以及PyCharm配置整理,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-04-04
  • Python CSV文件模塊的使用案例分析

    Python CSV文件模塊的使用案例分析

    這篇文章主要介紹了Python CSV文件模塊的使用,結(jié)合具體案例形式分析了Python使用csv模塊操作csv文件的相關(guān)使用技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2019-12-12
  • python根據(jù)完整路徑獲得盤名/路徑名/文件名/文件擴(kuò)展名的方法

    python根據(jù)完整路徑獲得盤名/路徑名/文件名/文件擴(kuò)展名的方法

    這篇文章主要介紹了python根據(jù)完整路徑獲得盤名,路徑名,文件名,文件擴(kuò)展名的代碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-04-04

最新評論

巍山| 高平市| 五家渠市| 浪卡子县| 自治县| 沭阳县| 井研县| 南宫市| 宁远县| 塔城市| 遂宁市| 渭南市| 平陆县| 昌图县| 突泉县| 九台市| 昌平区| 额济纳旗| 长岭县| 永修县| 靖安县| 安福县| 伊春市| 朝阳区| 乐至县| 焦作市| 静乐县| 揭东县| 连江县| 道真| 湘乡市| 依安县| 新兴县| 古田县| 喀什市| 郧西县| 高邑县| 临颍县| 南木林县| 定远县| 普宁市|