iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >利用Python解决Excel问题的最佳方案总结
  • 211
分享到

利用Python解决Excel问题的最佳方案总结

python excelpython处理excel 2023-05-15 08:05:42 211人浏览 安东尼

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

摘要

目录「问题说明」「方案1」「方案2」「写在最后」「问题说明」 这次要处理的excel有两个sheet,要根据其中一个sheet的数据来计算另外一个sheet的值。造成问题的点在于,要

「问题说明」

这次要处理的excel有两个sheet,要根据其中一个sheet的数据来计算另外一个sheet的值。造成问题的点在于,要计算值的sheet里不仅仅有数值,还有公式。我们来看一下:

如上图所示,这个excel一共有两个sheet:CP和DS,我们要按照一定的业务规则,根据CP中的数据计算DS对应单元格的数据。图中蓝色方框框出来的是带公式的,而其他区域是数值。

我们来看看,如果我们按照之前说的处理逻辑,把excel一次性批量读取到dataframe处理,然后再一次性批量写回去有啥问题。这部分代码如下:

import pandas as pd
import xlwings as xw
 
#要处理的文件路径
fpath = "data/DS_fORMat.xlsm"
 
#把CP和DS两个sheet的数据分别读入pandas的dataframe
cp_df = pd.read_excel(fpath,sheet_name="CP",header=[0])
ds_df = pd.read_excel(fpath,sheet_name="DS",header=[0,1])
 
#计算过程省略......
 
#保存结果到excel       
app = xw.App(visible=False,add_book=False)
ds_format_workbook = app.books.open(fpath)
ds_worksheet = ds_format_workbook.sheets["DS"]
ds_worksheet.range("A1").expand().options(index=False).value = ds_df 
ds_format_workbook.save()
ds_format_workbook.close()
app.quit()

如上代码存在的问题在于,pd.read_excel()方法从excel里读取数据到dataframe的时候,对于有公式的单元格,会直接读取公式计算的结果(如果没有结果则返回Nan),而我们写入excel的时候是直接把dataframe一次性批量写回的,这样之前带公式的单元格,被写回的就是计算出来的值或Nan,而丢掉了公式。

好了,问题出现了,我们该如何解决呢?这里会想到两个思路:

  • dataframe写回excel的时候,不要一次性批量写回,而是通过行和列的迭代,只写回计算的数据,有公式的单元格不动;
  • 读取excel的时候,有没有办法做到对于有公式的单元格,读取公式,而不是读取公式计算的结果;

我确实按照上面两个思路分别尝试了一下,我们一起来看一下。

「方案1」

如下代码尝试遍历dataframe然后按单元格写入对应的值,有公式的单元格不动

#根据ds_df来写excel,只写该写的单元格
for row_idx,row in ds_df.iterrows():
    total_capabity_val = row[('Total','Capabity')].strip()
    total_capabity1_val = row[('Total','Capabity.1')].strip()
    #Total和1Gb  Eqv.所在的行不写
    if total_capabity_val!= 'Total' and total_capabity_val != '1Gb  Eqv.':
        #给Delta和LOI赋值
        if total_capabity1_val == 'LOI' or total_capabity1_val == 'Delta':
            ds_worksheet.range((row_idx + 3 ,3)).value = row[('Current week','BOH')]
            print(f"ds_sheet的第{row_idx + 3}行第3列被设置为{row[('Current week','BOH')]}") 
        #给Demand和Supply赋值
        if total_capabity1_val == 'Demand' or total_capabity1_val == 'Supply':
            cp_datetime_columns = cp_df.columns[53:]
            for col_idx in range(4,len(ds_df.columns)):
                ds_datetime = ds_df.columns.get_level_values(1)[col_idx]
                ds_month = ds_df.columns.get_level_values(0)[col_idx]
                if type(ds_datetime) == str and ds_datetime != 'TTL' and ds_datetime != 'Total' and (ds_datetime in cp_datetime_columns):
                    ds_worksheet.range((row_idx + 3,col_idx + 1)).value = row[(f'{ds_month}',f'{ds_datetime}')]
                    print(f"ds_sheet的第{row_idx + 3}行第{col_idx + 1}列被设置为{row[(f'{ds_month}',f'{ds_datetime}')]}") 
                elif type(ds_datetime) == datetime.datetime and (ds_datetime in cp_datetime_columns):
                    ds_worksheet.range((row_idx + 3,col_idx + 1)).value = row[(f'{ds_month}',ds_datetime)]     
                    print(f"ds_sheet的第{row_idx + 3}行第{col_idx + 1}列被设置为{row[(f'{ds_month}',ds_datetime)]}")   

