赞
踩
摘要: 本文以年平均购买课程数为核心指标,清洗数据后使用Tableau对学员人口学特征及学习行为特征进行分析仪表盘地址。使用多元线性回归方程分析用户购买驱动力,结果发现高粘性用户_yes、最后上课日期数值越大,课平均作业提交数、年平均优秀学员数对结果影响显著,从课程开发阶段,课程进行阶段,课程结束后三个阶段结合用户生命周期进行分析,提出对应运营策略。使用Kmeans聚类得到5类用户,根据用户学习行为特点,总结用户痛点,在AARRR模型基础上从用户获取、老客召回、激活、留存、促活、变现、传播等角度分析,给出相应的运营策略建议。
背景:
某互联网教育公司营销部门希望对近几年的学员数据进行分析挖掘,以期更好的了解学员信息,并针对学员的特点针对性的采取措施,最终提高课程的购买量。
本文将对核心思路如下:
将源数据《online_student_data.sql》导入MySQL中,数据来源于企业真实数据,为了脱敏,将隐去用户ID。用SQL查询语句对信息做初步整理。整理过程如下:结合《online_area_data.sql》和《online_province_data.sql》将地理信息匹配相应省份,并将地理信息整理为重点城市或区域列,整理规则为若省份或区域属于“北上广深杭”或“港澳台”,则在特征列中显示省份/地区名,若非则显示对应的区域信息。
对应的SQL语句如下
select distinct *
from(
select a.*,
case when a.`城市` not in ('北京市','上海市','深圳市','广州市','杭州市','香港','澳门','台湾') then c.区域 else a.`城市` end as 重点城市或区域
from online_student_data as a
LEFT JOIN online_province_data as b on a.城市= b.地级市
LEFT JOIN online_area_data as c on c.省份=b.省) as a
where a.城市 is not null and a.城市=a.`重点城市或区域`;
将整理后的数据保存为data_keypoint_cities.csv,使用pandas将数据导入jupyter
notebook中,使用data.info()查看数据基本信息,经过初步整理的数据见下表,总共11204条数据,15个字段。
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
%matplotlib inline
data = pd.read_csv('./data_keypoint_cities.csv',encoding='gbk')
data.head()
data.info()`
为了快速理解数据,使用pandas_profilling查看每列数据分布特征。
# 数据概览
import pandas_profiling
profile=pandas_profiling.ProfileReport(data,title='Pandas Profiling Report', html={'style': 'full_width':True}}, minimal=True)
profile
根据上面的结果,我们对缺失值和每一列的数值分布已经有了初步的了解。日期字段的数据后续需要进行转换为时间格式,作业平均分、提交必做作业书和重点城市和区域具有缺失值,性别具有“未知”类,出生年有大量0值,也需要后续处理。
#数据清理-查看缺失值
# data.info()
print(data.isnull().sum())
数值变量处理:将作业平均分的缺失值填充为0,将提交必做作业总数的空缺值填充为0,剔除城市和重点城市或区域不匹配的行(行数较少,认为删除不影响结果)。
#数据清理-处理缺失值
data['作业平均分']=data['作业平均分'].fillna(0)
data['提交必做作业总数']=data['提交必做作业总数'].fillna(0)
na_keys=data[data['重点城市或区域'].isnull()].index.tolist()
data = data.drop(na_keys,axis=0)#剔除城市和重点城市或区域不匹配的
分类变量处理:使用透视表查看性别和出生年的类别分布,对出生年在0、2020年、2088年的行,用中位数填充。对性别为“未知”的数值随机选取性别进行填充。结果如下。
# 分类变量查看 # print(pd.pivot_table(data,index=[u'性别'])) # pd.pivot_table(data,index=[u'出生年']) #查看'出生年'数值分布 media_year = int(data['出生年'].median()) #查看表中'出生年'的数据类型为int型,计算中位数 data['出生年'].replace([0,2020,2088],media_year,inplace = True) data['出生年'].replace([19920928,2147483647],media_year,inplace = True) #替换 # 对性别列进行替换,随机选取性别 list_re_sex = [] list_sex = data['性别'].values.tolist() for i in list_sex: if i =='未知': list_re_sex.append(pd.DataFrame(['男','女']).sample(n =1,replace =True,random_state=None).values[0][0]) else: list_re_sex.append(i) data['性别'] = list_re_sex print(pd.pivot_table(data,index=[u'性别']))
在查看数据的缺失值之后,我们还需要根据特征之间存在的逻辑关系进行检查,查看是否存在异常值。依照逻辑,获得优秀学员次数 < 购买付费课数量,优秀比例应 <=1。
data['优秀比例'] = data['获得优秀学员的次数']/data['购买付费课数量']
abnomal_excellent_ratio_index = data[data['优秀比例']>1].index.tolist()
data = data.drop(abnomal_excellent_ratio_index,axis=0)#剔除不合逻辑的数据
# 因为发生除法,需要对数据再次进行检查,是否存在缺失值
data.isna().sum() # 发现有三个nan值,剔除
na_list = data[data.isna()['优秀比例']==True].index.tolist()
data.drop(na_list,axis=0,inplace = True)
此外,依据逻辑,不应存在付费课程数为0,但提交过必做作业的学员。此时,付费课程数使用中位数填充。
median_num = data['购买付费课数量'].median()
data.loc[(data['购买付费课数量']==0)&(data['提交必做作业总数']>0),'购买付费课数量']=median_num
由于很多分析的维度都是建立在时间上的,而我们通过图1-2中的数据类型结果,发现数据中的时间是字符串类型的,所以需要处理时间的类型,将其修改成datetime类型。
data['首次上课日期']=pd.to_datetime(data['首次上课日期'])
data['最后上课日期']=pd.to_datetime(data['最后上课日期'])
data['注册日期']=pd.to_datetime(data['注册日期'])
为了更好地分析学员的学习行为,我们认为平均值能更好地反映出学生的上课质量。故将提交必做作业总数转化为课平均作业提交数,即平均作业提交数=提交必做作业总数/购买付费课数量;将获得优秀学员的次数转化为年平均优秀学员数,即年平均优秀学员数=获得优秀学员的次数/至今的年数。
为分析学员首次上课以来的学习积极性,将购买付费课数量转化为年平均购买付费课程数,即年平均购买付费课程数=购买付费课数量/至今的年数。
为了更明晰查看学员行业分布,将是否来自互联网行业作为一个新的特征,添加到源数据中。结果如下。
import datetime
from datetime import datetime
data['截止日期'] ='2020-03-20'
datediff = pd.to_datetime(data['截止日期'])-data['首次上课日期']
data['年平均购买付费课程数'] = 365*(data['购买付费课数量']/datediff.dt.days)
data['平均作业提交数'] = data['提交必做作业总数']/data['购买付费课数量']
data['年平均优秀学员数']= 365*(data['获得优秀学员的次数']/datediff.dt.days)
data.drop(['截止日期'],axis = 1,inplace = True)
data['是否为互联网行业'] = np.where(data['行业']=='互联网', 'yes','no')
将处理好的数据保存在《user_data.csv》文件中。
data.to_csv('./user_data.csv',encoding = 'gbk')
为了更好地了解到当前学员的基本信息,使用Tableau制作仪表盘探索学员数据分布。包括地域、行业、性别、年龄、工作年限等人口学特征,以及学员购买课程的行为特征。仪表盘如下。
对于整个仪表盘,可调节的参数有:
按城市统计学员数目,如下图的条形图所示。学员数最多的三个城市为北京市、上海市、深圳市。
根据学员所在行业和性别为分类依据,统计学员人数,可以看到互联网行业学员最多,其次为教育、IT、未毕业、金融,其中互联网行业的学员数占比超过50%。女学员的数量普遍比男学员数量多。说明不论是否已参加工作,女性进修的积极性普遍比男性高。
根据出生年统计学员的年龄分布,出生年范围在1980-2000年,对应年龄为20-40岁。主力学员为1990-1996年的学员,对应年龄为24-30岁,处于即将进入职场/初入职场阶段。表明年轻人在事业上升期有很强的动力来购买网课,提高自身技能。
根据工作年限划分学员,学员的工作年限范围在0-3年,其中0年工作经验的学员人数最多,占比为34.01%;2年工作经验的学员人数次多,占比为33.09%;3年工作经验的学员人数最少,占比为10%。
学员购买付费课数量范围在1-53之间,为了观察学员购买付费课数量的分布,绘制如下帕累托图。
由上图可知,购买总课程量80%的学员,购买课程数量为1-11,累计购买课程数量为30,393。按总购买量排序,前三依次为购买课程数量为1(人数为4809人,总购买量为4809,购买量占比12.74%,)、2(人数为1966人,总购买量为3932,累计占比23.16%),3(人数为1086人,总购买量为3258,累计占比31.8%)。
由数据可以看出,学员购买付费课程数不服从二八定律。即,购买付费课程数相对分散。这说明为了提升付费课程销售总量,不仅需要大量拉新,对老客户的维护,提高客户复购率也是非常重要的。
为了更好地帮助营销团队提升课程销售量,选择“年平均购买付费课程数”为主要指标,探索用户人口学特征和用户学习行为特征与“年平均购买付费课程数”的关联。选择“年购买付费课程数”表征学员学习积极性,“年平均优秀学员数”表征学员的学习质量。使用气泡图表征学员学习积极性和学习质量的地域分布,气泡大小由人数决定。
为了避免极端值的影响,选取中位数表征年购买付费课程数和年平均优秀学员数。年平均付费课程数的中位数为2.59,年平均优秀学员数的中位数为0.28。这样可以把学员分为四类,高质高量、低质低量、高质低量、低质高量。高质高量学员所在区域的典型是台湾、深圳;低质低量学员所在区域的典型是澳门和东北;高质低量学员所在区域的典型是香港;低质高量学员所在区域的典型是北京市。
此外,还可以通过对性别、所在行业、工作年限等参数的筛选,进一步观察数据分布。
附,仪表盘地址
为了提升公司的整体销量,除了大量拉新以外,我们还需要提高每个用户每年购买付费课程的数量,因此,我们选择“年平均购买付费课程数”作为核心指标,探索影响它的关键因素。
构建多元线性回归模型,是一个寻找核心指标驱动因素的通用方法。我们以“年平均购买付费课程数”为因变量,其他学员人口学特征以及学习行为特征作为自变量,通过构建多元线性回归模型,找到影响y值-“年平均付费课程数”的关键驱动因素。后期可以改变营销策略等方式影响特定的特征变量,从而使y值-“年平均付费课程数”显著增加,提升付费课程的总销售量。
从《user_data.csv》读取数据,并将日期转换为数值型变量
lm_data = pd.read_csv('./user_data.csv', encoding='gbk')
lm_data.head(2)
import datetime as dt
from datetime import datetime
lm_data['首次上课日期']=pd.to_datetime(lm_data['首次上课日期']).map(dt.datetime.toordinal)
lm_data['最后上课日期']=pd.to_datetime(lm_data['最后上课日期']).map(dt.datetime.toordinal)
lm_data['注册日期']=pd.to_datetime(lm_data['注册日期']).map(dt.datetime.toordinal)
切分自变量和因变量,75%的数据作为训练集,25%的数据作为测试集。
# 切分因变量和自变量
X = lm_data.drop(['年平均购买付费课程数'],axis=1 )
y = lm_data.loc[:,['年平均购买付费课程数']]
# 25%测试集,75%训练集
from sklearn.model_selection import cross_val_score,train_test_split
#构建训练集和测试集
train_X,test_X,train_y,test_y= train_test_split(X,y,test_size=0.25,random_state=4)
使用线性回归,需要满足假设:变量服从正态分布,故使用概率密度图观察train_y值,从图中可知,train_y值呈现明显右偏(偏度为0.95)
# train_y值,明显右偏
sns.pairplot(train_y,diag_kind='kde',kind='reg')
# 计算偏度
train_y.skew()
对因变量取对数,查看ln_train_y的分布,接近正态分布
# train_ln_y值接近正态分布
train_y['年平均购买付费课程数'] = np.log(train_y['年平均购买付费课程数'])
train_ln_y = train_y.loc[:,['年平均购买付费课程数']]
sns.pairplot(train_ln_y,diag_kind='kde',kind='reg')
对测试集进行相同取对数转换
test_y['年平均购买付费课程数'] = np.log(test_y['年平均购买付费课程数'])
# ln_y值接近正态分布
test_ln_y = test_y.loc[:,['年平均购买付费课程数']]
sns.pairplot(test_ln_y,diag_kind='kde',kind='reg')
使用箱型图查看数据的异常值分布,发现异常数据共48个,使用临界值替换异常值,其中右侧临界值为16.3,即年平均购买付费课程数大于16.3的的数值均替换为16.3。
特征变量的选取
特征变量的选取对回归效果有决定性的影响,如果特征变量与因变量的相关性不强,或者变量之前存在强相关性,则会严重影响回归结果。如果回归效果不好,则可以根据业务需要,重新选取/增加指标。
为了更好地关注一些不做分析就无法识别的特征,将一些批凭直觉就可以判断的,和“年平均付费课程数”指标相关性很大的特征:如“提交必做作业数量”、“获得优秀学员次数”替换为均值类指标,“平均作业提交数”、 “年平均优秀学员数”。此外为简化回归,删除“‘Unnamed: 0’,‘主键’,‘获得优秀学员的次数’,‘提交必做作业总数’,‘城市’,‘行业’,‘购买付费课数量’,‘性别’,‘重点城市或区域’,'是否为互联网行业’分类变量。
train_X = train_X.drop(['Unnamed: 0','主键','获得优秀学员的次数','提交必做作业总数','城市','行业','购买付费课数量','性别','重点城市或区域','是否为互联网行业'],axis =
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。