優(yōu)惠券使用情況數(shù)據(jù)分析(源碼自用)
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import seaborn as sns? ? # 繪圖模塊,基于matplotlib的可視化python包,不能完全替代matplotlib,只是對(duì)matplotlib進(jìn)行升級(jí)
plt.rcParams['font.sans-serif'] = ['SimHei']? ?# 用來正常顯示中文標(biāo)簽
plt.rcParams['axes.unicode_minus'] = False? ? # 用來正常顯示負(fù)號(hào)
"""
1.加載數(shù)據(jù)
parse_dates:將指定的列加載成日期的格式
"""
offline = pd.read_csv('ccf_offline_stage1_train.csv', parse_dates=['Date_received', 'Date'])
"""
2.數(shù)據(jù)的規(guī)整
判斷每一列當(dāng)中有多少個(gè)空值
offline.isnull().sum()
2.1 把“Discount_rate”列中的滿減政策轉(zhuǎn)換成折扣率
offline['Discount_rate'] = offline['Discount_rate'].fillna('null')
def discount_rate_opt(s):? ?# s代表每一個(gè)元素
? ? if ':' in s:
? ? ? ? split = s.split(':')
? ? ? ? discount_rate = (int(split[0]) - int(split[1]))/int(split[0])
? ? ? ? return round(discount_rate, 2)? ? # 折扣率保留兩位小數(shù)
? ? elif s == 'null':
? ? ? ? return np.NaN
? ? else:
? ? ? ? return float(s)
offline['Discount_rate'] = offline['Discount_rate'].map(discount_rate_opt)
2.2 Coupon_id字段:null代表無優(yōu)惠券,此時(shí)Discount_rate與Date_received字段無意義。檢查Coupon_id與Discount_rate和Date_received判斷空值和非空值是否一一對(duì)應(yīng)
# np.all():判斷一個(gè)可迭代數(shù)據(jù)中是否都為True,如果是返回True,否則返回False
nan1 = offline['Coupon_id'].isnull()? ? # 判斷優(yōu)惠券是否為空
nan2 = offline['Date_received'].isnull()? ? # 判斷領(lǐng)券日期是否為空
nan3 = offline['Discount_rate'].isnull()
np.all(nan1 == nan2)? ? # 如果結(jié)果為True,說明Coupon_id與Date_received空值與非空值是一一對(duì)應(yīng)的關(guān)系
np.all(nan1 == nan3)? ? # 如果結(jié)果為True,說明Coupon_id與Discount_rate空值與非空值是一一對(duì)應(yīng)的關(guān)系
2.3 消費(fèi)情況判斷
如果Date == null & Coupon_id != null,有券未消費(fèi)(coupon_no_consume)
如果Date == null & Coupon_id == null,無券未消費(fèi)(no_coupon_no_consume)
如果Date != null & Coupon_id == null,無券消費(fèi)(no_coupon_consume)
如果Date != null & Coupon_id != null,有券消費(fèi)(coupon_consume)
"""
coupon_no_consume = offline[(offline['Date'].isnull() & offline['Coupon_id'].notnull())]
no_coupon_no_consume = offline[(offline['Date'].isnull() & offline['Coupon_id'].isnull())]
no_coupon_consume = offline[(offline['Date'].notnull() & offline['Coupon_id'].isnull())]
coupon_consume = offline[(offline['Date'].notnull() & offline['Coupon_id'].notnull())]
"""
print('有券未消費(fèi):{}'.format(len(coupon_no_consume)))
print('無券未消費(fèi):{}'.format(len(no_coupon_no_consume)))? ? # 無意義,不需分析
print('無券消費(fèi):{}'.format(len(no_coupon_consume)))
print('有券消費(fèi):{}'.format(len(coupon_consume)))
# 用優(yōu)惠券消費(fèi)的有7萬,相比其他用戶來說,占比較少
3.數(shù)據(jù)分析
# 繪制餅圖占比
consume_status_dict = {'coupon_no_consume': len(coupon_no_consume),
? ? ? ? ? ? ? ? ? ? ? ?'no_coupon_consume': len(no_coupon_consume),
? ? ? ? ? ? ? ? ? ? ? ?'coupon_consume': len(coupon_consume)}
consume_status = pd.Series(consume_status_dict)
# 消費(fèi)方式構(gòu)成的餅圖(figure:看作是一張畫布,axes:代表畫布內(nèi)的多個(gè)坐標(biāo)系)
fig, ax = plt.subplots(1, 1, figsize=(8, 10), dpi=240)
consume_status.plot.pie(ax=ax,
? ? ? ? ? ? ? ? ? ? ? ? autopct='%1.1f%%',
? ? ? ? ? ? ? ? ? ? ? ? shadow=True,
? ? ? ? ? ? ? ? ? ? ? ? explode=[0.02, 0.05, 0.2],
? ? ? ? ? ? ? ? ? ? ? ? textprops={'fontsize': 15, 'color': 'blue'},
? ? ? ? ? ? ? ? ? ? ? ? wedgeprops={'linewidth': 1, 'edgecolor': 'black'},
? ? ? ? ? ? ? ? ? ? ? ? labels=['有券未消費(fèi) \n ({})'.format(len(coupon_no_consume)),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? '無券消費(fèi) \n ({})'.format(len(no_coupon_consume)),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? '有券消費(fèi) \n ({})'.format(len(coupon_consume)),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ]
? ? ? ? ? ? ? ? ? ? ? ? )
ax.set_ylabel('')? ?# 去除ylabel
ax.set_title('消費(fèi)占比情況')
plt.legend(labels=['有券未消費(fèi)', '無券消費(fèi)', '有券消費(fèi)'])
# 有券未消費(fèi)占比55.7%最大,說明大多數(shù)人拿完券之后,尚未使用;無券消費(fèi)用戶占比40%,說明很多人沒有使用優(yōu)惠券,可能優(yōu)惠券的吸引力不大,客戶沒在意或者新用戶比較多;用券消費(fèi)用戶比較小,占4.3%,說明優(yōu)惠券使用率不高,可以考慮是不是加大優(yōu)惠券力度......

3.1在有券消費(fèi)人群中,分析距離和優(yōu)惠折扣
# 各商家對(duì)應(yīng)的顧客到點(diǎn)平均距離
Merchant_distance = coupon_consume.groupby('Merchant_id')['Distance'].mean()
print(Merchant_distance[Merchant_distance == 0])
# 有4076個(gè)商家,有1431個(gè)商家的用券消費(fèi)用戶平均范圍在500米以內(nèi)
# 各商家對(duì)應(yīng)的顧客到點(diǎn)消費(fèi)平均折扣力度
Merchant_discount_rate = coupon_consume.groupby('Merchant_id')['Discount_rate'].mean()
Merchant_discount_rate.sort_values()
Merchant_discount_rate.hist()
print(Merchant_discount_rate.mean())
# 所有商家平均折扣的平均值:0.88
3.2 持券到店消費(fèi)人數(shù)最多的商家
# 對(duì)商家進(jìn)行分組,取出用戶id,對(duì)用戶id進(jìn)行去重統(tǒng)計(jì)數(shù)量
popular_merchant = coupon_consume.groupby('Merchant_id')['User_id'].apply(lambda x: len(x.unique())).sort_values(ascending=False)
# 找出持券消費(fèi)人數(shù)>500的商家id
popular_merchant500 = popular_merchant[popular_merchant > 500]
# 共有16家店鋪,持券消費(fèi)人數(shù)在500人以上,持券消費(fèi)人數(shù)最多商家是5341,持券消費(fèi)人數(shù)在2800,排名最后的商家,持券消費(fèi)人數(shù)為559人,這批商家對(duì)優(yōu)惠券的使用方法得當(dāng),消費(fèi)者喜歡用消費(fèi)券進(jìn)行消費(fèi),可以適當(dāng)借鑒這批商家的推廣力度
3.3 持券消費(fèi)人數(shù)在500人以上的商家,連接顧客到店平均距離和平均折扣力度
merchant_pop_dis = pd.merge(left=popular_merchant500, right=Merchant_distance, on='Merchant_id', how='inner')
merchant_pop_dis_rate = pd.merge(left=merchant_pop_dis, right=Merchant_discount_rate, on='Merchant_id', how='inner')
3.4計(jì)算到點(diǎn)消費(fèi)人數(shù)與平均距離和折扣力度的相關(guān)系數(shù)
corr(correlation:相關(guān)系數(shù)),用來計(jì)算df數(shù)據(jù)中列與列的相關(guān)性(皮爾遜相關(guān)系數(shù)),取值范圍[-1,1]之間
1:完全正相關(guān),-1:完全負(fù)相關(guān);絕對(duì)值越大,相關(guān)性越大,反之同理
正相關(guān):隨著變量的增大,而增大,反之同理;負(fù)相關(guān):隨著變量的增大,而減小,反之同理
merchant_pop_dis_rate.corr()
# 持券消費(fèi)人數(shù),與距離和折扣率都呈現(xiàn)出負(fù)相關(guān),屬于生活中的正?,F(xiàn)象
# 用熱力圖展示相關(guān)系數(shù)(data:相關(guān)系數(shù),annot:顯示相關(guān)系數(shù),cmap:顏色范圍,vmax:最大值,vmin:最小值)
sns.heatmap(data=merchant_pop_dis_rate.corr(),annot=True, cmap='Accent', vmax=1, vmin=-1)

由圖可知:
1.到點(diǎn)消費(fèi)人數(shù)的多少與顧客到店鋪的距離之間呈現(xiàn)負(fù)相關(guān),相關(guān)系數(shù)0.31,在0.3~0.5之間,為低度相關(guān)
2.到店消費(fèi)人數(shù)的多少與優(yōu)惠打折力度呈現(xiàn)負(fù)相關(guān),相關(guān)系數(shù)0.2,在0~0.3之間,為相關(guān)程度極弱
綜上所述,這些店家之所以火爆,應(yīng)該是物美價(jià)廉導(dǎo)致,與距離和優(yōu)惠力度相關(guān)性不大
4.1 分析每天中優(yōu)惠券的總體發(fā)放量與使用量情況
業(yè)務(wù)分析:日期(優(yōu)惠券的發(fā)放日期Date_received,使用日期date)用作圖表的x軸
需要統(tǒng)計(jì)每天優(yōu)惠券發(fā)放數(shù)量和使用數(shù)量
"""
offline['Date'].notnull().sum()? ? # 77.7萬消費(fèi)數(shù)據(jù)
offline['Date_received'].notnull().sum()? ? # 已經(jīng)發(fā)送出105萬優(yōu)惠券
# 取出存在消費(fèi)日期的記錄,進(jìn)行升序,再去重
date_sort = offline[offline['Date'].notnull()]['Date'].sort_values().unique()
# 取出存在領(lǐng)券日期的記錄,進(jìn)行升序,再去重
date_receive_sort = offline[offline['Date_received'].notnull()]['Date_received'].sort_values().unique()
# 每天優(yōu)惠券的使用量(即持券消費(fèi)人群)
consume_num_everyday = coupon_consume[['User_id', 'Date_received']]
consume_num_everyday = consume_num_everyday.groupby('Date_received').count()
consume_num_everyday = consume_num_everyday.rename(columns={'User_id': 'count'})
# 每天發(fā)放的優(yōu)惠券數(shù)量(取出所有領(lǐng)券日期!=null的數(shù)據(jù),再進(jìn)行按天分組,計(jì)數(shù)就可以)
coupon_sendout_everyday = offline[offline['Date_received'].notnull()][['Date_received', 'User_id']]
coupon_sendout_everyday = coupon_sendout_everyday.groupby('Date_received').count()
coupon_sendout_everyday = coupon_sendout_everyday.rename(columns={'User_id': 'count'})
# 繪制每天發(fā)券量和每天用券量
plt.figure(figsize=(18, 6), dpi=400)
plt.bar(x=date_receive_sort, height=coupon_sendout_everyday['count'], label='每天發(fā)券量')
plt.bar(x=date_receive_sort, height=consume_num_everyday['count'], label='每天用券量')
plt.yscale('log')? ? # 對(duì)y軸進(jìn)行對(duì)數(shù)縮放
plt.legend()

# 16年2月為例,用券量級(jí)別在1000,發(fā)券量在10萬左右,在100倍左右,優(yōu)惠券的使用率還是非常低的
# 計(jì)算每天的優(yōu)惠券與發(fā)券量占比
plt.figure(figsize=(18,6), dpi=400)
plt.bar(x=date_receive_sort, height=consume_num_everyday['count']/coupon_sendout_everyday['count'], label='百分比')
plt.legend()

# 由圖可知,優(yōu)惠券使用率最高在16年3月底,達(dá)到了30%,使用率最低在16年1月底,最低為3%左右。整體來看,優(yōu)惠券使用率波動(dòng)較大