如上的代码确实解决了问题,也即有公式的单元格的公式被保留了。但是,根据我们文章开头提到的python处理excel的忠告,这个代码是有严重性能问题的,因为它通过api频繁操作excel的单元格,导致写入非常慢,在我的老迈Mac本上一共跑了40分钟,简直不可接受,故该方案只能放弃。

「方案2」

这个方案是希望做到读取excel有公式值的单元格的时候,能保留公式值。这只能从各个Python的excel库的API来寻找有无对应的方法了。Pandas的read_excel()方法我仔细看了一下没有对应的参数可以支持。Openpyxl我倒是找到了一个API可以支持,如下:

import openpyxl
ds_format_workbook = openpyxl.load_workbook(fpath,data_only=False)
ds_wooksheet = ds_format_workbook['DS']
ds_df =  pd.DataFrame(ds_wooksheet.values)

关键是这里的data_only参数,为True则返回数据,为False的情况下可以保留公式值

本以为找到了对应解决方案正一顿窃喜,但当我看到通过openpyxl读取到dataframe中的数据结构的时候,才被破了一盆冷水。因为我的excel表的表头是比较复杂的两级的表头,表头中还存在合并和拆分单元格的情况,这样的表头被openpyxl读取到dataframe后,没有按照pandas的多级索引进行处理,而是简单的被处理成数字索引0123...

但我对dataframe的计算会依赖多级索引,因此openpyxl的这种处理方式导致我后面的计算无法处理。

openpyxl不行,再看看xlwings呢?通过对xlwings API文档的一通寻找,还真给我找到了,如下所示:

Range类提供了一个Property叫formula,可以获取和设置formula。

看到这个我简直如获至宝,赶紧代码操练起来。也许出于惯性,又或许是被之前按行列单元格操作excel的效率搞怕了,我直接先想到的方案还是一次性批量搞定,也即一次性读取excel所有的公式,然后再一次性写回去,所以我一开始的代码是这样的:

#使用xlwings来读取formula
app = xw.App(visible=False,add_book=False)
ds_format_workbook = app.books.open(fpath)
ds_worksheet = ds_format_workbook.sheets["DS"]
#先把所有公式一次性读取并保存下来
formulas = ds_worksheet.used_range.formula
 
#中间计算过程省略...
 
#一次性把所有公式写回去
ds_worksheet.used_range.formula = formulas 

可是我想错了,ds_worksheet.used_range.formula让我误解只会返回excel中的有公式的单元格的公式,但其实它返回的是所有的单元格,只是对有公式的单元格保留了公式。所以,当我重新写回公式的时候,会覆盖掉我通过dataframe计算完并写入excel的其他的值。

既然这样的话,那我只能对有公式的单元格分别处理而不是一次性处理了,所以代码得这样写:

#使用xlwings来读取formula
app = xw.App(visible=False,add_book=False)
ds_format_workbook = app.books.open(fpath)
ds_worksheet = ds_format_workbook.sheets["DS"]
 
#保留excel中的formula
#找到DS中Total所在的行,Total之后的行都是formula
row = ds_df.loc[ds_df[('Total','Capabity')]=='Total ']
total_row_index = row.index.values[0]
#获取对应excel的行号(dataframe把两层表头当做索引,从数据行开始计数,而且从0开始计数。excel从表头就开始计数,而且从1开始计数)
excel_total_row_idx = int(total_row_index+2)
#获取excel最后一行的索引
excel_last_row_idx = ds_worksheet.used_range.rows.count
#保留按日期计算的各列的formula
I_col_formula = ds_worksheet.range(f'I3:I{excel_total_row_idx}').formula
N_col_formula = ds_worksheet.range(f'N3:N{excel_total_row_idx}').formula
T_col_formula = ds_worksheet.range(f'T3:T{excel_total_row_idx}').formula
U_col_formula = ds_worksheet.range(f'U3:U{excel_total_row_idx}').formula
Z_col_formula = ds_worksheet.range(f'Z3:Z{excel_total_row_idx}').formula
AE_col_formula = ds_worksheet.range(f'AE3:AE{excel_total_row_idx}').formula
AK_col_formula = ds_worksheet.range(f'AK3:AK{excel_total_row_idx}').formula
AL_col_formula = ds_worksheet.range(f'AL3:AL{excel_total_row_idx}').formula
#保留Total行开始一直到末尾所有行的formula
total_to_last_formula = ds_worksheet.range(f'A{excel_total_row_idx+1}:AL{excel_last_row_idx}').formula
 
#中间计算过程省略...
 
