問題一代碼
本文從購買力、購買時間偏好兩個維度分析會員的消費(fèi)特征。
以會員消費(fèi)總金額、消費(fèi)次數(shù)、商品購買數(shù)量代表會員購買力;
同時按季節(jié)和天對會員消費(fèi)行為進(jìn)行消費(fèi)時間偏好分析。
同時對會員及非會員的消費(fèi)次數(shù)和消費(fèi)金額進(jìn)行對比分析。
導(dǎo)入包及數(shù)據(jù)
import matplotlib
import warnings
import re
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from 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-會員消費(fèi)明細(xì)表.xlsx')
數(shù)據(jù)探索與預(yù)處理
1.附件一會員信息表探索與預(yù)處理
#查看是否缺失數(shù)據(jù)
print('會員信息表一共有{}行記錄,{}列'.format(data1.shape[0],data1.shape[1]))
print('數(shù)據(jù)缺失情況為:\n',data1.isnull().sum())
print('會員不重復(fù)卡號kh的信息有',len(data1['kh'].unique()))
#會員卡號去重
print("去除重復(fù)值前的數(shù)據(jù)量", data1.shape)
data1.drop_duplicates(subset=['kh'],keep='first',inplace=True)
print("去除重復(fù)值后的數(shù)據(jù)量", data1.shape)
#去除登記時間的缺失值,并去重
print("去除重復(fù)值前的數(shù)據(jù)量", data1.shape)
data1.dropna(subset='djsj',inplace=True)
print("去除登記時間的缺失值,并去重?cái)?shù)據(jù)量", data1.shape)
#性別上缺失的比例較少,所以使用眾數(shù)填充
data1['xb'].fillna(data1['xb'].mode().values[0],inplace=True)
#檢驗(yàn)是否在登記時間這一字段中存在異常值,若存在異常值,則無法進(jìn)行基本操作
data1_1 = data1['djsj'] + pd.Timedelta(days=1)
#查看處理完成的數(shù)據(jù)缺失值情況
data1.isnull().sum()
#對于出生日期的處理
#由于出生日期缺失值過多,且存在較多的異常值,不能貿(mào)然刪除
#故下面另建一個數(shù)據(jù)集L來保存“出生日期”和‘性別’信息,方便下面對會員的性別和年齡信息進(jìn)行統(tǒng)計(jì)
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()
# 出生日期這列中出現(xiàn)較多的異常值,以一個正常人壽命為100年算起,我們假定會員年齡范圍在1922-2022年起
# 將超過該范圍的值當(dāng)作異常值進(jìn)行剔除
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()
# 用于與銷售流水表進(jìn)行合并的數(shù)據(jù)只取['會員卡號', '性別', '登記時間']這三列,將出生日期這列意義不大的進(jìn)行刪除(這列信息最有可能出錯),并重置索引
data1.drop('csny', axis = 1, inplace = True)
data1.index = range(data1.shape[0])
print('數(shù)據(jù)清洗之后共有{}行記錄,{}列字段,字段分別為{}'.format(data1.shape[0], data1.shape[1], data1.columns.tolist()))
2.附件三會員銷售流水表
對于不是本地會員的會員當(dāng)作非會員處理。
#檢查是否含有缺失值
print('未處理時的數(shù)據(jù)數(shù)目:',data2.shape[0],data2.shape[1])
print('缺失值數(shù)據(jù)數(shù)目:',data2.isnull().sum())
#檢查將售價、數(shù)量、金額、積分是否都大于0
print('商品售價大于0的數(shù)量:{} \t 全部記錄有{}'.format(len(data2['sj']>0),len(data2['sj'])))
print('商品數(shù)量大于0的數(shù)量:{} \t 全部記錄有{}'.format(len(data2['sl']>0),len(data2['sl'])))
print('會員積分大于0的數(shù)量:{} \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.將會員信息表喝會員消費(fèi)信息明細(xì)進(jìn)行合并
#按照兩表的卡號信息將兩表合并,將附件2中有會員卡號的進(jìn)行左合并,得到附件1會員和非會員的數(shù)據(jù)
data_merge = pd.merge(data2,data1,on='kh',how='left')
data_merge
# 再次查看金額>0,積分>0,數(shù)量>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
#創(chuàng)造字段檢查其是否為會員
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()) #未發(fā)現(xiàn)缺失值
data_total = data_total.drop_duplicates()
print(data_total.shape)
#檢查將售價、數(shù)量、金額、積分是否都大于0
print('商品售價大于0的數(shù)量:{} \t 全部記錄有{}'.format(len(data_total['sj']>0),len(data_total['sj'])))
print('商品數(shù)量大于0的數(shù)量:{} \t 全部記錄有{}'.format(len(data_total['sl']>0),len(data_total['sl'])))
print('積分大于0的數(shù)量:{} \t 全部記錄有{}'.format(len(data_total['je']>0),len(data_total['je'])))
#檢驗(yàn)是否在-登記時間這一字段中存在異常值,若存在異常值,則無法進(jìn)行基本操作
data_total_1 = data_total['dtime'] + pd.Timedelta(days=1)
#經(jīng)檢驗(yàn)日期時間沒有問題
5.附件二和上處理的一三合并的文件進(jìn)行二次合并
#檢查各個數(shù)據(jù)集長度
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%')
會員統(tǒng)計(jì)分析
分析會員的年齡構(gòu)成、男女比例等基本信息
#處理男女比例這一列,女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()
#使用上述預(yù)處理后的數(shù)據(jù)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')
分析會員的總訂單占比,總消費(fèi)金額占比等消費(fèi)情況
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%')
分別以季度和天為單位,分析不同時間段會員的消費(fèi)時間偏好
不同季度和天為單位的消費(fèi)時間偏好
# 將會員的消費(fèi)數(shù)據(jù)另存為另一個數(shù)據(jù)集
df_vip = df1.dropna()
df_vip.drop(['會員'], axis = 1, inplace = True)
df_vip.index = range(df_vip.shape[0])
df_vip.info()
# 將“消費(fèi)產(chǎn)生的時間”轉(zhuǎn)變成日期格式
df_vip['消費(fèi)產(chǎn)生的時間'] = pd.to_datetime(df_vip['消費(fèi)產(chǎn)生的時間'])
# 新增四列數(shù)據(jù),季度、天、年份和月份的字段
df_vip['年份'] = df_vip['消費(fèi)產(chǎn)生的時間'].dt.year
df_vip['月份'] = df_vip['消費(fèi)產(chǎn)生的時間'].dt.month
df_vip['季度'] = df_vip['消費(fèi)產(chǎn)生的時間'].dt.quarter
df_vip['天'] = df_vip['消費(fèi)產(chǎn)生的時間'].dt.day
df_vip.head()
# 前提假設(shè):2015-2018年之間,消費(fèi)者偏好在時間上不會發(fā)生太大的變化(均值),消費(fèi)偏好——>以不同時間的訂單數(shù)來衡量
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 = ['季度的均值消費(fèi)偏好', '天數(shù)的均值消費(fèi)偏好']
labels = ['季度', '天數(shù)']
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('均值消費(fèi)訂單數(shù)')
print(f'{titles[i]}最優(yōu)的時間為: {time_list[i][maxindex_list[i]]}\t 對應(yīng)的均值消費(fèi)訂單數(shù)為: {order_list[i][maxindex_list[i]]}')
plt.savefig('./季度和天數(shù)的均值消費(fèi)偏好情況.png')
不同年份之間的的季度或天數(shù)的消費(fèi)訂單差異
# 自定義函數(shù)來繪制不同年份之間的的季度或天數(shù)的消費(fèi)訂單差異
def plot_qd(df, label_y, label_m, nrow, ncol):
"""
df: 為DataFrame的數(shù)據(jù)集
label_y: 為年份的字段標(biāo)簽
label_m: 為標(biāo)簽的一個列表
n_row: 圖的行數(shù)
n_col: 圖的列數(shù)
"""
# 必須去掉最后一年的數(shù)據(jù),只能對2015-2017之間的數(shù)據(jù)進(jìn)行分析
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, '消費(fèi)產(chǎn)生的時間'].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('消費(fèi)訂單數(shù)')
axs[k].set_title(f'2015-2018年會員的{label_m[k]}消費(fèi)訂單差異')
axs[k].legend()
plt.savefig(f'./2015-2018年會員的{"和".join(label_m)}消費(fèi)訂單差異.png')
plot_qd(df_vip, '年份', ['季度', '天'], 1, 2)
不同年份之間的月份消費(fèi)訂單差異
# 自定義函數(shù)來繪制不同年份之間的月份消費(fèi)訂單差異
def plot_ym(df, label_y, label_m):
"""
df: 為DataFrame的數(shù)據(jù)集
label_y: 為年份的字段標(biāo)簽
label_m: 為月份的字段標(biāo)簽
"""
# 必須去掉最后一年的數(shù)據(jù),只能對2015-2017之間的數(shù)據(jù)進(jìn)行分析
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, '消費(fèi)產(chǎn)生的時間'].unique()))
money_m.append(df.loc[index1 & index2, '消費(fèi)金額'].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('消費(fèi)訂單數(shù)')
axs[0].set_title('2015-2018年會員的消費(fèi)訂單差異')
axs[1].set_xlabel('月份')
axs[1].set_ylabel('消費(fèi)金額總數(shù)')
axs[1].set_title('2015-2018年會員的消費(fèi)金額差異')
axs[0].legend()
axs[1].legend()
plt.savefig('./2015-2018年會員的消費(fèi)訂單和金額差異.png')
# 調(diào)用函數(shù)
plot_ym(df_vip, '年份', '月份')
# 再來分析下時間上的差差異——消費(fèi)訂單數(shù)
df_vip['時間'] = df_vip['消費(fèi)產(chǎn)生的時間'].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('消費(fèi)訂單')
plt.axvline(x = x_list[maxindex], linestyle = '--', c = 'r', alpha = 0.6)
plt.title('2015-2018年各段小時的銷售訂單數(shù)')
plt.savefig('./2015-2018年各段小時的銷售訂單數(shù).png')
文章來源:http://www.zghlxwxcb.cn/news/detail-633826.html
會員與非會員統(tǒng)計(jì)分析
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://www.zghlxwxcb.cn/news/detail-633826.html
到了這里,關(guān)于【數(shù)學(xué)建?!?018年數(shù)學(xué)建模國賽C題 問題一代碼的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!