【数学建模】2018年数学建模国赛C题 问题一代码

article/2025/9/12 6:09:18

文章目录

  • 问题一代码
      • 导入包及数据
      • 数据探索与预处理
    • 会员统计分析
      • 分析会员的年龄构成、男女比例等基本信息
      • 分析会员的总订单占比,总消费金额占比等消费情况
      • 分别以季度和天为单位,分析不同时间段会员的消费时间偏好
      • 会员与非会员统计分析

问题一代码

本文从购买力、购买时间偏好两个维度分析会员的消费特征。
以会员消费总金额、消费次数、商品购买数量代表会员购买力;
同时按季节和天对会员消费行为进行消费时间偏好分析。
同时对会员及非会员的消费次数和消费金额进行对比分析。

导入包及数据

import matplotlib
import warnings
import re
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as pltfrom sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
from sklearn.preprocessing import StandardScaler,MinMaxScaler%matplotlib inline
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
matplotlib.rcParams.update({'font.size' : 16})
plt.style.use('ggplot')
warnings.filterwarnings('ignore')
data1=pd.read_excel('./2018-C-Chinese的副本/附件1-会员信息表.xlsx')
data2=pd.read_excel('./2018-C-Chinese的副本/附件3-会员消费明细表.xlsx')

数据探索与预处理

1.附件一会员信息表探索与预处理

#查看是否缺失数据
print('会员信息表一共有{}行记录,{}列'.format(data1.shape[0],data1.shape[1]))
print('数据缺失情况为:\n',data1.isnull().sum())
print('会员不重复卡号kh的信息有',len(data1['kh'].unique()))
#会员卡号去重
print("去除重复值前的数据量", data1.shape)   
data1.drop_duplicates(subset=['kh'],keep='first',inplace=True)
print("去除重复值后的数据量", data1.shape)  
#去除登记时间的缺失值,并去重
print("去除重复值前的数据量", data1.shape)   
data1.dropna(subset='djsj',inplace=True)
print("去除登记时间的缺失值,并去重数据量", data1.shape) 
#性别上缺失的比例较少,所以使用众数填充
data1['xb'].fillna(data1['xb'].mode().values[0],inplace=True)
#检验是否在登记时间这一字段中存在异常值,若存在异常值,则无法进行基本操作
data1_1 = data1['djsj'] + pd.Timedelta(days=1)
#查看处理完成的数据缺失值情况
data1.isnull().sum()
#对于出生日期的处理
#由于出生日期缺失值过多,且存在较多的异常值,不能贸然删除
#故下面另建一个数据集L来保存“出生日期”和‘性别’信息,方便下面对会员的性别和年龄信息进行统计
L = pd.DataFrame(data1.loc[data1['csny'].notnull(),['csny','xb']])
L['age'] = L['csny'].astype(str).apply(lambda x:x[0:3]+'0')
L.drop('csny',axis=1,inplace=True)
L['age'].value_counts()
# 出生日期这列中出现较多的异常值,以一个正常人寿命为100年算起,我们假定会员年龄范围在1922-2022年起
# 将超过该范围的值当作异常值进行剔除
L['age'] = L['age'].astype(int)
condaition = 'age >= 1922 and age <=2022'
L = L.query(condaition)
L.index = range(L.shape[0])
L['age'].value_counts()
# 用于与销售流水表进行合并的数据只取['会员卡号', '性别', '登记时间']这三列,将出生日期这列意义不大的进行删除(这列信息最有可能出错),并重置索引
data1.drop('csny', axis = 1, inplace = True)
data1.index = range(data1.shape[0])
print('数据清洗之后共有{}行记录,{}列字段,字段分别为{}'.format(data1.shape[0], data1.shape[1], data1.columns.tolist()))

2.附件三会员销售流水表
对于不是本地会员的会员当作非会员处理。

#检查是否含有缺失值
print('未处理时的数据数目:',data2.shape[0],data2.shape[1])
print('缺失值数据数目:',data2.isnull().sum())
#检查将售价、数量、金额、积分是否都大于0
print('商品售价大于0的数量:{} \t 全部记录有{}'.format(len(data2['sj']>0),len(data2['sj'])))
print('商品数量大于0的数量:{} \t 全部记录有{}'.format(len(data2['sl']>0),len(data2['sl'])))
print('会员积分大于0的数量:{} \t 全部记录有{}'.format(len(data2['jf']>0),len(data2['jf'])))
data2.drop(['syjh', 'gzbm', 'gzmc'], axis = 1, inplace = True)
# 重置索引
data2.index = range(data2.shape[0])

