用Python写一个Excel汇总和比对小程序

文章目录

  • 用Python写一个Excel汇总和比对小程序
  • 前言
  • 一、错误思路
  • 二、使用Pandas的矢量化操作加速
    • 1.先明白pandas处理大型数据集的一些经验法则
    • 2.正确的比对思路
      • 1. 首先我们需要清楚要找出的不一样的内容包括哪些
      • 2.得到两个表之间的交集、差集
      • 3.重点:【唯一标识码】相同部分怎么判断里面内容是否发生变化
        • 1.举个例子
        • 2.对两个表的列名进行处理
        • 3.将两个表进行横向合并
        • 4.通过dataframe直接进行相同列名的数据比对
        • 5.数据的写入
  • 源码下载

前言

最近由于工作需要,要多次比对两张Excel表里面的内容变化(有相同的行列索引),并将变化的单元格标注出来,所以想自己写个比对程序出来。
         虽然网上有类似工具,Python也有company库用来比对,但是都不怎么符合我的要求,索引还是自己写一个。这里我不详细介绍所有代码,重点介绍一下比对的思路和开发过程中遇到的一些坑。

一、错误思路

我需要的是比对每一个单元格里面的内容是否发生变化,所以一开始我的想法就是根据行列索引遍历每个单元格进行比对,就像下面这样:

import openpyxl
import timewb1 = openpyxl.load_workbook("./cs/1.xlsm")
wb2 = openpyxl.load_workbook("./cs/2.xlsm")sheet1 = wb1.active
sheet2 = wb2.activenrows = sheet1.max_row
ncols = sheet1.max_column
print(nrows)
print(ncols)num = 1start = time.time()
for row in range(1,nrows):for col in range(1,ncols):if sheet1.cell(row,col).value == sheet2.cell(row,col).value: #这里两张表是复制的,所以用相等# print("旧:%s---新:%s"%(sheet1.cell(row,col).value,sheet2.cell(row,col).value)) passprint(num)num += 1
print(time.time()-start)


         我用的Excel表数据是3000行32列的,可以看出总共遍历循环96000次,用时1s多,但是我每次比对数据至少在120000条左右,也就是说我光循环比对至少40s左右,这还不算读取和最后写入的时间,效率太低。
         而且,这种方法还要一个前提,我必须提前将数据表处理好,使每一行都相互对应,如果出现新增和删减就没法得出结果,所有这种方法显然行不通。

二、使用Pandas的矢量化操作加速

1.先明白pandas处理大型数据集的一些经验法则

  • 尝试尽可能使用矢量化操作,而不是在df 中解决for x的问题。如果你的代码是许多for循环,那么它可能更适合使用本机Python数据结构,因为Pandas会带来很多开销。
  • 如果你有更复杂的操作,其中矢量化根本不可能或太难以有效地解决,请使用.apply方法。
  • 如果必须循环遍历数组(确实发生了这种情况),请使用.iterrows()或.itertuples()来提高速度和语法。
  • Pandas有很多可选性,几乎总有几种方法可以从A到B。请注意这一点,比较不同方法的执行方式,并选择在项目环境中效果最佳的路线。
  • 一旦建立了数据清理脚本,就可以通过使用HDFStore存储中间结果来避免重新处理。
  • 将NumPy集成到Pandas操作中通常可以提高速度并简化语法。

这里建议去看看《还在抱怨pandas运行速度慢?这几个方法会颠覆你的看法》这篇文章,对pandas 使用有很大启发。

2.正确的比对思路

1. 首先我们需要清楚要找出的不一样的内容包括哪些

这里假如有新旧两个表,且这两个表中的列名完全一致,也都有相同的行索引【唯一标识码】,相同的【唯一标识码】对应相同的数据。


因为涉及到增加和减少,那么两个表中就可能出现三种情况:

  • 数据减少了,那么旧表有新表没有的【唯一标识码】
  • 数据增加了,那么新表有旧表没有的【唯一标识码】
  • 【唯一标识码】相同的数据,里面内容发生变化了

2.得到两个表之间的交集、差集

import pandas as pd
import timedf1 = pd.read_excel("./cs/1.xlsm",index_col="唯一标识码")
df2 = pd.read_excel("./cs/2.xlsm",index_col="唯一标识码")#将【唯一标识码】列设置为索引
df1.index = df1["唯一标识码"]
df2.index = df2["唯一标识码"]index1 = df1.index
index2 = df2.indexjiaoJi = list(set(index1).intersection(set(index2)))  #两个列表中相同的项
chaJi1 = list(set(index1).difference(set(index2)))    #旧表不同于新表的数据,既旧表有,新表没有
chaJi2 = list(set(index2).difference(set(index1)))    #新表不同于旧表的数据,既新表有,旧表没有print(jiaoJi[:10])
print(chaJi1[:10])
print(chaJi2[:10])

1.xlsx表中【唯一标识码】从1-3000,2.xlsx表中【唯一标识码】从1501-4500。


