python实现两个Excel表格数据对比、补充、交叉验证

业务背景

业务中需要用到类似企查查一类的数据平台进行数据导出,但企查查数据不一定精准,所以想采用另一个官方数据平台进行数据对比核验,企查查数据缺少的则补充,数据一致的保留企查查数据,不一致的进行颜色标注。

实现逻辑

经过调研,python可以实现表格的合并及数据处理,完成表格的合并及数据对比、数据补充、数据交叉验证。
首先将表格A数据和表格B数据交叉排列,奇数位为表格A的数据,偶数位为表格B数据,每两行为同一公司主体,进行上下数据对比,上一行数据没有的下一行补充,上下两行都有数据就进行对比,相同的不做处理,不同的标注颜色,并把表格B的数据放到大括号中拼接到表格A数据之后,最后删除偶数行的所有数据。

实现效果

表格A

image.png

表格B

image.png

合成后效果:

image.png

实现过程

1. Python环境安装:

下载地址:Python Releases for Windows | Python.org 下载时,注意选择自定义下载,并勾选添加路径,如下图:

image.png

下载安装完成后,按window+R键输入cmd打开命令行工具,输入python显示python版本即为安装成功。

2. Vscode代码编辑器下载及使用:

下载链接:Download Visual Studio Code - Mac, Linux, Windows
(1)转换为中文:安装好后可在扩展区搜索Chinese插件下载,页面工具栏即可变成中文,如下图一:

image.png (2)vscode添加python:新建或打开编写的python程序后,vscode右下角会弹出添加python环境的提示,点击添加;

(3)代码运行:按ctrl+~键打开终端运行程序,运行代码如下:
切换到运行文件所在目录: cd 目录
运行python文件: python 文件名.py

image.png

3. Python代码:

