用Python写一个Excel汇总和比对小程序
用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汇总和比对小程序相关推荐
- 用python写一个圣诞互换礼物的抽奖小程序
目的 最近和朋友们想玩圣诞互换礼物,但是没找到可以抽奖的小程序,所以我决定自己写一个. 游戏规则:参加游戏的人需要随机抽取一个幸运儿送一个礼物,但是注意不要抽到自己,并且不要重复抽同一个人. 思路 准 ...
- 用python写一个日语五十音记忆小程序qaq
最近在B站自学日语~可能被英语洗脑太久了,感觉五十音图特别别扭超级难背qaq 朋友推荐了几个背单词软件都没有背五十音的,对零基础不太友好 自己写了一个感觉还挺好使 程序很简单,主要是没有日语输入法,要 ...
- python编写数据库连接工具_详解使用Python写一个向数据库填充数据的小工具(推荐)...
一. 背景 公司又要做一个新项目,是一个合作型项目,我们公司出web展示服务,合作伙伴线下提供展示数据. 而且本次项目是数据统计展示为主要功能,并没有研发对应的数据接入接口,所有展示数据源均来自数据库 ...
- 基于Python编写一个B站全自动抽奖的小程序
本文将利用Python编写一个B站全自动抽奖的小程序,可以实时监控自己关注的UP主,如果关注的UP主中有人发布了抽奖的动态,就自动参与这个抽奖.这样就能不错过任何一个可以暴富的机会了.需要的可以参考一 ...
- 写一个音乐播放器的微信小程序
要创建一个音乐播放器的微信小程序,您需要熟悉微信小程序的开发环境和语言(如 JavaScript 和 WXML/WXSS). 具体来说,您需要做以下几件事: 设计音乐播放器的用户界面,并使用 WXML ...
- 手把手教你写一个没有服务器的颜值打分小程序,可直接上线
小程序现在可以说非常火爆了,流量入口非常多.尤其是出了流量主功能以后,普通开发者也能在自己的个人小程序里植入官方广告来获取收入.程序员想赚点外快再合适不过了.今天教大家写一个颜值打分的小程序,利用现成 ...
- python 生成excel像素画_用python写一个excel画像素图脚本时所用到的一些库
首先 ,想法源于在果壳网看到的一个用excel画一幅像素图的活动 思路很简单: 先将一张像素图的每个像素点的rgb值取出来 然后用脚本操作excel,将rgb设置为单元格的背景色 主要就在于两点 一. ...
- 关于如何使用Python写一个开机自动认证校园网的脚本程序
有的学校有那个无感认证,有的学校没有,这个时候就可以自己动手丰衣足食,我学校就是只有手机才有无感认证,PC端是没有的,所以我就自己写了一个.(没有编程经验也可以,照着我的写就行) 首先,你需要安装好P ...
- 用python写一个简答的英文文章分析程序
前言 本人是软件工程在校学生,萌新一枚,写此程序为了练习字符串处理函数.程序有bug,例如没法把文章中的数字处理掉,希望多多包涵,有什么改进的方法可以留言. 一.代码内容 filehandle=ope ...
- 用python画满天星花朵_如何使用python做一个可以画一朵花的小程序?
这篇文章可以交给你怎么在windows或macOS与python3环境下做出一个可以根据你的自定义设置画出一朵花的程序. 在开始写正式的逻辑代码之前,我们要先导入一些库: from tkinter i ...
最新文章
- CodeGen准备存储库
- js中定义变量之②var let const的区别
- python好还是c+-JAVA,Python和C+各有什么特点和优势?
- 手把手教你如何写简历
- MySQL高级 - SQL优化 - 子查询优化
- 自建CA生成证书详解
- 国内博客(blog)搬家工具(服务)大全
- 为什么蓝牙一主多从能解决集中式水表抄表难题?
- php Y2K38 漏洞解决方法
- 思科交换机指示灯全解
- 学猫叫用计算机歌词,抖音学猫叫是什么歌 学猫叫歌曲歌词
- 科学计算机常用按键,电脑计算器里面的“科学型”的里面所有的按键的功能
- 安卓 输入框身份证号限制
- 华师大 OJ 3055
- 使用bootstrap制作简单的左侧导航栏
- THUSC 2017 游记
- 小米推迟上市和A股大跌,背后有什么共同原因?
- 欧几里得算法、扩展欧几里得算法(特解、应用、通解)
- 魔兽地图编辑器插件YDWE的使用与基本设置3之地形面板、装饰物面板、单位面板、区域面板、镜头面板
- UVA11292 The Dragon of Loowater
热门文章
- Jasper报表导出pdf中文不显示——Font simsun is not available to the JVM. See the Javadoc for more det,已解决
- 川师c语言实验报告9,川师c语言实验报告十.doc
- Eucalyptus简介
- tomcat常见漏洞
- SQL注入——判断注入
- 空调开关html,酒店墙上空调开关图解—酒店墙上空调开关图案是什么意思
- 阿里巴巴Java开发手册(2018-2021泰山版整理)
- 智能监狱管理系统APP软件开发
- 光环PMP 项目资源管理、项目相关方管理
- uefiboot 文件_UEFI下win系统启动过程及用bcdboot命令如何修复引导启动