高教杯数学建模2020C题总结

news2024/9/24 3:23:19

🧡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-123
    for j in range(2017,2019+1): # 2017、2018、2019
        mulidx.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区别?

  1. 统计个数时,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其他有用的参数

  1. 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、第二列代表bins2
    width 设置柱形宽度
    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等处理得心应手 ~

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

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

相关文章

Java课题笔记~ 自定义拦截器实现权限验证

实现一个权限验证拦截器。 1、修改web.xml文件中请求路径 2、将所有的页面放入WEB-INF目录下 3、开发登录FirstController 4、开发拦截器 5、配置springmvc.xml文件 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.spri…

TDD(测试驱动开发)?

01、前言 很早之前&#xff0c;曾在网络上见到过 TDD 这 3 个大写的英文字母&#xff0c;它是 Test Driven Development 这三个单词的缩写&#xff0c;也就是“测试驱动开发”的意思——听起来很不错的一种理念。 其理念主要是确保两件事&#xff1a; 确保所有的需求都能被照…

Java SPI加载机制

SPI加载机制 SPI&#xff08;Service Provider Interface&#xff09;是一种通过外界配置来加载具体代码内容的技术手段。SPI是JDK内置的一种服务提供发现机制&#xff0c;用于实现框架的扩展和组件替换。 在SPI中&#xff0c;框架提供一整套接口&#xff0c;使用者实现这些接…

Android Studio实现解析HTML获取图片URL,将URL存到list,进行列表展示