# 导入表格数据读取及处理模块
import pandas as pd
# 导入数据计算模块
import numpy as np
# 导入时间处理模块
# from datetime import datetime
# 导入读取和修改excel的模块
from openpyxl import load_workbook,Workbook
# 导入表格样式处理模块
from openpyxl.styles import *
# 比较字符串相似度的模块
import difflib# 导入表格数据读取及处理模块
import pandas as pd
# 导入数据计算模块
import numpy as np
# 导入时间处理模块
# from datetime import datetime
# 导入读取和修改excel的模块
from openpyxl import load_workbook,Workbook
# 导入表格样式处理模块
from openpyxl.styles import *
# 比较字符串相似度的模块
import difflib# 表格存放目录
url = "D:\\finance\\rank\\数据表格.xlsx"
# 整合后的表格存放目录
# afterUrl = ''
# 两个表格的sheetname名称
before = 'ifinds'    //表格A名称
after = 'winds'      //表格B名称
# 最终整合后表格名称
finalName = '对比数据结果'# 读取两个表格-通过sheet名称读取
data1 = pd.read_excel(url, header = 0, sheet_name = before )
data2 = pd.read_excel(url, header = 0, sheet_name = after )# 将数据重新赋值,避免修改数据后将原始ifind和wind数据修改
data3 = data1
data4 = data2# 进行表头重命名以统一表头名称
# 对ifind表格的表头名称重命名
data3 = data3.rename(columns = { '所属国民经济行业门类':'国民一级', '所属国民经济行业大类':'国民二级', '币种':'注册资本币种', '注册资本':'注册资本(万元)','参保人数(人)':'参保人数', '地级市':'城市','企业中文名称':'公司中文名称',}) 
# 对wind表格的表头名称重命名
data4 = data4.rename(columns = { '企业名称':'公司名称', '公司属性':'企业性质', '国民经济分类门类':'国民一级','国民经济分类大类':'国民二级','国民经济行业-门类':'国民一级','国民经济行业-大类':'国民二级',  '所属省份':'省份',  '所属城市':'城市',  '所属区县':'区/县',  '负债及股东权益合计2022':'负债和所有者权益总计2022', '经营活动现金净流量2022':'经营活动产生的现金流量净额2022','负债及股东权益合计2023':'负债和所有者权益总计2023', '经营活动现金净流量2023':'经营活动产生的现金流量净额2023','主体最新信用评级':'最新最低主体评级','是否城投债':'是否城投(THS)', '公司发行股票一览':'股票代码','币种':'注册资本币种','参保人数(人)':'参保人数','注册资本(万元)':'注册资本(万元)','注册资本':'注册资本(万元)','是否城投':'是否城投(THS)','是否城投债':'是否城投(THS)',})# # wind币种数据英文改中文
if '注册资本币种' in data4.columns:data4['注册资本币种'] = data4['注册资本币种'].replace('CNY', '人民币').replace('HKD', '港元').replace('MOP', '澳元').replace('USD', '美元').replace('EUR', '欧元').replace('IDR', '卢比').replace('RUB', '俄罗斯卢布').replace('AUD', '澳元').replace('GBP', '英镑')
# ifind企业性质改变
if '企业性质' in data3.columns:data3['企业性质'] = data3['企业性质'].replace('中央企业', '国企').replace('中央国有企业', '国企').replace('地方国有企业', '国企').replace('国有企业', '国企').replace('民营企业', '私企').replace('私营', '私企').replace('外商独资', '外资企业')
# wind企业性质改变
if '企业性质' in data4.columns:data4['企业性质'] = data4['企业性质'].replace('中央国有企业', '国企').replace('地方国有企业', '国企').replace('民营企业', '私企').replace('国有企业', '国企').replace('区县级国有企业', '国企').replace('市级国有企业', '国企').replace('省级国有企业', '国企')
# ifind经营状态的改变
if '经营状态' in data3.columns:data3['经营状态'] = data3['经营状态'].replace('在业', '存续')
# ifind和wind的企业规模的改变
if '企业规模' in data3.columns:data3['企业规模'] = data3['企业规模'].replace('L大型', '大型企业').replace('M中型', '中型企业').replace('S小型', '小型企业').replace('XS微型', '微型企业').replace('L(大型)', '大型企业').replace('M(中型)', '中型企业').replace('S(小型)', '小型企业').replace('XS(微型)', '微型企业')
if '企业规模' in data4.columns:data4['企业规模'] = data4['企业规模'].replace('大型', '大型企业').replace('中型', '中型企业').replace('小型', '小型企业').replace('小微企业', '小型企业')# 参保人数数据取整函数
def newList(inputList):result = []for num in inputList:if pd.isnull(num) or num == "--":num = 0result.append(int(num))return result
# 调用函数
# ifind参保人数取整
if '参保人数' in data3.columns:data3['参保人数'] = newList(data3['参保人数'])
# wind参保人数取整
if '参保人数' in data4.columns:data4['参保人数'] = newList(data4['参保人数'])# 保留两位小数的函数
def rateList(inputList):result = []for num in inputList:num = float(num)if pd.isnull(num) or num == "--":num = 0num = "{:.2f}".format(num)result.append(num)return result# 将wind的财务数据缩小10000倍    or value[:5] == '负债和所有'
for value in data4.columns:if value[:5] == '所有者权益' or value[:4] == '营业收入' or value[:4] == '利润总额' or value[:4] == '资产总额' or value[:5] == '经营活动产':data4[value] = data4[value].apply(lambda x: x/10000)# 将ifind的财务数据保留两位  大股东持股比例、 注册资本(万元)
for value in data3.columns:if value[:5] == '所有者权益' or value[:5] == '负债和所有' or value[:4] == '营业收入' or value[:4] == '利润总额' or value[:4] == '资产总额' or value[:5] == '经营活动产'or value[:5] == '注册资本(' or value[:5] == '大股东持股':data3[value] = rateList(data3[value])# 将wind的财务数据保留两位
for value in data4.columns:if value[:5] == '所有者权益' or value[:5] == '负债和所有' or value[:4] == '营业收入' or value[:4] == '利润总额' or value[:4] == '资产总额' or value[:5] == '经营活动产'or value[:5] == '注册资本(' or value[:5] == '大股东持股':data4[value] = rateList(data4[value])# # 经营范围重复度高于50%则取ifind的经营范围数据,否则标识出来
# 计算重复度的方法
# pdData3 = pd.DataFrame(data3)
pdData4 = pd.DataFrame(data4)
def string_similar(s1, s2):return difflib.SequenceMatcher(None, s1, s2).quick_ratio()
if '经营范围' in data3.columns:for index in range(0, len(data3['经营范围']), 1):# 调用方法if string_similar(str(data3['经营范围'][index]), str(data4['经营范围'][index])) > 0.5:# pdData4.loc[index,'经营范围'] = data3['经营范围'][index]data4['经营范围'][index] = data3['经营范围'][index]# wind省份数据北京、天津、重庆、上海添加‘市’字的函数
def addword(addData):result = []for value in addData:if value == '北京' or value == '上海' or value == '天津' or value == '重庆':value = value + '市'result.append(value)return result
# 调用函数
if '省份' in data4.columns:data4['省份']= addword(data4['省份'])# wind地市级去掉北京、重庆、上海、天津的函数
def deleteword(addData):result = []for value in addData:if value == '北京市' or value == '上海市' or value == '天津市' or value == '重庆市':value = '0'result.append(value)return result
# 调用函数
if '城市' in data4.columns:data4['城市']= deleteword(data4['城市'])# wind的股票代码去掉股票简称函数
def removeName(word):result = []for value in word:value = str(value).split('(')[0]result.append(value)return result
# 调用去掉股票简称的函数
if '股票代码' in data4.columns:data4['股票代码'] = removeName(data4['股票代码'])# 有股票代码的将上市公司信息改为是,否则改为否
pdData3 = pd.DataFrame(data3)
if '股票代码' in data3.columns:for index in range(0, len(data3['股票代码']), 1):# 如果wind股票代码单元格的字符长度大于2,则将代码编号改为是,否则改为否if len(str(data3['股票代码'][index])) > 2:pdData3.loc[index:, '是否上市'] = "是"else:pdData3.loc[index:, '是否上市'] = "否"# 如果wind股票代码单元格的字符长度大于2,则将代码编号改为是,否则改为否if '股票代码' in data4.columns and len(str(data4['股票代码'][index])) > 2:pdData4.loc[index:, '是否上市'] = "是"else:pdData4.loc[index:, '是否上市'] = "否"# 合并两个表格数据,并且ifind数据在前,wind数据在后
result = pd.concat([data3, data4], ignore_index = True)# 得到的合并表格的标题,重新创建新表格,添加表头
dfNew = pd.DataFrame(columns = result.columns)# 获取合并的两个表格的索引,通过索引使两个表格的数据交叉排列
data3 = data3.set_index(np.arange(1, data3['序号'].count()+1, 1), drop = False)
data4 = data4.set_index(np.arange(1, data4['序号'].count()+1, 1), drop = False)# 合并两个表格的索引到一个表格
for i in np.arange(1, data3['序号'].count()+1, 1):dfNew.loc[2*i-2] = data3.loc[i]dfNew.loc[2*i-1] = data4.loc[i]# 遍历判断:如果第一行数据为nan或为0,就把第二行的数据填充到第一行,
for column in np.arange(0, dfNew.shape[0]):if column % 2 == 0:       for index in range(len(dfNew.iloc[column].values)):if pd.isnull(dfNew.iloc[column].values[index]) or str(dfNew.iloc[column].values[index]) == '0' or str(dfNew.iloc[column].values[index]) == '0.00' or str(dfNew.iloc[column].values[index]) == '0.0':dfNew.iloc[column, index]= dfNew.iloc[column+1].values[index]# # 定义list,用来存储数据不同的列的下标数据
rowsList = []
columnsList = [[] for _ in range(dfNew.shape[0])]
# 如果第二行数据和第一行数据不同,就把wind的数据添加括号拼接到ifind后
for row in np.arange(0, dfNew.shape[0]):if row % 2 == 0:   rowsList.append(row)    for index in range(len(dfNew.iloc[row].values)):if pd.notnull(dfNew.iloc[row+1].values[index]):# 处理因中英文括号导致的差异if(str(dfNew.iloc[row].values[index]).replace('(','(').replace(')',')') != str(dfNew.iloc[row+1].values[index]).replace('(', '(').replace(')',')') and str(dfNew.iloc[row+1].values[index]) != '0' and str(dfNew.iloc[row+1].values[index]) != '0.00' and str(dfNew.iloc[row+1].values[index]) != '0.0') :dfNew.iloc[row, index] = str(dfNew.iloc[row].values[index]) + '{' + str(dfNew.iloc[row+1].values[index]) + '}'        # 每一行的列的添加有问题columnsList[row].append(index)else:dfNew.iloc[row, index] = str(dfNew.iloc[row].values[index])# 将三个表格导出为三个sheet
writer = pd.ExcelWriter(url)
dfNew.to_excel(writer, sheet_name = finalName, index = False)
data1.to_excel(writer, sheet_name = before, index = False)
data2.to_excel(writer, sheet_name = after, index = False)
writer._save()
writer.close()  # # 添加不同数据组的高亮
wb = load_workbook(url)
sheet1 = wb['对比数据结果']
for row in rowsList:for column in columnsList[row]:sheet1.cell(row + 2,column + 1).fill = PatternFill('solid', fgColor = Color('9dff00'))# # 删除wind行的数据 第二行
deleteRow = []
for i in np.arange(dfNew.shape[0] + 5,2, -1):if i%2 == 1:sheet1.delete_rows(i)# # 导出添加样式后的表格
wb.save(url)
wb.close()
print("恭喜你,合并完成!")