3.将会员信息表喝会员消费信息明细进行合并

#按照两表的卡号信息将两表合并,将附件2中有会员卡号的进行左合并,得到附件1会员和非会员的数据
data_merge = pd.merge(data2,data1,on='kh',how='left')
data_merge
# 再次查看金额>0,积分>0,数量>0
index1 = data_merge['je'] > 0
index2 = data_merge['jf'] > 0
index3 = data_merge['sl'] > 0
data_merge1 = data_merge.loc[index1 & index2 & index3,:]
data_merge1.index = range(data_merge1.shape[0])
data_merge1.shape
#创造字段检查其是否为会员
data_merge1['vip'] = 1
data_merge1
data_merge1.loc[data_merge1['xb'].isnull(),'vip'] = 0
data_merge1

4.处理附件二

data_total = pd.read_excel('./2018-C-Chinese的副本/附件2-销售流水表.xlsx')
print(data_total.shape)
print(data_total.isnull().sum()) #未发现缺失值
data_total = data_total.drop_duplicates()
print(data_total.shape)
#检查将售价、数量、金额、积分是否都大于0
print('商品售价大于0的数量:{} \t 全部记录有{}'.format(len(data_total['sj']>0),len(data_total['sj'])))
print('商品数量大于0的数量:{} \t 全部记录有{}'.format(len(data_total['sl']>0),len(data_total['sl'])))
print('积分大于0的数量:{} \t 全部记录有{}'.format(len(data_total['je']>0),len(data_total['je'])))
#检验是否在-登记时间这一字段中存在异常值,若存在异常值,则无法进行基本操作
data_total_1 = data_total['dtime'] + pd.Timedelta(days=1)
#经检验日期时间没有问题

5.附件二和上处理的一三合并的文件进行二次合并

#检查各个数据集长度
print(f'附件二{len(data_total)}\t附件一和三合并{len(data_merge1)}')
data23 = pd.merge(data_total,data_merge1,on=['dtime','spbm','je'],how='left')
data23.loc[data23['vip'].isnull(),'vip'] = 0
data23.drop(['kh','sj_y','sl_y','kh','xb','djsj'],axis=1,inplace=True)
fig, axs = plt.subplots(1, 2, figsize = (12, 7), dpi = 100)
axs[0].pie([len(data23.loc[data23['vip']==1,'dtime'].unique()),len(data23.loc[data23['vip']==0,'dtime'].unique())],labels = ['vip','normal'], wedgeprops = {'width': 0.4}, counterclock = False, autopct = '%.2f%%', pctdistance = 0.8)
axs[0].set_title('total dingdan%')
axs[1].pie([data23.loc[data23['vip'] == 1, 'je'].sum(), data23.loc[data23['vip'] == 0, 'je'].sum()], labels = ['vip', 'normal'], wedgeprops = {'width': 0.4}, counterclock = False, autopct = '%.2f%%', pctdistance = 0.8)
axs[1].set_title('total je%')

会员统计分析

分析会员的年龄构成、男女比例等基本信息

#处理男女比例这一列,女0,男1
L['xb'] = L['xb'].apply(lambda x:'male' if x==1 else 'female')
sex_sort = L['xb'].value_counts()
#将年龄划分为不同年龄段
#老年(1920-1950)、中年(1960-1990)、青年(1990-2010)
L['age group']='middle'
L.loc[L['age'] <= 1950,'age group'] = 'old'
L.loc[L['age'] >= 1990,'age group'] = 'young'
res = L['age group'].value_counts()
#使用上述预处理后的数据L,包含两个字段,分别是age和性别,先画出年龄条形图
fig, axs = plt.subplots(1,2,figsize=(16,7),dpi=100)
#绘制条形图
ax = sns.countplot(x='age',data = L,ax = axs[0])
for p in ax.patches:height = p.get_height()ax.text(x = p.get_x() + (p.get_width() / 2), y = height + 500, s = '{:.0f}'.format(height), ha = 'center')
axs[0].set_title('year of birth')
# 绘制饼图
axs[1].pie(sex_sort, labels = sex_sort.index, wedgeprops = {'width': 0.4}, counterclock = False, autopct = '%.2f%%', pctdistance = 0.8)
axs[1].set_title('male vs female')