得出差集1和差集2就可以很容易通过行索引得出新增和减少的数据了

df_chaji1 = df1.loc[chaJi1]
df_chaji2 = df2.loc[chaJi2]
print(df_chaji1)
print(df_chaji2)

3.重点:【唯一标识码】相同部分怎么判断里面内容是否发生变化

1.举个例子

这里先给大家举个简单的案列,这里有如下的表格数据,我们要找出列1和列2数据不同的地方

df = pd.read_excel("./test.xlsx",index_col="唯一标识码")
res = df["列1"] == df["列2"]
print(res)


大家可以发现,在dataframe数据可以直接使用列与列进行比较,返回bool值,很方便。
那么我们两个表中的数据怎么进行列与列的比较呢?

2.对两个表的列名进行处理

首先,我们将两个表的列名进行重设,表1的列名就是【列名-1】,表2的列名就是【列-2】

columns = df1.columns.tolist()
columns1 = list(map(lambda x: x+"-1",columns))
columns2 = list(map(lambda x: x+"-2",columns))df_jiaoji1 = df1.loc[jiaoJi]
df_jiaoji2 = df2.loc[jiaoJi]df_jiaoji1.columns = columns1
df_jiaoji2.columns = columns2print(df_jiaoji1)
print(df_jiaoji2)

3.将两个表进行横向合并

df_jiaoji_total = pd.concat([df_jiaoji1,df_jiaoji2],axis=1)  #axis=1表示横向合并
print(df_jiaoji_total[["分类编码-1","分类编码-2"]])


怎么样,看到这里知道我为什么要举上面的例子了把,就是为了能通过列直接比较。思路清楚了那就直接上代码:

4.通过dataframe直接进行相同列名的数据比对

start = time.time()
#比对所有同种类型的列的数据是否相等,得到一个bool值的series的迭代对象,并保存到ser_list列表中
ser_list = map(lambda x,y : df_jiaoji_total[x] == df_jiaoji_total[y] ,self.columns1,self.columns2)#将每个series转换成dataframe数据类型,并用最早的列名进行设置(也可以不用,但是为了方便观察结果还是设置)
df_list = map(lambda x,y : x.to_frame(y),ser_list,self.columns)#横向拼接所有的dataframe数据,数据为TRUE表示这个单元格比对结果相同,False表示不同
compare_df = pd.concat(df_list,axis=1)#过滤所有数据都是TRUE的行的索引值,表示比对后前后结果相同,不需要记录
compare_index = list(filter(lambda x : bool(1-all(compare_df.loc[x])) , compare_df.index))#根据最终得到的索引值可以确定哪些数据比对结果存在不同
#compare_bool用于定位哪些单元格出现差异
#compare_result则是存在差异的原始数据
self.compare_bool = compare_df.loc[compare_index]
self.compare_result = self.df2.loc[compare_index]#将compare_bool的行、列索引设置成序号类型,方便写入时定位单位元格位置
nrows = compare_bool.shape[0]
ncols = compare_bool.shape[1]
compare_bool.index = range(nrows)
compare_bool.columns = range(ncols)print(compare_bool)
print(compare_result)
print(time.time()-start)


大家可以很明显发现,遍历确定1500行31列的数据差异只需要0.25s,相较于之前的1.2s快了不知多少,而且在数据量越大的情况下越明显,有兴趣的可以测试一下。

5.数据的写入

这里我用openpyxl库来进行写入,主要是设置单元格格式比较简单,因为我们要将变化的数据的单元格填充为黄色

import openpyxl
from openpyxl.styles import PatternFill
start = time.time()
wb = openpyxl.Workbook()
ws_jiaoJi = wb.create_sheet("相同资产标识码内容发生变化",0)
# #创建单元格样式,填充为黄色,solid表示填充实色,不加不显示
fill = PatternFill("solid",fgColor="FFFF00")#先把列名写入
ws_jiaoJi.append(columns)#用compare_bool作为遍历对象,如果值为FALSE,表示数据发生变化了,单元格就填充为黄色
for i,r in compare_bool.iterrows():  for x,y in enumerate(r):if y == False:ws_jiaoJi.cell(row=i+2,column=x+1).fill = fill#用compare_result来遍历写入具体数据ws_jiaoJi.cell(row=i+2,column=x+1,value=compare_result.iloc[i,x])wb.save("./compare.xlsx")print(time.time()-start)


可以看到正确将比对结果输出为Excel表了


但这里不得不吐槽一下,写入的速度是真的慢,希望有高人指点一下可以怎么加快。
另外,如果大家还有更好的办法,希望可以不吝赐教。

源码下载