注意事项

1.注意两个表格第一列的表头为序号,第一列传入从1开始的序号作为合并数据的排列下标,否则程序会报错;
2.两组表格排列顺序要一致;
3.注意程序运行前要将表格关闭,表格被占用时程序不能运行会报错;
4.将两张表格放到一个excel文件的两个sheet中,对比数据表格放到第三个sheet中,注意名称要和代码里对应上;

总结

我基本上已经处理到了表格合并遇上的大多问题,代码也添加了详细注释,欢迎大家来积极提出问题,共同解决问题。

关于Python学习指南

学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后给大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

包括:Python激活码+安装包、Python web开发,Python爬虫,Python数据分析,人工智能、自动化办公等学习教程。带你从零基础系统性的学好Python!

👉Python所有方向的学习路线👈

Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。(全套教程文末领取)

在这里插入图片描述

👉Python学习视频600合集👈

观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

在这里插入图片描述

温馨提示:篇幅有限,已打包文件夹,获取方式在:文末

👉Python70个实战练手案例&源码👈

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

在这里插入图片描述

👉Python大厂面试资料👈

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

在这里插入图片描述

在这里插入图片描述

👉Python副业兼职路线&方法👈

学好 Python 不论是就业还是做副业赚钱都不错,但要学会兼职接单还是要有一个学习规划。