在这里插入图片描述

# 绘制各个年龄段的饼图
plt.figure(figsize = (8, 6), dpi = 100)
plt.pie(res.values, labels = ['middle', 'young', 'old'], autopct = '%.2f%%', pctdistance = 0.8, counterclock = False, wedgeprops = {'width': 0.4})
plt.title('fenbu')
#plt.savefig('./age fenbu.png')

分析会员的总订单占比,总消费金额占比等消费情况

fig, axs = plt.subplots(1, 2, figsize = (12, 7), dpi = 100)
axs[0].pie([len(data_merge1.loc[data_merge1['vip']==1,'dtime'].unique()),len(data_merge1.loc[data_merge1['vip']==0,'dtime'].unique())],labels = ['vip','normal'], wedgeprops = {'width': 0.4}, counterclock = False, autopct = '%.2f%%', pctdistance = 0.8)
axs[0].set_title('total dingdan%')
axs[1].pie([data_merge1.loc[data_merge1['vip'] == 1, 'je'].sum(), data_merge1.loc[data_merge1['vip'] == 0, 'je'].sum()], labels = ['vip', 'normal'], wedgeprops = {'width': 0.4}, counterclock = False, autopct = '%.2f%%', pctdistance = 0.8)
axs[1].set_title('total je%')

在这里插入图片描述

分别以季度和天为单位,分析不同时间段会员的消费时间偏好

不同季度和天为单位的消费时间偏好

# 将会员的消费数据另存为另一个数据集
df_vip = df1.dropna()
df_vip.drop(['会员'], axis = 1, inplace = True)
df_vip.index = range(df_vip.shape[0])
df_vip.info()
# 将“消费产生的时间”转变成日期格式
df_vip['消费产生的时间'] = pd.to_datetime(df_vip['消费产生的时间'])
# 新增四列数据,季度、天、年份和月份的字段
df_vip['年份'] = df_vip['消费产生的时间'].dt.year
df_vip['月份'] = df_vip['消费产生的时间'].dt.month
df_vip['季度'] = df_vip['消费产生的时间'].dt.quarter
df_vip['天'] = df_vip['消费产生的时间'].dt.day
df_vip.head()
# 前提假设:2015-2018年之间,消费者偏好在时间上不会发生太大的变化(均值),消费偏好——>以不同时间的订单数来衡量
quarters_list, quarters_order = orders(df_vip, '季度', 3)
days_list, days_order = orders(df_vip, '天', 36)
time_list = [quarters_list, days_list]
order_list = [quarters_order, days_order]
maxindex_list = [quarters_order.index(max(quarters_order)), days_order.index(max(days_order))]
fig, axs = plt.subplots(1, 2, figsize = (18, 7), dpi = 100)
colors = np.random.choice(['r', 'g', 'b', 'orange', 'y'], replace = False, size = len(axs))
titles = ['季度的均值消费偏好', '天数的均值消费偏好']
labels = ['季度', '天数']
for i in range(len(axs)):ax = axs[i]ax.plot(time_list[i], order_list[i], linestyle = '-.', c = colors[i], marker = 'o', alpha = 0.85)ax.axvline(x = time_list[i][maxindex_list[i]], linestyle = '--', c = 'k', alpha = 0.8)ax.set_title(titles[i])ax.set_xlabel(labels[i])ax.set_ylabel('均值消费订单数')print(f'{titles[i]}最优的时间为: {time_list[i][maxindex_list[i]]}\t 对应的均值消费订单数为: {order_list[i][maxindex_list[i]]}')
plt.savefig('./季度和天数的均值消费偏好情况.png')

在这里插入图片描述
不同年份之间的的季度或天数的消费订单差异

