高教杯数学建模2020C题总结
🧡1. 前言🧡
跟队友花了三天模拟2020C题,现在整理一下一些数据处理的代码,以及在模拟中没有解决的问题。方便以后回溯笔记。
🧡2. 数据处理🧡
2.1 导入数据,并做相关预处理
import pandas as pd
import numpy as np
import re# import data
df1=pd.read_excel('oridata/附件1:123家有信贷记录企业的相关数据.xlsx',sheet_name='企业信息')
df2=pd.read_excel('oridata/附件1:123家有信贷记录企业的相关数据.xlsx',sheet_name='进项发票信息')
df3=pd.read_excel('oridata/附件1:123家有信贷记录企业的相关数据.xlsx',sheet_name='销项发票信息')# 删除df2、df3重复行
duplicate_rows = df2.duplicated() # 检测重复行 从前向后查,后一个重复则true
print(duplicate_rows.sum())
df2 = df2[~duplicate_rows]
duplicate_rows = df3.duplicated() # 检测重复行 从前向后查,后一个重复则true
print(duplicate_rows.sum())
df3 = df3[~duplicate_rows]# 处理企业代号,将 E1 ===> 数字1 使用正则表达式提取数字部分并转换为整数
df1['企业代号'] = df1['企业代号'].apply(lambda x: int(re.findall(r'\d+', x)[0]))
df2['企业代号'] = df2['企业代号'].apply(lambda x: int(re.findall(r'\d+', x)[0]))
df3['企业代号'] = df3['企业代号'].apply(lambda x: int(re.findall(r'\d+', x)[0])) # 处理时间数据, 将 2017-1-1 ==> 年份属性2017 、 月份属性1
df2['开票日期'] = pd.to_datetime(df2['开票日期'])
df2['年份'] = df2['开票日期'].dt.year
df2['月份'] = df2['开票日期'].dt.month
df3['开票日期'] = pd.to_datetime(df3['开票日期'])
df3['年份'] = df3['开票日期'].dt.year
df3['月份'] = df3['开票日期'].dt.month# 获取所有公司的列表 1,2,3,.....123
all_companies = df1['企业代号'].unique() df3
2.2 信誉等级和是否违约 转成英文
"""
信誉等级和是否违约 中文转英文
"""
data0=df1.copy()
toClassNum_map1={'A': 3, 'B': 2, 'C': 1,'D':0}
data0['信誉评级'] = data0['信誉评级'].map(toClassNum_map1)
toClassNum_map2={'是': 0, '否': 1}
data0['是否违约'] = data0['是否违约'].map(toClassNum_map2)data0=data0[['企业代号','信誉评级','是否违约']]
data0
2.3 利用groupby统计各种指标
基本原理:
2.3.1 统计三年总买入、卖出的价税合计总金额 和 各年买入、卖出的价税合计总金额
data1=df2.copy()
data2=df3.copy()# 统计三年总买入、卖出的价税合计总金额
data1_totalmoney = data1.groupby('企业代号')['价税合计'].sum().reset_index(name='买入-价税总金额')
data2_totalmoney = data2.groupby('企业代号')['价税合计'].sum().reset_index(name='卖出-价税总金额')data_totoalmoney_merge=pd.merge(data1_totalmoney,data2_totalmoney,on='企业代号')
data_totoalmoney_merge# 各年买入、卖出的价税合计总金额
data1_yearmoney = data1.groupby(['企业代号','年份']).agg({'价税合计':'sum'})
data2_yearmoney = data2.groupby(['企业代号','年份']).agg({'价税合计':'sum'})
print(data1_yearmoney) # 查看结果只有356行 != 123*3,说明有些企业少了某些年的数据,计数为0,而grougby函数不会展示计数为0的分组,因此需要填充缺失年
mulidx=[] # 生成二维索引 (企业代号、年份)
for i in range(1,123+1): # 1-123for j in range(2017,2019+1): # 2017、2018、2019mulidx.append((i,j))
mulidx=pd.MultiIndex.from_tuples(mulidx,names=["企业代号", "年份"]) # 转为二维行索引,命名为("企业代号", "年份")
data1_yearmoney=data1_yearmoney.reindex(mulidx, fill_value=0)
data2_yearmoney=data2_yearmoney.reindex(mulidx, fill_value=0)data_yearmoney_merge=pd.merge(data1_yearmoney,data2_yearmoney,left_index=True, right_index=True,suffixes=('_买入', '_卖出'))
data_yearmoney_merge
#
2.3.2 统计三年总买入、卖出的总发票数和违约发票数
"""
违约率
"""
data3=df2.copy()
data4=df3.copy()# ===============统计三年总买入、卖出的总发票数和违约发票数=============
# 总发票个数
data3_totalPay=data3.groupby('企业代号').agg({'发票号码':'count'})
data3_totalPay=data3_totalPay.reindex(all_companies ,fill_value=0)
data3_totalPay=data3_totalPay.rename(columns={'发票号码':'买入-总发票次数'})data4_totalPay=data4.groupby('企业代号').agg({'发票号码':'count'})
data4_totalPay=data4_totalPay.reindex(all_companies ,fill_value=0)
data4_totalPay=data4_totalPay.rename(columns={'发票号码':'卖出-总发票次数'})data_totalPay_merge=pd.merge(data3_totalPay,data4_totalPay,on='企业代号')
data_totalPay_merge# 违约发票个数
data3=data3[(data3['价税合计'] < 0 ) | (data3['发票状态']=='作废状态')]
data3_totalBadPay=data3.groupby('企业代号').agg({'发票号码':'count'})
data3_totalBadPay=data3_totalBadPay.reindex(all_companies ,fill_value=0)
data3_totalBadPay=data3_totalBadPay.rename(columns={'发票号码':'买入-总违约发票次数'})data4=data4[(data4['价税合计'] < 0 ) | (data4['发票状态']=='作废状态')]
data4_totalBadPay=data4.groupby('企业代号').agg({'发票号码':'count'})
data4_totalBadPay=data4_totalBadPay.reindex(all_companies ,fill_value=0)
data4_totalBadPay=data4_totalBadPay.rename(columns={'发票号码':'卖出-总违约发票次数'})data_totalBadPay_merge=pd.merge(data3_totalBadPay,data4_totalBadPay,on='企业代号')
data_totalBadPay_merge
2.3.3 统计各公司营业时间(月数)
"""
营业时间
"""
data5=data2.copy()
data5['年-月']= data5['开票日期'].dt.strftime('%Y-%m')# 使用 drop_duplicates 方法按照 '企业代号' '年-月' 进行分组,并保留每个组别的第一条数据
data5 = data5.drop_duplicates(subset=['企业代号','年-月'], keep='first')
data5 = data5.groupby(['企业代号'])['年-月'].size().reset_index(name='卖出-营业时间')
data5
2.4 总结
2.4.1 agg{sum}和sum区别?
- 统计个数时,data2.groupby(‘企业代号’).agg({‘价税合计’:‘sum’}) 和 **data2.groupby(‘企业代号’)[‘价税合计’].sum().reset_index(name=‘卖出-价税总金额’)**作用是否一样?
看图,差别在于:前者将企业代号(从1开始)作为行索引,后者重新生成一个(从0开始)的行索引。
前者的好处是当需要填充缺失值时,可以用reindex根据企业代号填充;后者的好处是方便pd.concat合并多个表
2.4.2 pd.concat 和 pd.merge的区别?
- pd.concat
根据轴相连
一次可以连接多个表
join:outer、inner,其中inner:上下拼接的时候,保留了共有的列信息! 左右拼接的时候保留了共有的行信息! - pd.merge
根据共有属性相连
一次只能连接两张表
join: outer、inner、left、right
on:共同属性列
2.4.3 groupby其他有用的参数
- unstack可以将分组的行索引变成列索引
test=data1.groupby('企业代号')['发票状态'].value_counts().unstack()
test
2. 当agg对多组进行多个操作后,会存在两维列索引,以下展示如何转为一维列索引
test=data1.groupby('企业代号').agg({'价税合计':['mean','sum'],'发票状态':'size'})
test.columns = ['_'.join(col).strip() for col in test.columns.values] # 合并多级列
test
3. get_group筛选出满足特定条件的组
test=data1.groupby('发票状态').get_group('作废发票').reset_index() # 筛选出满足条件的
test
2.4.4 利用globals简化代码
如下,已经定义了10个变量,想要输出它们的长度
print(df1.count())
print(df2.count())
print(df3.count())
print(df4.count())
print(df5.count())
print(df6.count())
print(df7.count())
print(df8.count())
print(df9.count())
print(df10.count())# gloabs()简化
for i in range(10):print(globals()[f'df{i+1}'].count())
🧡3. 画图🧡
配色方案:红色–#d7003a,绿色–green,混淆矩阵的cmap–Greens
3.1 营业时间直方图
"""
主要设置:bin 调整柱子数目 light_index 调整哪个柱子为突出色xytext 调整位置
"""import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
plt.rcParams['font.sans-serif'] = ['SimHei'] # 为了支持中文字体
plt.rcParams['axes.unicode_minus'] = False # 上述字库没负号,因此负号不进行字体变换data1=pd.read_excel('out/t1_123_指标.xlsx')
data1=data1['卖出-营业时间']fig, ax = plt.subplots()
bins = 10 #直方图的柱子数目
colors = ['g']
n, bins, patches = ax.hist(data1, bins=bins, color=colors[0], alpha=0.7, label='Group', edgecolor='black')# 设置最高利润的柱子颜色为红色
light_index=9
patches[light_index].set_facecolor('#d7003a')
# 标注最高利润的柱子 ax.annotate('Max', xy=(bins[light_index], n[light_index]), xycoords='data',xytext=(12, 5), textcoords='offset points', color='red', weight='bold')ax.legend()
ax.set_xlabel('营业时间(月)', fontsize=12)
ax.set_ylabel('频数', fontsize=12)
ax.set_title('各企业营业时间直方图', fontsize=14)
ax.tick_params(axis='both', which='major', labelsize=10)
ax.grid(True, linestyle='--', alpha=0.7)
# ax.set_facecolor('#f0f0f0')
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
plt.tight_layout() # 自动调整子图或图形的布局,使其适应绘图区域,避免重叠和裁剪plt.savefig('img/营业时间.png',dpi=300) # 在plt.show()之前调用
plt.show()
3.2 各企业买入、卖出总发票次数和作废发票次数堆叠图(前10个企业)
"""
堆叠图
主要设置:ax.text第二个参数 根据实际数值设置文本高度
"""
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
plt.rcParams['font.sans-serif'] = ['SimHei'] # 为了支持中文字体
plt.rcParams['axes.unicode_minus'] = False # 上述字库没负号,因此负号不进行字体变换data=pd.read_excel('out/t1_123_指标.xlsx')
data2=data['买入-作废发票数'].head(10)
data1=data['买入-总发票次数'].head(10)
x_labels=data['企业代号'].head(10)fig, ax = plt.subplots()
# 绘制第一组数据的柱状图
bar1=ax.bar(x_labels, data1, label='买入-总发票次数',color='g')# 绘制第二组数据的柱状图,底部从第一组数据开始
bar2=ax.bar(x_labels, data2, bottom=data1, label='买入-作废发票数',color='#d7003a')# 在每个柱子的顶部添加文本
for rect1, rect2 in zip(bar1, bar2):height1 = rect1.get_height()height2 = rect2.get_height()ax.text(rect2.get_x() + rect2.get_width() / 2, height1+height2+1000,f'{height2}', ha='center', va='top')ax.legend()
ax.set_xlabel('企业代号', fontsize=12)
ax.set_ylabel('发票数', fontsize=12)
ax.set_title('各企业总发票次数和作废发票次数堆叠图', fontsize=14)
ax.tick_params(axis='both', which='major', labelsize=10)
ax.grid(True, linestyle='--', alpha=0.7)
# ax.set_facecolor('#f0f0f0')
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
plt.tight_layout() # 自动调整子图或图形的布局,使其适应绘图区域,避免重叠和裁剪
plt.xticks(range(1,11), x_labels)
plt.savefig('img/总-作废1.png',dpi=300)
plt.show()
3.3 买入卖出范围频数图
"""
范围频数图
主要设置:bins1、bins2 设置范围data 根据print结果手动输入变量,第一列代表bins1、第二列代表bins2width 设置柱形宽度ax.bar 第二个参数设置与xlabels对齐
"""
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
plt.rcParams['font.sans-serif'] = ['SimHei'] # 为了支持中文字体
plt.rcParams['axes.unicode_minus'] = False # 上述字库没负号,因此负号不进行字体变换data=pd.read_excel('out/t1_123_指标.xlsx')
# print(data.describe())data1=data['买入-价税总金额']
data2=data['卖出-价税总金额']# 自定义范围
bins1 = [0, 1e5, 1e6, 1e7, 1e8, 1e10] # 范围为[0, 20), [20, 40), [40, 60)
bins2 = [0, 1e5, 1e6, 1e7, 1e8, 1e10]
# 使用cut函数对数据进行划分
categories1 = pd.cut(data1, bins=bins1)
categories2 = pd.cut(data2, bins=bins1)
# 使用value_counts函数统计各范围的数据个数
count1 = categories1.value_counts()
count2 = categories2.value_counts()
print(count1)
print(count2)# 生成示例数据
groups = ['0-1e5', '1e5-1e6', '1e6-1e7', '1e7-1e8', '1e8-1e10']
indicators = ['买入-价税总金额', '卖出-价税总金额']
data = np.array([[28,11],[31,24],[30,34],[31,45],[3,9]]
)fig, ax = plt.subplots()
width = 0.2
colors = ['g', '#d7003a']for i in range(len(groups)):x = (np.arange(len(indicators)) - len(indicators)//2) * width + i # 距离print(x)for j in range(len(indicators)):ax.bar(x[j]+0.1, data[i][j], width, color=colors[j], label=indicators[j] if i == 0 else '')ax.legend(loc='upper left')
ax.set_xlabel('金额范围', fontsize=12)
ax.set_ylabel('数目', fontsize=12)
ax.set_title('买入卖出价税总金额', fontsize=14)
ax.set_xticks(np.arange(len(groups)))
ax.set_xticklabels(groups)
plt.savefig('img/买入卖出价税总金额.jpg',dpi=300)
plt.show()
暂时写这么多吧 ~ 希望以后遇到groupby等处理得心应手 ~
相关文章:

高教杯数学建模2020C题总结
🧡1. 前言🧡 跟队友花了三天模拟2020C题,现在整理一下一些数据处理的代码,以及在模拟中没有解决的问题。方便以后回溯笔记。 🧡2. 数据处理🧡 2.1 导入数据,并做相关预处理 import pandas a…...

Swagger
目录 简介 使用方式: 常用注解 简介 使用Swagger你只需要按照他的规范去定义接口及接口相关信息再通过Swagger衍生出来的一系列项目和工具,就可以做到生成各种格式的接口文档,以及在线接口调试页面等等。 官网:https://swagger…...
Android 13像Settings一样获取热点和网络共享
一.背景 由于客户定制的Settings里面需要获取到热点和网络共享状态,所以需要实现此功能。 目录 一.背景 二.前提条件 三.调用api 二.前提条件 首先应用肯定要是系统应用,并且导入framework.jar包,具体可以参考: Android 应用自动开启辅助(无障碍)功能并使用辅助(无障碍…...

操作系统搭建相关知识
文章目录 系统篇netstat命令systemctl命令Systemd系统资源分类(12类) 网络篇ifconfig命令操作系统配置动态IP脚本dhcp服务的安装与配置防火墙相关知识 操作系统常用配置文件 系统篇 netstat命令 netstat指路 systemctl命令 常用于重启系统的每个服务…...

【校招VIP】前端校招考点之vue底层特性
考点介绍: 大家在面试途中遇到的相对多的问题,也是难点的问题,一般都有vue底层原理。对于只会用但是不懂的小白来说真是太痛苦了,仅仅能说出来 一些 数据劫持,双向数据绑定,虚拟dom树的名词来说远远不够。 …...

vue3+vite配置vantUI主题
❓在项目中统一配置UI主题色,各个组件配色统一修改 vantUI按需安装 参考vantUI文档 创建vantVar.less文件夹进行样式编写 vantVar.less :root:root{//导航--van-nav-bar-height: 44px;//按钮--van-button-primary-color: #ffffff;--van-button-primary-backgr…...

C++基础语法——继承
1.继承是什么? 继承是一种面向对象编程的概念,它允许一个类(称为子类或派生类)从另一个类(称为基类或父类)继承属性和方法。继承使得子类能够使用基类已有的代码,并且可以在此基础上进行扩展或修…...
vim配置之spf13-vim
文章目录 vim配置:spf13-vim什么是spf13-vim安装*nix and os x安装 spf13-vim使用技巧或快捷键spf13的vim默认没有启用剪切板,需要在vimrc中设置 vim配置:spf13-vim 什么是spf13-vim 官网:http://vim.spf13.com/ 它是一个完全跨平台发布,保持vim的感觉…...

Azure如何启用网络观察应用程序
文章目录 基础概念介绍实操 基础概念介绍 Azure中的网络观察应用程序是一种用于监视和诊断Azure网络的工具。它提供了一种集中管理和监控网络流量、连接性和性能的方式。网络观察应用程序能够提供网络流量分析、连接监视、性能监视和故障诊断等功能,用于帮助管理员…...
分步注册方式 编写驱动
作业:通过分步注册方式,编写LED灯驱动:(驱动文件mycdev.c 测试文件test.c 头文件head.h) mycdev.c #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/io.h> …...

repmgr出现双主,并且时间线分叉,删除了最新的时间线节点
遇到的问题如下: 2023-08-17 20:24:21.566 CST [1556001] LOG: database system was interrupted; last known up at 2023-08-17 20:21:41 CST 2023-08-17 20:24:21.770 CST [1556001] LOG: restored log file "00000009.history" from archive cp: 无法…...
ThinkPHP中实现IP地址定位
在网站开发中,我们经常需要获取用户的地理位置信息以提供个性化的服务。一种常见的方法是通过IP地址定位。在本文中,我们将介绍如何在ThinkPHP框架中实现IP地址定位。 一、IP地址定位的基本原理 IP地址是Internet上的设备在网络中的标识符。每个设备都有…...

使用Python批量将Word文件转为PDF文件
说明:在使用Minio服务器时,无法对word文件预览,如果有需要的话,可以将word文件转为pdf文件,再存储到Minio中,本文介绍如何批量将word文件,转为pdf格式的文件; 安装库 首先ÿ…...

XDR解决方案成为了新的安全趋势
和当今指数倍增长的安全数据相比,安全人才的短缺带来了潜在的风险。几乎所有的公司,无论规模大小,在安全资源能力上都有限,需要过滤各种告警才能将分析量保持在可接受范围。但这样一来,潜在的威胁线索就可能被埋没&…...

001-Nacos 服务注册
目录 Nacos介绍注册中心架构面临问题源码分析实例注册-接口实例注册-入口实例注册-创建一个(Nacos)Service实例注册-注册(Nacos)Service Nacos 介绍 Dynamic Naming and Configuration Service 动态的命名和配置服务 反正可以实现注册中心的功能 注册中心架构 服务提供者 …...

71 # 协商缓存的配置:通过内容
对比(协商)缓存 比较一下再去决定是用缓存还是重新获取数据,这样会减少网络请求,提高性能。 对比缓存的工作原理 客户端第一次请求服务器的时候,服务器会把数据进行缓存,同时会生成一个缓存标识符&#…...

【服务器】Strace显示后台进程输出
今天有小朋友遇到一个问题 她想把2331509和2854637这两个进程调到前台来,以便于在当前shell查看这两个python进程的实时输出 我第一反应是用jobs -l然后fg (参考这里) 但是发现jobs -l根本没有输出: 原因是jobs看的是当前ses…...
centos如何安装libssl-dev libsdl-dev libavcodec-dev libavutil-dev ffmpeg
在 CentOS 系统上安装这些包可以按照以下步骤进行: 打开终端,使用 root 或具有管理员权限的用户登录。 使用以下命令安装 libssl-dev 包: yum install openssl-devel使用以下命令安装 libsdl-dev 包: yum install SDL-devel使用以…...

2022年12月 C/C++(二级)真题解析#中国电子学会#全国青少年软件编程等级考试
第1题:数组逆序重放 将一个数组中的值按逆序重新存放。例如,原来的顺序为8,6,5,4,1。要求改为1,4,5,6,8。 输入 输入为两行:第一行数组中元素的个数n(1 输出 输出为一行:输出逆序后数组的整数,每两个整数之间用空格分隔。 样例输入 5 8 6 5 4 1 样例输出 1 4 5 6 8 以下是…...

详谈MongoDB的那些事
概念区分 什么是关系型数据库 关系型数据库(Relational Database)是一种基于关系模型的数据库管理系统(DBMS)。在关系型数据库中,数据以表格的形式存储,表格由行和列组成,行表示数据记录&…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...

PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...
小木的算法日记-多叉树的递归/层序遍历
🌲 从二叉树到森林:一文彻底搞懂多叉树遍历的艺术 🚀 引言 你好,未来的算法大神! 在数据结构的世界里,“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的,它…...

jdbc查询mysql数据库时,出现id顺序错误的情况
我在repository中的查询语句如下所示,即传入一个List<intager>的数据,返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致,会导致返回的id是从小到大排列的,但我不希望这样。 Query("SELECT NEW com…...
js 设置3秒后执行
如何在JavaScript中延迟3秒执行操作 在JavaScript中,要设置一个操作在指定延迟后(例如3秒)执行,可以使用 setTimeout 函数。setTimeout 是JavaScript的核心计时器方法,它接受两个参数: 要执行的函数&…...