在这里插入图片描述

👉 这份完整版的Python全套学习资料已经上传,朋友们如果需要可以扫描下方CSDN官方认证二维码免费领取保证100%免费

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/780789.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

脱壳之常用的加固样本特征

梆梆加固样本特征 清单文件入口 android:name“com.SecShell.SecShell.ApplicationWrapper” 特征 免费版 meta-data meta-data总结 assets/secData0.jar lib/armeabi/libSecShell.so lib/armeabi/libSecShell-x86.so 梆梆企业版 assets/classes0.jar lib/armeabi-v7a/libD…

第一次运行 Python 项目,使用 python-pptx 提取 ppt 中的文字和图片

人工智能时代,最需要学习的编程语言是:python 。笔者是个 python 小白,昨天花了两个小时,第一次成功运行起来 python 项目 。 项目是 powerpoint-extractor ,可以将 ppt 文件中的图片提取出来,并输出到固定…

Windows安装tomcat,以服务的方式管理,如何设置虚拟内存

之前工作中,部署tomcat都是使用Linux服务器,最近遇到个客户,提供的服务器是Windows server,并且需要通过服务的方式管理tomcat;以自己多年的码农经验,感觉应该没有问题,结果啪啪打脸了&#xf…

双向BFS

P1032 [NOIP2002 提高组] 字串变换 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 方法学自于B19 双向BFS 字串变换_哔哩哔哩_bilibili #include<iostream> #include<algorithm> #include<cstdio> #include<queue> #include<map> using namesp…

Adaboost集成学习 | Matlab实现基于BiLSTM-Adaboost双向长短期记忆神经网络结合Adaboost集成学习时间序列预测(股票价格预测)

目录 效果一览基本介绍模型设计程序设计参考资料效果一览 基本介绍 Matlab实现基于BiLSTM-Adaboost双向长短期记忆神经网络结合Adaboost集成学习时间序列预测(股票价格预测) 模型设计 股票价格预测是一个具有挑战性的时间序列预测问题,可以使用深度学习模型如双向长短期记忆…

python爬虫之selenium4使用(万字讲解)

文章目录 一、前言二、selenium的介绍1、优点&#xff1a;2、缺点&#xff1a; 三、selenium环境搭建1、安装python模块2、selenium4新特性3、安装驱动WebDriver驱动选择驱动安装和测试 基础操作1、属性和方法2、单个元素定位通过id定位通过class_name定位一个元素通过xpath定位…

【OJ】动归练习五之子组串

个人主页 &#xff1a; zxctscl 如有转载请先通知 题目 1. 53. 最大子数组和1.1 分析1.2 代码 2. 918. 环形子数组的最大和2.1 分析2.2 代码 3. 152. 乘积最大子数组3.1 分析3.2 代码 4. 1567. 乘积为正数的最长子数组长度4.1 分析4.2 代码 1. 53. 最大子数组和 1.1 分析 一、…

密码学基础-对称密码/公钥密码/混合密码系统 详解

密码学基础-对称密码/公钥密码 加解密说明1.加密解密必要因素加密安全性说明 什么是对称密码图示说明对称密码详解什么是DES?举例说明 什么是3DES什么是AES? 公钥密码什么是RSA? 对称密钥和公钥密码优缺点对比对称密码对称密码算法总结对称密码存在的问题? 公钥密码公钥密码…

npm ERR! errno CERT_HAS_EXPIRED