# 自定义函数来绘制不同年份之间的的季度或天数的消费订单差异
def plot_qd(df, label_y, label_m, nrow, ncol):"""df: 为DataFrame的数据集label_y: 为年份的字段标签label_m: 为标签的一个列表n_row: 图的行数n_col: 图的列数"""# 必须去掉最后一年的数据,只能对2015-2017之间的数据进行分析y_list = np.sort(df[label_y].unique().tolist())[:-1]colors = np.random.choice(['r', 'g', 'b', 'orange', 'y', 'k', 'c', 'm'], replace = False, size = len(y_list))markers = ['o', '^', 'v']plt.figure(figsize = (8, 6), dpi = 100)fig, axs = plt.subplots(nrow, ncol, figsize = (16, 7), dpi = 100)for k in range(len(label_m)):m_list = np.sort(df[label_m[k]].unique().tolist())for i in range(len(y_list)):order_m = []index1 = df[label_y] == y_list[i]for j in range(len(m_list)):index2 = df[label_m[k]] == m_list[j]order_m.append(len(df.loc[index1 & index2, '消费产生的时间'].unique()))axs[k].plot(m_list, order_m, linestyle ='-.', c = colors[i], alpha = 0.8, marker = markers[i], label = y_list[i], markersize = 4)axs[k].set_xlabel(f'{label_m[k]}')axs[k].set_ylabel('消费订单数')axs[k].set_title(f'2015-2018年会员的{label_m[k]}消费订单差异')axs[k].legend()plt.savefig(f'./2015-2018年会员的{"和".join(label_m)}消费订单差异.png')
plot_qd(df_vip, '年份', ['季度', '天'], 1, 2)

在这里插入图片描述
不同年份之间的月份消费订单差异

# 自定义函数来绘制不同年份之间的月份消费订单差异
def plot_ym(df, label_y, label_m):"""df: 为DataFrame的数据集label_y: 为年份的字段标签label_m: 为月份的字段标签"""# 必须去掉最后一年的数据,只能对2015-2017之间的数据进行分析y_list = np.sort(df[label_y].unique().tolist())[:-1]m_list = np.sort(df[label_m].unique().tolist())colors = np.random.choice(['r', 'g', 'b', 'orange', 'y'], replace = False, size = len(y_list))markers = ['o', '^', 'v']fig, axs = plt.subplots(1, 2, figsize = (18, 8), dpi = 100)for i in range(len(y_list)):order_m = []money_m = []index1 = df[label_y] == y_list[i]for j in range(len(m_list)):index2 = df[label_m] == m_list[j]order_m.append(len(df.loc[index1 & index2, '消费产生的时间'].unique()))money_m.append(df.loc[index1 & index2, '消费金额'].sum())axs[0].plot(m_list, order_m, linestyle ='-.', c = colors[i], alpha = 0.8, marker = markers[i], label = y_list[i])axs[1].plot(m_list, money_m, linestyle ='-.', c = colors[i], alpha = 0.8, marker = markers[i], label = y_list[i])axs[0].set_xlabel('月份')axs[0].set_ylabel('消费订单数')axs[0].set_title('2015-2018年会员的消费订单差异')axs[1].set_xlabel('月份')axs[1].set_ylabel('消费金额总数')axs[1].set_title('2015-2018年会员的消费金额差异')axs[0].legend()axs[1].legend()plt.savefig('./2015-2018年会员的消费订单和金额差异.png')
# 调用函数
plot_ym(df_vip, '年份', '月份')

在这里插入图片描述

# 再来分析下时间上的差差异——消费订单数
df_vip['时间'] = df_vip['消费产生的时间'].dt.hour
x_list, order_nums = orders(df_vip, '时间', 1)
maxindex = order_nums.index(max(order_nums))
plt.figure(figsize = (8, 6), dpi = 100)
plt.plot(x_list, order_nums, linestyle = '-.', marker = 'o', c = 'm', alpha = 0.8)
plt.xlabel('小时')
plt.ylabel('消费订单')
plt.axvline(x = x_list[maxindex], linestyle = '--', c = 'r', alpha = 0.6)
plt.title('2015-2018年各段小时的销售订单数')
plt.savefig('./2015-2018年各段小时的销售订单数.png')

在这里插入图片描述

会员与非会员统计分析