目录 效果build.gradle(app)添加的依赖(用不上的可以不加)AndroidManifest.xml错误代码activity_main.xmlitem_image.xmlMainActivityImage适配器ImageModel 接收图片URL效果 build.gradle(app)添加的依赖(用不上的可以不加) dependencies {implementation com.square…

信息安全:VPN 技术原理与应用.

信息安全&#xff1a;VPN 技术原理与应用. VPN 是网络通信安全保护的常用技术。VPN 中文翻译为“虚拟专用网”&#xff0c;其基本技术原理是把需要经过公共网传递的报文 (packet) 加密处理后&#xff0c;再由公共网络发送到目的地。利用VPN 技术能够在不可信任的公共网络上构建…

PDF怎么转Word?8 个最佳 PDF 转 Word 转换器

PDF 转 Word 转换工具只是一个特殊程序&#xff0c;可以将 PDF&#xff08;本机和/或扫描&#xff09;转换为 Microsoft Office Word 格式。将 PDF 导出到 Word 的主要原因之一是满足可编辑文档的需求&#xff0c;尽管还有其他原因。 由于缺少 PDF 阅读器&#xff0c;您可以选…

实用的开源应用全新开源源码Vue3+TS的前后台分离的开发平台源码开源技术社区平台

开源全新开源源码Vue3TS的前后台分离的开发平台源码。创意、新奇、有趣、实用的开源应用、系统、软件、硬件及技术&#xff0c;一个探索、发现、分享、使用与互动交流的开源技术社区平台。致力于打造活力开源社区&#xff0c;共建开源新生态&#xff01; 功能简介 个人办公&a…

python的进度条tqdm库,显示时进度条不换行设置

问题描述 tqdm库&#xff0c;显示时进度条不要换行&#xff0c;直接在一行里显示当前进度 换行显示&#xff1a; 不换行显示 解决方案&#xff08;参考链接&#xff09; 添加参数position0 和 leaveTrue 举例&#xff1a; 修改前&#xff1a; import tqdm import time f…

树莓派上搭建WordPress博客网站,并通过内网穿透发布到公网

文章目录 概述安装 PHP安装MySQL数据库安装 Wordpress设置您的 WordPress 数据库设置 MySQL/MariaDB创建 WordPress 数据库 WordPress configuration将WordPress站点发布到公网安装相对URL插件修改config.php配置 支持好友链接样式定制主题 概述 在本次教程里&#xff0c;我们…

Markdown 入门基础

文章目录 Markdown 是什么&#xff1f;为什么要使用 Markdown?工欲善其事&#xff0c;必先利其器Markdown 的工作原理Markdown 有什么用&#xff1f;网站文件资料笔记书籍演示文稿邮件文档 Markdown 方言其它资源 Markdown 是什么&#xff1f; Markdown 是一种轻量级的标记语…

【Docker报错】docker拉取镜像时报错:no such host

报错信息 [rootSoft soft]# docker pull mysql Using default tag: latest Error response from daemon: Head "https://registry-1.docker.io/v2/library/mysql/manifests/latest": dial tcp: lookup registry-1.docker.io on 192.168.80.2:53: no such host解决方法…

ogg格式怎么转换为mp3?

ogg格式怎么转换为mp3&#xff1f;我们都知道&#xff0c;OGG格式作为一种数字饮片格式&#xff0c;使用的是有损压缩技术&#xff0c;从而也保证了文件音质较高。然而&#xff0c;也正是因为这个特点&#xff0c;导致OGG格式文件较大。很多时候&#xff0c;我们在使用OGG格式文…

内网穿透-外远程连接中的RabbitMQ服务

文章目录 前言1.安装erlang 语言2.安装rabbitMQ3. 内网穿透3.1 安装cpolar内网穿透(支持一键自动安装脚本)3.2 创建HTTP隧道 4. 公网远程连接5.固定公网TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 前言 RabbitMQ是一个在 AMQP(高级消息队列协议)基…

日志系统——日志格式化模块设计

一&#xff0c;模块主要成员 该模块的主要作用是对日志消息进行格式化&#xff0c;将日志消息组织成制定格式的字符串。 该模块主要成员有两个&#xff1a;1.格式化字符串。 2.格式化子项数组 1.1 格式化字符串 格式化字符串的主要功能是保存日志输出的格式字符串。其格式化字…

网络安全/黑客技术(就业前景与经验分享)

网络安全与我们每一个人都息息相关&#xff0c;无论是企业还是个人&#xff0c;现在都非常重视网络安全。而且网络安全是一个新兴的行业&#xff0c;人才需求量远远大于供给&#xff0c;所以在薪资福利上具有很大的优势&#xff0c;并且对于初学者而言&#xff0c;很多人依旧担…

ThreadPool线程池

文章目录 一.概述和架构二.使用方式和底层原理三.七个参数介绍四.工作流程和拒绝策略五.自定义线程池 一.概述和架构 一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能,而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务,这避免了在短时间…

文件名称是递增的,删除掉其中一部分的文件,导致递增文件缺少,通过python查找出缺少的递增文件名称

文件名称是递增的&#xff0c;删除掉其中一部分的文件&#xff0c;导致递增文件缺少&#xff0c;通过python查找出缺少的递增文件名称 通过python,查找出缺少的递增的文件的名称&#xff1a; 代码如下&#xff1a; import osdef find_missing_numbers(folder_path):file_list …

6000万美元?通用汽车投资初创新贵Mitra,开发“经济型电池”

根据最新消息&#xff0c;通用汽车公司日前宣布领导一轮6000万美元的B轮融资&#xff0c;投资对象为电池材料初创公司Mitra Chem。此次投资旨在帮助通用汽车改进未来电动汽车的电池制造&#xff0c;使其更加经济实惠且易获取。 目前&#xff0c;大多数电池使用的是镍和钴的制造…

linux系统--makefile文件,gdb 以及文件描述符

目录 1 makefile 1.1 makefile的基本规则 1.2 makefile工作原理 1.3 makefile中的变量 1.4 makefile函数 1.5 makefile的清理操作 2 gdb调试 2.1 gdb介绍 2.2 生成调试信息 2.3 启动gdb 2.4 显示源代码 3文件IO 3.1 C库IO函数的工作流程 3.2 C库函数与系统函数的…

Sigmastar SSC8826Q 2K行车记录仪解决方案

一、方案描述 行车记录仪是智能辅助汽车驾驶&#xff0c;和管理行车生活的车联网智能终端设备&#xff0c;利用智能芯片处理器、GPS定位、网络通信、自动控制等技术&#xff0c;将与行车生活有关的各项数据有机地结合在一起。 行车记录仪如今已经成了必不可少的车载用品之一&…