1 问题描述 使用npm命令安装相关依赖报错&#xff1a;npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED npm ERR! request to https://registry.npm.taobao.org/vue%2fcli failed, reason: certificate has expired报错示例图如下所示&#xff1a; 2原因分析…

Spring Boot 整合分布式搜索引擎 Elastic Search 实现 自动补全功能

文章目录 ⛄引言一、分词器⛅拼音分词器⚡自定义分词器 二、自动补全查询三、自动补全⌚业务需求⏰实现酒店搜索自动补全 四、效果图⛵小结 ⛄引言 本文参考黑马 分布式Elastic search Elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能&#xff0c;…

谈一谈BEV和Transformer在自动驾驶中的应用

谈一谈BEV和Transformer在自动驾驶中的应用 BEV和Transformer都这么火&#xff0c;这次就聊一聊。 结尾有资料连接 一 BEV有什么用 首先&#xff0c;鸟瞰图并不能带来新的功能&#xff0c;对规控也没有什么额外的好处。 从鸟瞰图这个名词就可以看出来&#xff0c;本来摄像头…

阿里云Salesforce CRM功能差异列表 - Winter‘24

阉割版的阿里云Salesforce由于技术和监管等因素与国际版的Salesforce差距很大&#xff01; 一、Winter‘ 24版差异概况&#xff1a; 1.1. 主要版本&#xff1a; 阿里云上的 Salesforce 提供两个版本&#xff0c;用于生产用途的 CN 版本&#xff08;CN Edition&#xff09;和用…

day4 linux上部署第一个nest项目(java转ts全栈/3R教室)

背景&#xff1a;上一篇吧nest-vben-admin项目&#xff0c;再开发环境上跑通了&#xff0c;并且build出来了dist文件&#xff0c;接下来再部署到linux试试吧 dist文件夹是干嘛的&#xff1f; 一个pnpn install 直接生成了两个dist文件夹&#xff0c;前端admin项目一个&#xf…

Jenkins磁盘空间批量清理脚本

一、简介 Jenkins如果没有设置保留构建历史数&#xff0c;磁盘会随着使用次数增加而越来越满&#xff0c;于是需要批量清理一下。 二、清理脚本 找到Script Console 输入脚本&#xff0c;并点击执行&#xff0c;需要注意期望删除的构建历史编号&#xff08;可以查看下面的效果…

14. Springboot集成RabbitMQ

目录 1、前言 2、什么是RabbitMQ 3、安装RabbitMQ 4、Springboot集成RabbitMQ 4.1、添加依赖 4.2、添加配置 4.3、添加controller&#xff0c;作为生产者 4.4、设置生产者消息确认CallBack 4.5、添加Consumer&#xff0c;作为消费者 4.6、启动程序&#xff0c;访问 1…

关键字:this总结

this关键字的使用1. 目前可能出现的问题&#xff1f;及解决方案&#xff1f;我们在声明一个属性对应的setXxx方法时&#xff0c;通过形参给对应的属性赋值。如果形参名和属性名同名了&#xff0c;那么该如何在方法内区分这两个变量呢&#xff1f;解决方案&#xff1a;使用this。…

YOLOv9改进策略 :block优化 | 无需TokenMixer也能达成SOTA性能的极简ViT架构 | CVPR2023 RIFormer

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文改进内容&#xff1a; token mixer被验证能够大幅度提升性能&#xff0c;但典型的token mixer为自注意力机制&#xff0c;推理耗时长&#xff0c;计算代价大&#xff0c;而RIFormers是无需TokenMixer也能达成SOTA性能的极简ViT架构…

java寻找递增子序列(力扣Leetcode491)

寻找递增子序列 力扣原题链接 问题描述 给定一个整数数组 nums&#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中至少有两个元素。你可以按任意顺序返回答案。数组中可能含有重复元素&#xff0c;如出现两个整数相等&#xff0c;也可以视作递增序…

Raspberry Pi Pico 可以充当 GPU 吗?

来自 element14 的克莱姆的任务是探索将 Raspberry Pi Pico 转化为 GPU 的可能性&#xff0c;以便在游戏中渲染超级流畅的图形。是的&#xff0c;你没有看错&#xff01;他不是在尝试使用我们的怪物级新 Raspberry Pi 5&#xff0c;甚至不是 Pi 4&#xff0c;他是在尝试使用我们…

数据结构:归并排序

归并排序 时间复杂度O(N*logN) 如果两个序列有序,通过归并,可以让两个序列合并后也有序,变成一个有序的新数组 对于一个数组,如果他的左右区间都有序,就可以进行归并了 归并的方法 将数组的左右两个有序区间比较,每次都取出一个最小的,然后放入临时数组(不能在原数组上修改…