o2o数据分析
分析目标
1.分析店面客流量是否火爆的影响因素
2.分析顾客的消费情况
3.分析投放优惠劵的使用情况¶
1.导入相关包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns #绘图模块 基于matplotlib的可视化python包,不能完全替代matplotlib只是一个升级
plt.rcParams['font.sans-serif']=['SimHei'] #显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示正负号
%matplotlib inline
#pip install seaborn
2.加载数据
offline=pd.read_csv('D:\zhangxinfile\python数据实战练习(jupyter lab)\数据分析实战项目资料\O2O\资料\ccf_offline_stage1_train.csv',parse_dates=['Date_received','Date'])
offline.info()#175万的数据,需要转成日期,parse_dates():将指定的列加载成日期的格式,列里面的数据必须为日期类型的
offline.head(10)#NaT代表时间日期格式的空值
3.数据的规整
#判断每一列当中有多少个空值
offline.isnull().sum()#相当于对1,0进行计数
#优惠券id以及折扣率,领劵日期,三者可能存在同时等于null的情况
3.1把Discount_rate中的满减政策转化为折扣率
offline['Discount_rate']=offline['Discount_rate'].fillna('null')
offline.head()
def discount_rate_opt(s):#s代表每一个元素
if ':' in s:
split=s.split(':')
discount_rate = (int(split[0])-int(split[1]))/int(split[0])
return round(discount_rate,2)#折扣率保留两位小数
elif s=='null':
return np.NaN
else:
return float(s)
offline['Discount_rate'] = offline['Discount_rate'].map(discount_rate_opt)
offline.head()
3.2Coupon_id字段:null代表无优惠券,此时Discount_rate 和Date_received字段无意义
检查coupon——id与Discount_rate和Date_received判断空值和非空值是否为一一对应。
#np.all()#判断一个可迭代的数据中心是否都为true,如果是返回TRUE,否则返回False
np.all([True,True,True])
nan1=offline['Coupon_id'].isnull() #判断优惠券是否为空
nan2=offline['Date_received'].isnull()#判断领劵日期是否为空
np.all(nan1==nan2) #如果结果为true 说明之前的猜测:coupon——id和Date_received空值与非空值是一一对应的关系
nan3=offline['Discount_rate'].isnull()#判断领劵日期是否为空
np.all(nan2==nan3)#如果结果为true 说明之前的猜测:coupon——id和Date_received空值与非空值是一一对应的关系
3.3 对不同类别的消费进行分析
如果Date=null&coupon_id!=null,有券未消费----(cpon_no_consume)
如果Date=null&coupon_id=null,无券未消费—(no_cpon_no_consume)
如果Date!=null&Coupon_id=null,无券消费(no_cpon_consume)
如果Date!=null&Coupon_id!=null,有券消费(cpon_consume)
cpon_no_consume=offline[(offline['Date'].isnull() & offline['Coupon_id'].notnull())]
no_cpon_no_consume=offline[(offline['Date'].isnull() & offline['Coupon_id'].isnull())]
no_cpon_consume=offline[(offline['Date'].notnull() & offline['Coupon_id'].isnull())]
cpon_consume=offline[(offline['Date'].notnull() & offline['Coupon_id'].notnull())]
print('有券未消费:{}'.format(len(cpon_no_consume)))
print('无券未消费:{}'.format(len(no_cpon_no_consume))) #无意义,不进行后续分析
print('无券消费:{}'.format(len(no_cpon_consume)))
print('有券消费:{}'.format(len(cpon_consume)))
#用券消费的用户7万人相比较其他用户来说,占比较少
4.数据分析及数据可视化
将原始数据转化为Series中的可识别数据
#绘制饼图占比
consume_status_dict ={'cpon_no_consume':len(cpon_no_consume),'no_cpon_consume':len(no_cpon_consume),'cpon_consume':len(cpon_consume)}
consume_status=pd.Series(consume_status_dict)
consume_status
#消费方式构成的饼图 (详细解析请参考:https://blog.csdn.net/tefuirnever/article/details/93724227)
#消费方式构成的饼图 (详细解析请参考:https://blog.csdn.net/tefuirnever/article/details/93724227)
fig,ax=plt.subplots(1,1,figsize=(8,10))
consume_status.plot.pie(ax=ax,
autopct='%1.1f%%', #占比情况
shadow=True,
explode=[0.02,0.05,0.02],
textprops={'fontsize':15,'color':'blue'},
wedgeprops={'linewidth':1,'edgecolor':'black'},
labels=['有券未消费({})'.format(len(cpon_no_consume)),
'无券消费({})'.format(len(no_cpon_consume)),
'有券消费({})'.format(len(cpon_consume))]
)
ax.set_ylabel('')#去除ylabel
ax.set_title('消费占比情况')
plt.legend(labels=['有券未消费','无券消费','有券消费'])
#有券未消费占比55.7%最大,说明大多数人拿完券之后尚未使用
#无券用户占比40%,说明很多人没有使用优惠券,可能优惠前的吸引力必达,客户没在意,可能新用户比较多
#用券消费的用户占比较小:4.3%,说明优惠券使用率不高,可以适当加大优惠券的力度
另一种更为简单的生成饼图方式(详细过程参考:https://blog.csdn.net/captain811/article/details/79248912?utm_source=app&app_version=5.0.1&code=app_1562916241&uLinkId=usr1mkqgl919blen)
consume_status.plot.pie(
autopct='%1.1f%%', #占比情况
shadow=True,
explode=[0.02,0.05,0.02],
textprops={'fontsize':15,'color':'blue'},
wedgeprops={'linewidth':1,'edgecolor':'black'},
labels=['有券未消费({})'.format(len(cpon_no_consume)),
'无券消费({})'.format(len(no_cpon_consume)),
'有券消费({})'.format(len(cpon_consume))]
)
plt.title('消费占比情况')
plt.legend(loc=0)
4.1在有券消费人群中,分析距离和优惠折扣
#各商家对应的顾客到店的平均距离
Merchant_distance=cpon_consume.groupby(by='Merchant_id')['Distance'].mean()
Merchant_distance.sort_values(ascending=False)
Merchant_distance[Merchant_distance==0]
#有4076个商家有1431个商家的用券消费用户平均范围在500m以内
#各商家对应的顾客到店消费平均折扣力度
Merchant_discount_rate=cpon_consume.groupby('Merchant_id')['Discount_rate'].mean() #分组之后取了平均值
Merchant_discount_rate.sort_values(ascending=True)
Merchant_discount_rate.hist() #y轴的数字代表数量
Merchant_discount_rate.mean()
#由图可知,在哪个折扣的店铺数量最多
4.2持券到店消费人数最多的商家
#对商家进行分组,取出用户id,对用户id进行去重统计数量
popular_merchant=cpon_consume.groupby('Merchant_id')['User_id'].apply(lambda x:len(x.unique())).sort_values(ascending=False)
popular_merchant
pupular_merchant500=popular_merchant[popular_merchant>500]
pupular_merchant500.name = 'customer_count' #指定列明为消费者数量(持券消费者)
print(len(pupular_merchant500))
print(pupular_merchant500)
# 共有16家店铺,持券消费人数在500人以上
# 持券消费人数最多商家是5341,持券消费人数为2800(且此为去重后数据,原始数据可能比这个还要多)
# 排名最后的商家,持券消费人数为559人
# 这批商家对优惠券的使用方法得当,消费者喜欢用优惠券进行消费,可以适当借鉴这批商家的推广力度
4.3持券消费人数在500人以上的商家,连接顾客到店平均距离和平均折扣力度
merchant_pop_dis=pd.merge(left=pupular_merchant500,right=Merchant_distance,on='Merchant_id',how='inner')
merchant_pop_dis.sort_values('Distance',ascending=False)
merchant_pop_dis_rate=pd.merge(left=merchant_pop_dis,right=Merchant_discount_rate,on='Merchant_id',how='inner')
merchant_pop_dis_rate
4.4计算到店消费人数与平均距离和折扣力度的相关系数
#corr(correlation:相关系数),用来计算df数据中列与列的向关性(皮尔逊相关系数)取值为【-1,1】
1代表完全正向关,-1代表完全负相关
正相关,随着变量的增大而增大,反之同理
负相关,随着变量的增大而减小,反之同理
绝对值越大,相关性越大,反之成立
merchant_pop_dis_rate.corr()
#持券消费人数,与距离和折扣率都呈现出负相关,属于生活中的正常现象
#用热力图展示相关系数
sns.heatmap(data=merchant_pop_dis_rate.corr(),annot=True,cmap='Accent',vmax=1,vmin=-1,linewidths=10) #可以上网上自行查找
#data是相关系数,,linewidths=10是每个块的间距,annot显示相关系数的值,cmap颜色的范围,vmax去最大值,vmin为最小值
#由图可知:
1.到店消费人数的多少与顾客到店铺的距离之间呈现负相关, 相关系数为0.31,在0.3-0.5之间为低度相关。
2.到店消费人数的多少与优惠打折力度呈现负相关,相关系数为0.2,在0-0.3之间,相关程度极弱。
综上所述,这些店家之所以火爆,应该是物美价廉导致的,与我们的距离和优惠力度相关性不大
4.5 分析每天当中优惠券的总体发放量与使用量情况
#业务分析:日期(优惠券的发放日期Date_received,使用日期Date)用作图表的x轴
#需要统计每天优惠券发放数量和使用数量
offline['Date'].notnull().sum() #77.6万的消费记录
offline['Date_received'].notnull().sum() #已经发送出105万的优惠券
#取出存在消费日期的记录,进行升序,在去重
date_sort=offline[offline['Date'].notnull()]['Date'].sort_values().unique()
date_sort[:5]
#取出存在领券日期的记录,进行升序,在去重
date_receive_sort = offline[offline['Date_received'].notnull()]['Date_received'].sort_values().unique()
date_receive_sort[:5]
#每天优惠券的使用量(即持券消费人群)
consume_num_everday = cpon_consume[['User_id','Date_received']]
consume_num_everday = consume_num_everday.groupby('Date_received').count()
consume_num_everday = consume_num_everday.rename(columns={'User_id':'count'})
consume_num_everday
#每天发放的优惠券数量(领券日期!=null的数据,在进行按天分组,计数就可以)
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'})
coupon_sendout_everyday
# 绘制每天发券量和每天用券量
plt.figure(figsize=(18,6))
plt.bar(x=date_receive_sort,height=coupon_sendout_everyday['count'],label='每天发券量')
plt.bar(x=date_receive_sort,height=consume_num_everday['count'],label='每天用券量')
plt.yscale('log') #对y轴进行对数缩放
plt.legend()
#16年2月为例,用券量级别为1000,发券量在10万左右,两者相差100倍,优惠券使用率还是非常低的
#绘制每天发券量与用券量比例图
plt.figure(figsize=(18,6))
plt.bar(x=date_receive_sort,height=consume_num_everday['count']/coupon_sendout_everyday['count'],label='百分比')
plt.legend()
#由图可知,优惠券使用率最高在16年3月底,达到了30%
#使用率最低在16年一月底,最低为3%左右
#总体来看,使用率较低