#保存结果到excel                 
#直接把ds_df完整赋值给excel,会导致excel原有的公式被值覆盖
ds_worksheet.range("A1").expand().options(index=False).value = ds_df 
#用之前保留的formulas,重置公式
ds_worksheet.range(f'I3:I{excel_total_row_idx}').formula = I_col_formula
ds_worksheet.range(f'N3:N{excel_total_row_idx}').formula = N_col_formula
ds_worksheet.range(f'T3:T{excel_total_row_idx}').formula = T_col_formula
ds_worksheet.range(f'U3:U{excel_total_row_idx}').formula = U_col_formula
ds_worksheet.range(f'Z3:Z{excel_total_row_idx}').formula = Z_col_formula
ds_worksheet.range(f'AE3:AE{excel_total_row_idx}').formula = AE_col_formula
ds_worksheet.range(f'AK3:AK{excel_total_row_idx}').formula = AK_col_formula
ds_worksheet.range(f'AL3:AL{excel_total_row_idx}').formula = AL_col_formula
ds_worksheet.range(f'A{excel_total_row_idx+1}:AL{excel_last_row_idx}').formula = total_to_last_formula
 
ds_format_workbook.save()
ds_format_workbook.close()
app.quit()

测试,如上代码完美地解决我的需求,而且性能上也完全没问题。

「写在最后」

通过这几次用Python对Excel进行处理的实践,让我深刻感觉到,Pandas用于对Excel数据的高效内存计算是很不错的,但涉及到对Excel的读写以及一些跟样式、格式相关的操作,还是得依赖xlwings或openpyxl等其他库来完成,因此,在用Python处理Excel的场景,最佳方案是将Pandas和xlwings或openpyxl等库结合起来一起使用是最佳组合。

到此这篇关于利用Python解决Excel问题的文章就介绍到这了,更多相关Python解决Excel问题内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 利用Python解决Excel问题的最佳方案总结

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

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

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

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