fig, axs = plt.subplots(1, 2, figsize = (12, 7), dpi = 100)
axs[0].pie([len(data23.loc[data23['vip']==1,'dtime'].unique()),len(data23.loc[data23['vip']==0,'dtime'].unique())],labels = ['vip','normal'], wedgeprops = {'width': 0.4}, counterclock = False, autopct = '%.2f%%', pctdistance = 0.8)
axs[0].set_title('total dingdan%')
axs[1].pie([data23.loc[data23['vip'] == 1, 'je'].sum(), data23.loc[data23['vip'] == 0, 'je'].sum()], labels = ['vip', 'normal'], wedgeprops = {'width': 0.4}, counterclock = False, autopct = '%.2f%%', pctdistance = 0.8)
axs[1].set_title('total je%')

在这里插入图片描述


http://chatgpt.dhexx.cn/article/gueJ2uKf.shtml

相关文章

美赛真题和优秀论文(2019-2021)

无偿提供2019-2021年美赛真题、数据、O奖论文 部分示例&#xff1a; 资源地址&#xff1a;MCM ICM (gitee.com) 如有资源丢失情况&#xff0c;可后台私信获取 一次参赛&#xff0c;受益终身

2020年美赛A题总结

2020年美赛A题总结 更新 最近很多朋友都想看一看论文&#xff0c;我平时不怎么上csdn&#xff0c;可能无法及时发给大家&#xff0c;故上传了论文资源。 祝大家美赛顺利&#xff01; https://download.csdn.net/download/hroukie/14727940 ————分割线———— 更新下&am…

2020美赛建模C题思路和理解

思路和理解 问题中心&#xff1a;评论数据星级建模 简要思路&#xff1a;理解成京东淘宝商城的评论数据&#xff0c;解释4.8星的指数怎么来的&#xff0c;你对商品的一段评论对该等级有多大影响&#xff1f; 个人的习惯是大数据问题第四章单独写数据清洗&#xff0c;具体流程看…

2023年美赛春季赛 赛题浅析

由于今年各种各样的原因&#xff0c;导致美赛头一次&#xff0c;据说也将是最后一次&#xff0c;临时调整&#xff0c;加设春季赛。这对于急需建模奖项的大家来说是一个很好的机会。无论怎样的原因&#xff0c;今年美赛我们可能有所遗憾。但&#xff0c;春季赛也许就是弥补遗憾…

【备战美赛】重要!2023年美赛官方发布最新通知

备战美赛 春节假期结束&#xff0c;各项比赛也需要准备起来啦&#xff01;近日&#xff0c;美赛组委会发布了2023年官方最新邮件&#xff0c;邮件内容主要是介绍本届竞赛基本情况、参赛规则、竞赛奖励、资源下载等相关内容&#xff0c;确定了比赛时间为北京时间2月17日-2月21日…

2018美赛B题总结

Update 2019/07/26:根据读者提出的问题&#xff0c;添加了查找数据方法、时间安排、论文及代码的下载地址等内容。 前言 本文主要是记录这次建模的过程和思路。用到的模型简单提及&#xff0c;并省略数据和结论。 涉及到的最小二乘法、模糊数学模型和马尔科夫链知识可以见我…

[数模美赛]2018数学建模美赛MCM总结

前言 说实话自己已经很久没有更新博客了&#xff0c;一方面是自己在这地方天天摸鱼&#xff0c;不好好学习&#xff0c;没什么可以更新的东西&#xff1b;令一方面&#xff0c;自己是在太懒&#xff0c;没办法&#xff0c;毕竟在一个非211、985学校的所谓“实验班”待着&#x…

2018美赛建模总结+Latex标准美赛模板分享

比赛经验总结 2018年2月13号上午9点&#xff0c;美赛建模比赛截止&#xff01;接下来&#xff0c;分享一下我的感受和经验&#xff1a; 2018年的美赛数学建模是2月9号开始的&#xff0c;然后我们从他官网开始放题的时候&#xff0c;就下载下来&#xff0c;三个人一块商量选题…

【明解C语言】循环语句之while

目录 一、while语句 1&#xff1a;语法结构&#xff1a; 2.while语句的三个部分 二、while语句代码示例&#xff1a; 1.在屏幕上输出1~10 2.while循环流程图&#xff1a; 三、break循环语句中的作用 四、continue在循环语句中的作用 五、getchar()函数代码分析 1.g…