用Python写一个Excel汇总和比对小程序相关推荐

  1. 用python写一个圣诞互换礼物的抽奖小程序

    目的 最近和朋友们想玩圣诞互换礼物,但是没找到可以抽奖的小程序,所以我决定自己写一个. 游戏规则:参加游戏的人需要随机抽取一个幸运儿送一个礼物,但是注意不要抽到自己,并且不要重复抽同一个人. 思路 准 ...

  2. 用python写一个日语五十音记忆小程序qaq

    最近在B站自学日语~可能被英语洗脑太久了,感觉五十音图特别别扭超级难背qaq 朋友推荐了几个背单词软件都没有背五十音的,对零基础不太友好 自己写了一个感觉还挺好使 程序很简单,主要是没有日语输入法,要 ...

  3. python编写数据库连接工具_详解使用Python写一个向数据库填充数据的小工具(推荐)...

    一. 背景 公司又要做一个新项目,是一个合作型项目,我们公司出web展示服务,合作伙伴线下提供展示数据. 而且本次项目是数据统计展示为主要功能,并没有研发对应的数据接入接口,所有展示数据源均来自数据库 ...

  4. 基于Python编写一个B站全自动抽奖的小程序

    本文将利用Python编写一个B站全自动抽奖的小程序,可以实时监控自己关注的UP主,如果关注的UP主中有人发布了抽奖的动态,就自动参与这个抽奖.这样就能不错过任何一个可以暴富的机会了.需要的可以参考一 ...

  5. 写一个音乐播放器的微信小程序

    要创建一个音乐播放器的微信小程序,您需要熟悉微信小程序的开发环境和语言(如 JavaScript 和 WXML/WXSS). 具体来说,您需要做以下几件事: 设计音乐播放器的用户界面,并使用 WXML ...

  6. 手把手教你写一个没有服务器的颜值打分小程序,可直接上线

    小程序现在可以说非常火爆了,流量入口非常多.尤其是出了流量主功能以后,普通开发者也能在自己的个人小程序里植入官方广告来获取收入.程序员想赚点外快再合适不过了.今天教大家写一个颜值打分的小程序,利用现成 ...

  7. python 生成excel像素画_用python写一个excel画像素图脚本时所用到的一些库

    首先 ,想法源于在果壳网看到的一个用excel画一幅像素图的活动 思路很简单: 先将一张像素图的每个像素点的rgb值取出来 然后用脚本操作excel,将rgb设置为单元格的背景色 主要就在于两点 一. ...

  8. 关于如何使用Python写一个开机自动认证校园网的脚本程序

    有的学校有那个无感认证,有的学校没有,这个时候就可以自己动手丰衣足食,我学校就是只有手机才有无感认证,PC端是没有的,所以我就自己写了一个.(没有编程经验也可以,照着我的写就行) 首先,你需要安装好P ...

  9. 用python写一个简答的英文文章分析程序

    前言 本人是软件工程在校学生,萌新一枚,写此程序为了练习字符串处理函数.程序有bug,例如没法把文章中的数字处理掉,希望多多包涵,有什么改进的方法可以留言. 一.代码内容 filehandle=ope ...

  10. 用python画满天星花朵_如何使用python做一个可以画一朵花的小程序?

    这篇文章可以交给你怎么在windows或macOS与python3环境下做出一个可以根据你的自定义设置画出一朵花的程序. 在开始写正式的逻辑代码之前,我们要先导入一些库: from tkinter i ...

最新文章

  1. CodeGen准备存储库
  2. js中定义变量之②var let const的区别
  3. python好还是c+-JAVA,Python和C+各有什么特点和优势?
  4. 手把手教你如何写简历
  5. MySQL高级 - SQL优化 - 子查询优化
  6. 自建CA生成证书详解
  7. 国内博客(blog)搬家工具(服务)大全
  8. 为什么蓝牙一主多从能解决集中式水表抄表难题?
  9. php Y2K38 漏洞解决方法
  10. 思科交换机指示灯全解
  11. 学猫叫用计算机歌词,抖音学猫叫是什么歌 学猫叫歌曲歌词
  12. 科学计算机常用按键,电脑计算器里面的“科学型”的里面所有的按键的功能
  13. 安卓 输入框身份证号限制
  14. 华师大 OJ 3055
  15. 使用bootstrap制作简单的左侧导航栏
  16. THUSC 2017 游记
  17. 小米推迟上市和A股大跌,背后有什么共同原因?
  18. 欧几里得算法、扩展欧几里得算法(特解、应用、通解)
  19. 魔兽地图编辑器插件YDWE的使用与基本设置3之地形面板、装饰物面板、单位面板、区域面板、镜头面板
  20. UVA11292 The Dragon of Loowater

热门文章

  1. Jasper报表导出pdf中文不显示——Font simsun is not available to the JVM. See the Javadoc for more det,已解决
  2. 川师c语言实验报告9,川师c语言实验报告十.doc
  3. Eucalyptus简介
  4. tomcat常见漏洞
  5. SQL注入——判断注入
  6. 空调开关html,酒店墙上空调开关图解—酒店墙上空调开关图案是什么意思
  7. 阿里巴巴Java开发手册(2018-2021泰山版整理)
  8. 智能监狱管理系统APP软件开发
  9. 光环PMP 项目资源管理、项目相关方管理
  10. uefiboot 文件_UEFI下win系统启动过程及用bcdboot命令如何修复引导启动