下载Word文档
猜你喜欢
  • 利用Python解决Excel问题的最佳方案总结
    目录「问题说明」「方案1」「方案2」「写在最后」「问题说明」 这次要处理的excel有两个sheet,要根据其中一个sheet的数据来计算另外一个sheet的值。造成问题的点在于,要...
    99+
    2023-05-15
    python excel python处理excel
  • 用Python解决Excel问题的最佳姿势
     大家好,我是毕加锁。 今天给大家带来的是用Python解决Excel问题的最佳姿势 文末送书! 文末送书! 文末送书! 「问题说明」 这次要处理的excel有两个sheet,要根据其中一个sheet的数据来计算另外一个sheet的值。造...
    99+
    2023-09-03
    pandas python excel
  • 解决Pandas生成Excel时的sheet问题的方法总结
    目录楔子同时导入多个 sheet覆盖一个 sheet楔子 估计有不少小伙伴在将 DataFrame 导入到 Excel 的时候,都遇到过下面这种尴尬的情况: 想将多个 DataFra...
    99+
    2024-04-02
  • 解决Mac安装win7蓝屏问题最佳方案
    轻松解决MACbook Air双系统蓝屏问题 本人最近为解决Mac安装Windows7的蓝屏问题在网络上遍寻各类方案,发现大家说法各异,不尽相同,有些方法颇为复杂,为了让以后诸君遇此问题能轻松摆平,特将本人亲身体会分享之...
    99+
    2023-06-01
    win7蓝屏 Mac 方案 问题 蓝屏
  • K3问题总结和解决方法
    一、问题描述 客户端运行,提示:该数据正在被修改,无法编辑? 解决方法1、关闭杀毒软件; 2、用KDMAINDBG.EXE跟踪检测组件; 3、在数据库的该套帐实体中的表中清空t-funcontrol的内容 二、问题描述1...
    99+
    2023-01-31
    解决方法
  • JS利用循环解决的一些常见问题总结
    目录1. 打印0-100中3的倍数2. 在页面中写入 1000-2000年中的闰年3. 打印100以内所有偶数的和4.求出1-1/2+1/3-1/4……1...
    99+
    2024-04-02
  • 【总结】sublime写PHP遇到的常见问题及解决方案
    Sublime Text是一款功能丰富的文本编辑器,它被广泛使用来编写各种编程语言的代码。然而,一些PHP开发者有时遇到了一些问题,他们发现Sublime Text可能对PHP不太管用。这令人感到困惑:为什么这个备受喜爱的编辑器在处理PHP...
    99+
    2023-05-14
    php sublime
  • ASP 重定向:最佳实践和常见问题解决方案。
    ASP 重定向:最佳实践和常见问题解决方案 重定向是 Web 开发中常用的技术之一。重定向可以将一个页面或资源的请求转发到另一个 URL,通常是因为原始 URL 无效或需要跳转到其他页面。在 ASP 中,重定向是通过 Response.Re...
    99+
    2023-10-27
    重定向 打包 面试
  • PHPcms整合问题解决方案汇总
    标题:PHPcms整合问题解决方案汇总,需要具体代码示例 在网站开发中,PHPcms是一个常用的内容管理系统,但在实际整合过程中会遇到各种问题。本文将汇总常见的PHPcms整合问题,并...
    99+
    2024-03-14
    解决方案 php cms
  • Oracle常见问题解决方案汇总
    1、Oracle 11g ORA-12514:TNS:监听程序当前无法识别连接描述符中请求的服务 数据库服务器崩了,而且尝试重启服务和重启机器都解决不了问题 打开cmd窗口 C:\Users\hxt&g...
    99+
    2024-04-02
  • SpringBoot前后端分离解决跨域问题的3种解决方案总结
    目录什么是跨域跨域问题的解决策略三种解决方法总结什么是跨域 想要知道什么是跨域的话,我们可以通过一个小案例简单了解一下跨域的概念:在项目代码编写的时候,我们将前端项目代码和后端的项目...
    99+
    2024-04-02
  • Go语言编程的最佳实践和常见问题解决方案
    在当今互联网高速发展的时代,编程语言的选择至关重要。Go语言作为一种快速、高效、易于学习和使用的编程语言,受到了越来越多开发者的青睐。然而,虽然Go语言具有许多优点,但在实际开发中也会...
    99+
    2024-03-01
    实践 go语言 问题解决
  • 利用Jacob将Excel转换PDF的问题汇总
    目录前言问题一、Excel数据列较多时,PDF中列打印不全,问题二、大量数据时,PDF页模糊解决总结前言 好久不见,分享一个近期在项目开发中遇到的一个新问题,关于使用easyexce...
    99+
    2024-04-02
  • 怎么用Python解决Excel问题
    本篇内容介绍了“怎么用Python解决Excel问题”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!「问题说明」这次要处理的excel有两个s...
    99+
    2023-07-06
  • Git分支管理:最佳实践和常见问题解决方案
    Git是目前最流行的版本控制系统之一,它提供了强大的分支管理功能,使得多人协作开发变得更加高效。本文将介绍Git分支管理的最佳实践和常见问题解决方案。 一、分支管理的基础知识 在Git中,分支是指指向某个提交对象的指针,它们可以在不同的提...
    99+
    2023-11-12
    django http git
  • Python重定向npm日志:解决日志问题的最佳方法?
    如果你使用过npm,你可能会遇到日志输出问题。npm将所有的日志都输出到控制台,而不是将其记录到文件中。这可能会导致在处理大型项目时,日志信息过多而难以捕捉。为了解决这个问题,我们可以使用Python来重定向npm的日志输出。 在Pyth...
    99+
    2023-06-19
    重定向 日志 npm
  • 解决java.sql.SQLException: validateConnection false问题的方法汇总(最全)
    目录现象解决方案1(治标不治本)解决方案2解决方案3总结现象 由空指针导致的validateConnection false 解决方案1(治标不治本) 解决方案1(治标不治本): ...
    99+
    2023-03-06
    java.sql.sqlexception java.sql.sqlexception报错
  • Python 和 JavaScript:Windows 同步的最佳解决方案是什么?
    在当今科技发展的时代,计算机已经成为人们日常生活中不可或缺的工具。而其中最为重要的两个编程语言,Python 和 JavaScript,已经成为众多开发者的首选。但是,在 Windows 操作系统下,Python 和 JavaScript...
    99+
    2023-09-09
    javascript windows 同步
  • 解决Oracle提示乱码问题的方法总结
    解决Oracle提示乱码问题的方法总结 在使用Oracle数据库时,经常会遇到数据存储或查询过程中出现乱码的情况,这给数据操作和结果展示带来了困扰。造成乱码问题的主要原因是数据库字符集...
    99+
    2024-03-08
    数据类型选择 编码设置 字符集调整
  • Python 和 Apache:解决路径同步问题的最佳组合?
    在开发 Web 应用程序时,路径同步是一个常见的问题,特别是在使用 Apache 作为 Web 服务器时。通常情况下,开发人员需要确保应用程序和服务器的文件路径匹配,否则可能会导致应用程序无法正常运行。为了解决这个问题,许多开发人员转向 ...
    99+
    2023-09-29
    apache path 同步
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作