c语言while的知识点,C语言循环语句知识点

C语言循环语句知识点 引导语&#xff1a;循环语句是由循环体及循环的终止条件两部分组成的。以下是百分网小编分享给大家的C语言循环语句知识点&#xff0c;欢迎参考学习! 循环语句 (一)、for循环 它的一般形式为: for(;;) 语句; 初始化总是一个赋值语句&#xff0c;它用来给循…

C语言详解系列——循环语句详解(1)while语句的语法结构

文章目录 while语句breakcontinue while语句 之前的学习中我们了解到了if语句的用法&#xff0c;这个语句只会执行一次&#xff0c;但在我们的生活当中有许多事情是需要重复去做的&#xff0c;那我们应该怎么实现呢&#xff1f;C语言当中给我们引入了&#xff1a;while语句&am…

C语言 do while语句的用法

目录 1.如何选择循环 2.do while语句 3.do while流程图 4.do while循环的使用 1.如何选择循环 如何选择使用哪一种循环?首先&#xff0c;确定是需要入口条件循环还是出口条件循环。通常&#xff0c;入口条件循环用得比较多&#xff0c;有几个原因。其一&#xff0c;一般原则…

C语言之while语句简述

C语言中的while语句是一个循环语句&#xff0c;它的结构为&#xff1a; while(表达式) { 语句; . . . . . . . . . . } 当表达式为真时&#xff0c;就执行下面的语句&#xff0c;再判断表达式是否为真&#xff0c;为真则继续执行&#xff0c;再判断表达式的值………&#xff0c…

c语言while的作用范围,C语言中While语句使用规则

很简单&#xff1a; 如果表达式为条件成立&#xff0c;则执行循环体的内容&#xff1b; 如果表达式为条件不成立&#xff0c;则不执行循环体的内容 例如&#xff1a; 执行的结果很简单&#xff0c;每隔一秒钟打印一句 “hello world”&#xff0c;一共五次 此时 a>0 &#x…

C语言循环语句while

C语言中有三种循环语句&#xff1a;while语句、do while语句、for语句 while循环&#xff1a; 简单while循环示例&#xff1a; //输出1-10 int main() {int i 1;while (i < 10){printf("%d\n", i);i;}return 0; } while语句中break和continue的作用 1.break…

C语言while语句从1加到n

#include<stdio.h> int main() {int sum,m 1 , n;printf("请输入n 的值&#xff1a;\n");scanf("%d",&n);while (m < n ){sum sum m;m;}printf("值为&#xff1a;%d", sum);return 0; } 实例&#xff1a;

C语言 while语句中的break与continue

break和continue都是用来结束循环的&#xff0c;但是二者还是有区别的。具体请看下文&#xff1a; break使用示例 上述代码可以看出循环中只要遇到break&#xff0c;就停止后期的所有的循环&#xff0c;直接终止循环。 所以while中的 break是用于永久终止循环的。 continue使用…

c语言无法跳出while语句,c语言while语句的用法 该循环永远不会结束

导读:说到语句,我们很多人都知道,有朋友问c语言中while的用法,另外,还有朋友想问c语言的while循环语句,这到底怎么回事呢?事实上c语言while的限制呢,今天小编整理了c语言while语句的用法,希望能帮到大家。 c语言while语句的用法 C语言中while的用法解析如下: 一、1表…

c语言while将字符循环,C语言 while语句的用法详解

在C语言中,共有三大常用的程序结构: 顺序结构:代码从前往后执行,没有任何“拐弯抹角”; 选择结构:也叫分支结构,重点要掌握 if else、switch 以及条件运算符; 循环结构:重复执行同一段代码。 前面讲解了顺序结构和选择结构,本节开始讲解循环结构。所谓循环(Loop),就…

C语言—while语句

#include <stdio.h>int main() {int i 0;while (i < 100){printf("%d\t", i);i;} } 只要表达式为真就一直执行循环体里的语句&#xff1b; 当i<100的是否&#xff0c;打印i的值&#xff0c;i自加1&#xff1b; 打印0到99后&#xff0c;i等于100的时候&…