互联网教育-用户分析案例(驱动力分析&学员画像)

互联网教育-用户数据驱动力分析及学员画像分层

摘要: 本文以年平均购买课程数为核心指标,清洗数据后使用Tableau对学员人口学特征及学习行为特征进行分析仪表盘地址。使用多元线性回归方程分析用户购买驱动力,结果发现高粘性用户_yes、最后上课日期数值越大,课平均作业提交数、年平均优秀学员数对结果影响显著,从课程开发阶段,课程进行阶段,课程结束后三个阶段结合用户生命周期进行分析,提出对应运营策略。使用Kmeans聚类得到5类用户,根据用户学习行为特点,总结用户痛点,在AARRR模型基础上从用户获取、老客召回、激活、留存、促活、变现、传播等角度分析,给出相应的运营策略建议。

用户数据分析

  • 互联网教育-用户数据驱动力分析及学员画像分层
    • 一、数据准备
      • 1. 获取数据
      • 2. 了解数据基本情况
    • 二、数据清洗
      • 1. 查看是否含有缺失值
      • 2. 查看是否含有异常值
      • 3. 数据整理
    • 三、学员人口学特征及行为特征可视化分析
      • 1. 学员基本信息
      • 2. 学员购买付费课数量的行为特征
    • 四、“年平均购买付费课程数”的驱动力分析
      • 1. 第一次多元线性回归
      • 2. 第一次多元线性回归模型检验及结果分析
      • 3. 第二次多元线性回归-扩展新的特征
        • (1)新增特征变量
        • (2)剔除与y值不相关的特征变量
        • (3)剔除存在多重共线性的特征变量
        • (4)使用特征选择RFECV确定最佳特征的数量
      • 4. 第二次多元线性回归
      • 5. 第二次线性回归模型检验及结果分析
    • 五、学员画像及用户分层运营策略
      • 1. Kmeans模型实现用户画像分层
      • 2. 提炼用户画像并提出对应运营策略

背景

某互联网教育公司营销部门希望对近几年的学员数据进行分析挖掘,以期更好的了解学员信息,并针对学员的特点针对性的采取措施,最终提高课程的购买量。

本文将对核心思路如下:

  • 确定核心指标“年平均购买课程数”
  • 搭建数据仪表盘,学员信息
  • 核心指标驱动力分析:搭建回归方程,探索影响核心指标的驱动因素
  • 学员画像分析:根据学员特征,对学员进行聚类,将用户分层,以便精细化运营

一、数据准备

1. 获取数据

将源数据《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()`

互联网教育-用户分析案例(驱动力分析&学员画像)_第1张图片

2. 了解数据基本情况

为了快速理解数据,使用pandas_profilling查看每列数据分布特征。

 # 数据概览
import pandas_profiling
profile=pandas_profiling.ProfileReport(data,title='Pandas Profiling Report', html={'style': 'full_width':True}}, minimal=True)
profile

互联网教育-用户分析案例(驱动力分析&学员画像)_第2张图片
互联网教育-用户分析案例(驱动力分析&学员画像)_第3张图片
互联网教育-用户分析案例(驱动力分析&学员画像)_第4张图片
互联网教育-用户分析案例(驱动力分析&学员画像)_第5张图片
互联网教育-用户分析案例(驱动力分析&学员画像)_第6张图片
互联网教育-用户分析案例(驱动力分析&学员画像)_第7张图片
互联网教育-用户分析案例(驱动力分析&学员画像)_第8张图片
互联网教育-用户分析案例(驱动力分析&学员画像)_第9张图片
互联网教育-用户分析案例(驱动力分析&学员画像)_第10张图片
根据上面的结果,我们对缺失值和每一列的数值分布已经有了初步的了解。日期字段的数据后续需要进行转换为时间格式,作业平均分、提交必做作业书和重点城市和区域具有缺失值,性别具有“未知”类,出生年有大量0值,也需要后续处理。

二、数据清洗

1. 查看是否含有缺失值

#数据清理-查看缺失值
# data.info()
print(data.isnull().sum())

互联网教育-用户分析案例(驱动力分析&学员画像)_第11张图片
数值变量处理:将作业平均分的缺失值填充为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'性别']))

互联网教育-用户分析案例(驱动力分析&学员画像)_第12张图片

2. 查看是否含有异常值

在查看数据的缺失值之后,我们还需要根据特征之间存在的逻辑关系进行检查,查看是否存在异常值。依照逻辑,获得优秀学员次数 < 购买付费课数量,优秀比例应 <=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

3. 数据整理

由于很多分析的维度都是建立在时间上的,而我们通过图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')

互联网教育-用户分析案例(驱动力分析&学员画像)_第13张图片
将处理好的数据保存在《user_data.csv》文件中。

data.to_csv('./user_data.csv',encoding = 'gbk')

三、学员人口学特征及行为特征可视化分析

为了更好地了解到当前学员的基本信息,使用Tableau制作仪表盘探索学员数据分布。包括地域、行业、性别、年龄、工作年限等人口学特征,以及学员购买课程的行为特征。仪表盘如下。
互联网教育-用户分析案例(驱动力分析&学员画像)_第14张图片
对于整个仪表盘,可调节的参数有:

  • 重点城市和区域
  • 行业
  • 性别
  • 是否为互联网行业
  • 工作年限

1. 学员基本信息

按城市统计学员数目,如下图的条形图所示。学员数最多的三个城市为北京市、上海市、深圳市。
互联网教育-用户分析案例(驱动力分析&学员画像)_第15张图片
根据学员所在行业和性别为分类依据,统计学员人数,可以看到互联网行业学员最多,其次为教育、IT、未毕业、金融,其中互联网行业的学员数占比超过50%。女学员的数量普遍比男学员数量多。说明不论是否已参加工作,女性进修的积极性普遍比男性高。
互联网教育-用户分析案例(驱动力分析&学员画像)_第16张图片
根据出生年统计学员的年龄分布,出生年范围在1980-2000年,对应年龄为20-40岁。主力学员为1990-1996年的学员,对应年龄为24-30岁,处于即将进入职场/初入职场阶段。表明年轻人在事业上升期有很强的动力来购买网课,提高自身技能。
互联网教育-用户分析案例(驱动力分析&学员画像)_第17张图片
根据工作年限划分学员,学员的工作年限范围在0-3年,其中0年工作经验的学员人数最多,占比为34.01%;2年工作经验的学员人数次多,占比为33.09%;3年工作经验的学员人数最少,占比为10%。
互联网教育-用户分析案例(驱动力分析&学员画像)_第18张图片

2. 学员购买付费课数量的行为特征

学员购买付费课数量范围在1-53之间,为了观察学员购买付费课数量的分布,绘制如下帕累托图。
互联网教育-用户分析案例(驱动力分析&学员画像)_第19张图片
由上图可知,购买总课程量80%的学员,购买课程数量为1-11,累计购买课程数量为30,393。按总购买量排序,前三依次为购买课程数量为1(人数为4809人,总购买量为4809,购买量占比12.74%,)、2(人数为1966人,总购买量为3932,累计占比23.16%),3(人数为1086人,总购买量为3258,累计占比31.8%)。
由数据可以看出,学员购买付费课程数不服从二八定律。即,购买付费课程数相对分散。这说明为了提升付费课程销售总量,不仅需要大量拉新,对老客户的维护,提高客户复购率也是非常重要的。
为了更好地帮助营销团队提升课程销售量,选择“年平均购买付费课程数”为主要指标,探索用户人口学特征和用户学习行为特征与“年平均购买付费课程数”的关联。选择“年购买付费课程数”表征学员学习积极性,“年平均优秀学员数”表征学员的学习质量。使用气泡图表征学员学习积极性和学习质量的地域分布,气泡大小由人数决定。
互联网教育-用户分析案例(驱动力分析&学员画像)_第20张图片
为了避免极端值的影响,选取中位数表征年购买付费课程数和年平均优秀学员数。年平均付费课程数的中位数为2.59,年平均优秀学员数的中位数为0.28。这样可以把学员分为四类,高质高量、低质低量、高质低量、低质高量。高质高量学员所在区域的典型是台湾、深圳;低质低量学员所在区域的典型是澳门和东北;高质低量学员所在区域的典型是香港;低质高量学员所在区域的典型是北京市。
此外,还可以通过对性别、所在行业、工作年限等参数的筛选,进一步观察数据分布。
附,仪表盘地址

四、“年平均购买付费课程数”的驱动力分析

为了提升公司的整体销量,除了大量拉新以外,我们还需要提高每个用户每年购买付费课程的数量,因此,我们选择“年平均购买付费课程数”作为核心指标,探索影响它的关键因素。
构建多元线性回归模型,是一个寻找核心指标驱动因素的通用方法。我们以“年平均购买付费课程数”为因变量,其他学员人口学特征以及学习行为特征作为自变量,通过构建多元线性回归模型,找到影响y值-“年平均付费课程数”的关键驱动因素。后期可以改变营销策略等方式影响特定的特征变量,从而使y值-“年平均付费课程数”显著增加,提升付费课程的总销售量。

1. 第一次多元线性回归

从《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()

互联网教育-用户分析案例(驱动力分析&学员画像)_第21张图片
对因变量取对数,查看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')

互联网教育-用户分析案例(驱动力分析&学员画像)_第22张图片
对测试集进行相同取对数转换

test_y['年平均购买付费课程数'] = np.log(test_y['年平均购买付费课程数'])
# ln_y值接近正态分布
test_ln_y =  test_y.loc[:,['年平均购买付费课程数']]
sns.pairplot(test_ln_y,diag_kind='kde',kind='reg')

互联网教育-用户分析案例(驱动力分析&学员画像)_第23张图片
使用箱型图查看数据的异常值分布,发现异常数据共48个,使用临界值替换异常值,其中右侧临界值为16.3,即年平均购买付费课程数大于16.3的的数值均替换为16.3。
互联网教育-用户分析案例(驱动力分析&学员画像)_第24张图片

特征变量的选取
特征变量的选取对回归效果有决定性的影响,如果特征变量与因变量的相关性不强,或者变量之前存在强相关性,则会严重影响回归结果。如果回归效果不好,则可以根据业务需要,重新选取/增加指标。
为了更好地关注一些不做分析就无法识别的特征,将一些批凭直觉就可以判断的,和“年平均付费课程数”指标相关性很大的特征:如“提交必做作业数量”、“获得优秀学员次数”替换为均值类指标,“平均作业提交数”、 “年平均优秀学员数”。此外为简化回归,删除“‘Unnamed: 0’,‘主键’,‘获得优秀学员的次数’,‘提交必做作业总数’,‘城市’,‘行业’,‘购买付费课数量’,‘性别’,‘重点城市或区域’,'是否为互联网行业’分类变量。

train_X = train_X.drop(['Unnamed: 0','主键','获得优秀学员的次数','提交必做作业总数','城市','行业','购买付费课数量','性别','重点城市或区域','是否为互联网行业'],axis = 1)

test_X = test_X.drop(['Unnamed: 0','主键','获得优秀学员的次数','提交必做作业总数','城市','行业','购买付费课数量','性别','重点城市或区域','是否为互联网行业'],axis = 1)

进行线性回归之前,需要检查多重共线性,并相应删除相关特征项。
在去除多重共线性之前,计算各特征之间的相关系数矩阵,并用热力图展现各特征之间的相关性。图中可以看出,特征之间有强相关的变量,如“优秀比例”和“年平均优秀学员数”之间相关系数为0.8,“是否为互联网行业_yes”和“是否为互联网行业_no”之间相关系数为1,“性别_女”和“性别_男”之间相关系数为1,这些特征同时存在会严重影响线性回归的结果。

plt.rcParams['axes.unicode_minus'] = False  #负号显示

#热力图展示相关系数
figure = plt.subplots(figsize = (12,8))
sns.heatmap(data=train_X.corr(),annot=True,linewidths=0.5, fmt='.1f',cmap=plt.cm.Reds)

互联网教育-用户分析案例(驱动力分析&学员画像)_第25张图片
使用VIF检查特征多重共线性。计算当前所有特征的VIF值,如图所示

import statsmodels
from statsmodels.stats.outliers_influence import variance_inflation_factor
# 计算当前所有特征的VIF值

vif = pd.DataFrame()
vif["Features"] = train_X.columns
vif["VIF_Factor"] = [variance_inflation_factor(train_X.values, i) for i in range(train_X.shape[1])]
vif["VIF_Factor"] = np.round(vif["VIF_Factor"].astype(np.float64),2)
vif

互联网教育-用户分析案例(驱动力分析&学员画像)_第26张图片
根据上图,去掉去掉注册日期,首次上课日期,出生年,再次计算各变量的VIF值。由图可看出,没有大于10的特征项。

vif.drop([1,3,5],axis=0,inplace=True)

row_num = vif.shape[0]
sub_X2 =train_X[pd.DataFrame(vif['Features'].values.tolist()).iloc[0:row_num].values.reshape(row_num,).tolist()] 

vif2 = pd.DataFrame()
vif2["Features"] = sub_X2.columns
vif2["VIF_Factor"] = [variance_inflation_factor(sub_X2.values, i) for i in range(sub_X2.shape[1])]
vif2["VIF_Factor"] = np.round(vif2["VIF_Factor"].astype(np.float64),2)

互联网教育-用户分析案例(驱动力分析&学员画像)_第27张图片
构建线性回归模型,并得到各特征的回归系数,即权重。

from sklearn.linear_model import LinearRegression
lr = LinearRegression()

# 基于训练集对测试集进行预测
lr.fit(sub_X2,train_ln_y)
# 输出线性回归模型的系数
coef_df = pd.DataFrame(lr.coef_[0], sub_X2.columns, columns=['Coefficients'])
# 增加截距项
coef_df = coef_df.append(pd.DataFrame(lr.intercept_[0], columns=['Coefficients'],index=['(截距)']))
coef_df.sort_values(by= ['Coefficients'],ascending=True)
coef_df = coef_df.astype(np.float64)
coef_df

互联网教育-用户分析案例(驱动力分析&学员画像)_第28张图片
使用训练好的多元线性回归模型预测测试集,预测结果显示, R 2 R^2 R2为0.46,调整 R 2 R^2 R2为0.46。
将预测值与实际值可视化,绘制两者的折线图,如下所示。直观上看,预测值与真实值有较大偏差。

# 使用测试集预测
sub_test_X = test_X[pd.DataFrame(vif['Features'].values.tolist()).iloc[0:row_num].values.reshape(row_num,).tolist()] 
y_hat = lr.predict(sub_test_X)

# 绘制y的预测值与实际值对比图
fig = plt.figure(figsize=(10,5))
plt.plot(range(len(y_hat)),y_hat,color='red',label='预测值',alpha = 0.3)
plt.plot(range(len(test_ln_y)),test_ln_y,color='black',label='真实值',alpha = 0.3)
plt.title('真实值与预测值',fontsize = 20)
plt.legend(fontsize= 10)
plt.ylim(-1,4)
plt.show()

# 模型检验
from sklearn.metrics import r2_score
r2 = r2_score(test_ln_y, y_hat)
print('R2值为:{}'.format(round(r2, 2)))

# 调整r2
n = sub_test_X.shape[0] # 行数
p = sub_test_X.shape[1] # 列数
adj_r2 = 1 - (1-r2)*(n-1)/(n-p-1)
print('调整R2值为:{}'.format(round(adj_r2, 2)))

互联网教育-用户分析案例(驱动力分析&学员画像)_第29张图片
标准化后进行回归
为了消除特征值大小对回归系数的影响,真实反映各个特征对自变量的贡献,需要将数据进行标准化处理。如下所示。

# 将数据标准化
from sklearn.preprocessing import StandardScaler
s = StandardScaler()
X_standard = s.fit_transform(sub_X2)
train_X_standard = pd.DataFrame(data=X_standard, columns=list(sub_X2.columns)) 

# 创建线性回归模型实例
from sklearn.linear_model import LinearRegression
lr2 = LinearRegression()
# 拟合数据
lr2.fit(train_X_standard, train_ln_y)
# 输出线性回归模型的系数
coef_df2 = pd.DataFrame(lr2.coef_[0], train_X_standard.columns, columns=['Coefficients'])
# 增加截距项,并对系数大小进行排序
coef_df2 = coef_df2.append(pd.DataFrame(lr2.intercept_[0], columns=['Coefficients'],index=['(截距)'])).sort_values(by= ['Coefficients'],ascending=True)
coef_df2

互联网教育-用户分析案例(驱动力分析&学员画像)_第30张图片

2. 第一次多元线性回归模型检验及结果分析

为了检验模型的准确性,将训练好的模型,对测试集先后进行进行标准化,预测。

# 将测试集数据标准化
from sklearn.preprocessing import StandardScaler
test_X_standard = s.transform(sub_test_X)
test_X_standard = pd.DataFrame(data=test_X_standard, columns=list(sub_test_X.columns))
# 预测
y_hat2 = lr2.predict(test_X_standard)

# 绘制y的预测值与实际值对比图
fig = plt.figure(figsize=(10,5))
plt.plot(range(len(y_hat2)),y_hat2,color='red',label='预测值',alpha = 0.3)
plt.plot(range(len(test_ln_y)),test_ln_y,color='black',label='真实值',alpha = 0.3)
plt.title('标准化后-真实值与预测值',fontsize = 20)
plt.legend(fontsize= 10)
plt.ylim(-1,5)
plt.show()

互联网教育-用户分析案例(驱动力分析&学员画像)_第31张图片
通过计算 R 2 R^2 R2的大小,来判断模型的拟合优度(标准化不影响)。结果显示, R 2 R^2 R2为0.46,调整 R 2 R^2 R2为0.46。 R 2 R^2 R2太小,模型存在欠拟合的问题,需要进行改进。

# 模型检验
from sklearn.metrics import r2_score
r2 = r2_score(test_ln_y, y_hat2)
print('R2值为:{}'.format(round(r2, 2)))

# 调整r2
n = sub_test_X.shape[0] # 行数
p = sub_test_X.shape[1] # 列数
adj_r2 = 1 - (1-r2)*(n-1)/(n-p-1)
print('调整R2值为:{}'.format(round(adj_r2, 2)))

通过标准化后回归方程,可以得到各个特征的系数,即各个特征对“年平均购买付费课程数”的驱动力大小,对系数进行排序,图下所示。


df1 = pd.DataFrame(index = coef_df2.index.tolist())
df1['正向驱动/负向'] = np.where(coef_df2['Coefficients']>0,'+','-')
df1 = pd.concat([coef_df2,df1],axis=1)
df1.index.name = '指标'
# df1.shape[0] # 查看行数
df1 =df1.reset_index()
df1.drop([7],axis = 0,inplace = True) # 删掉截距

df1['Coefficients'] = abs(df1['Coefficients'])
df1 = df1.sort_values(by = 'Coefficients',ascending =False)
df1

互联网教育-用户分析案例(驱动力分析&学员画像)_第32张图片
查找原因
第一次构建回归模型的效果较差,可能是因为特征变量与因变量的相关性不强,观察各个特征变量与因变量的相关系数矩阵热力图,可以看出, 特征变量与因变量的相关系数普遍较小。

train_df = pd.concat([sub_test_X,test_ln_y],axis = 1)
sns.heatmap(data=train_df.corr(),annot=True,linewidths=0.5, fmt='.1f',cmap=plt.cm.Reds)

互联网教育-用户分析案例(驱动力分析&学员画像)_第33张图片
解决方案
当特征不足或者现有的特征数据跟样本标签的相关性不强时,很容易处罚欠拟合现象。

  • 扩展新的特征。通过挖掘上下文特征,组合特征等行的特征,增加对y值的解释。
  • 改进特征筛选步骤。之前直接删除分类变量,可能删掉了对y值的解释较好的变量,需要改进特征的筛选步骤,如果部分特征的回归系数很小,可以使用相关系数法在回归前对特征进行筛选,还可以结合RFECV进行交叉验证的递归特征消除实现特征选择。

3. 第二次多元线性回归-扩展新的特征

(1)新增特征变量

为了重新构建更多可能与因变量相关性大的特征,增加对因变量值的解释,新增以下5个特征。

data['用户首次学习年龄'] = data['首次上课日期'].dt.year - data['出生年']
data['是否为一线城市'] = np.where(data.重点城市或区域.isin(['北京市','上海市','广州市','杭州市','深圳市']) ,'一线城市','其他')
data['注册到激活时长'] = data['首次上课日期']-data['注册日期']
data['注册到激活时长'] = data['注册到激活时长'].dt.days
data['高粘性用户'] = np.where(data['年平均购买付费课程数']>=3,'yes','no')
data['学习周期'] = (data['最后上课日期']-data['首次上课日期']).dt.days

互联网教育-用户分析案例(驱动力分析&学员画像)_第34张图片
为了加深对各个特征的理解,对各个指标进行可视化观察。
互联网教育-用户分析案例(驱动力分析&学员画像)_第35张图片
年平均购买付费课程数最小为0.34,最大为182.5。年平均购买付费课程数集中在0-8,其中1-2最多,占比超过一半。
互联网教育-用户分析案例(驱动力分析&学员画像)_第36张图片
课平均作业提交数集中在0-20,年平均优秀学员数集中在0-10之间。将年平均优秀学员数大于20的,使用边界值替换。课平均作业提交数大于30的,使用边界值替换。替换后的数值分布,如右图所示。
互联网教育-用户分析案例(驱动力分析&学员画像)_第37张图片
占比最多的是学习周期为0-120天的学员
互联网教育-用户分析案例(驱动力分析&学员画像)_第38张图片
互联网教育-用户分析案例(驱动力分析&学员画像)_第39张图片
用户首次学习年龄集中在20-35之间。将用户年龄小于10的数值,替换为中位数。替换后的数据分布如右图所示
互联网教育-用户分析案例(驱动力分析&学员画像)_第40张图片
用户集中在北京市,上海市,东部和深圳市。
互联网教育-用户分析案例(驱动力分析&学员画像)_第41张图片
用户从注册到激活时长绝大多数在150天以内。如果超过这个时间,用户很可能流失。
互联网教育-用户分析案例(驱动力分析&学员画像)_第42张图片
以“用户首次上课日期”定义为“成功转化用户”,即付费用户。新增付费用户在2018年开始出现明显增长,2019年2月达到峰值。月成功转化用户超过1750人。
互联网教育-用户分析案例(驱动力分析&学员画像)_第43张图片
定义年平均购买付费课程数>=3的用户为高粘性用户,用户占比为24.3%。绘制高粘性用户-城市&工作年限热力图,可以看出高粘性用户集中分布在北京市,其中2年工作经验的学员最多。

(2)剔除与y值不相关的特征变量

与第一次多元线性回归步骤相同,进行数据读取,数据类型转换,删除不需要的特征变量,并切分自变量和因变量,随机种子为4时,取75%的数据为训练集,25%的数据为测试集。
读取数据,日期转换为数值型变量,将 ‘性别’,‘重点城市或区域’,‘是否为互联网行业’,‘工作年限’,‘是否为一线城市’,‘高粘性用户’ 转换为哑变量,删除’城市’,‘行业’,‘Unnamed: 0’,‘主键’,‘截止日期’,‘购买付费课数量’,‘获得优秀学员的次数’,'提交必做作业总数’共8个特征。

lm_data = pd.read_csv('./user_data.csv', encoding='gbk') # 读取数据
# 日期转换为数值型变量
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)
lm_data['截止日期']=pd.to_datetime(lm_data['截止日期']).map(dt.datetime.toordinal)
lm_data['工作年限'] = lm_data['工作年限'].astype(object)

lm_data = pd.get_dummies(data=lm_data,columns=['性别','重点城市或区域','是否为互联网行业','工作年限','是否为一线城市','高粘性用户'],drop_first=False) 

lm_data.drop(['城市','行业','Unnamed: 0','主键','截止日期','购买付费课数量','获得优秀学员的次数','提交必做作业总数'],axis=1,inplace=True)

# 切分因变量和自变量 
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_df = pd.concat([train_X,train_y],axis = 1)
plt.rcParams['axes.unicode_minus'] = False  #负号显示

#热力图展示相关系数
figure = plt.subplots(figsize = (15,15))
sns.heatmap(train_df.corr(),annot=True,linewidths=0.5, fmt='.1f',cmap=plt.cm.Reds,annot_kws={'size':8})

互联网教育-用户分析案例(驱动力分析&学员画像)_第44张图片
剔除与train_y值相关系数小于0.05的特征。包括:‘优秀比例’, ‘是否为互联网行业_no’, ‘重点城市或区域_中部’, ‘是否为一线城市_其他’, ‘作业平均分’, ‘重点城市或区域_东北’, ‘重点城市或区域_深圳市’, ‘性别_男’, ‘重点城市或区域_澳门’, ‘用户首次学习年龄’, ‘重点城市或区域_台湾’, ‘重点城市或区域_东部’, ‘重点城市或区域_香港’, ‘重点城市或区域_上海市’, ‘重点城市或区域_西部’, ‘性别_女’, ‘重点城市或区域_广州市’, ‘重点城市或区域_杭州市’, ‘重点城市或区域_北京市’, ‘是否为一线城市_一线城市’, ‘工作年限_1’, ‘工作年限_2’, ‘是否为互联网行业_yes’, ‘出生年’,共24个特征量。

# 剔除与train_y值相关系数小于0.05的变量
df_corr = train_df.corr()
df_drop = df_corr.sort_values(by = '年平均购买付费课程数')['年平均购买付费课程数']
df_drop = df_drop[abs(df_drop)<0.05].index.tolist()
train_df.drop(df_drop,axis=1,inplace=True)
# 对测试集执行相同的操作,删除相同的24个特征变量
test_X.drop(df_drop,axis=1,inplace=True)
# 剔除与train_y没有相关性的变量
train_df.drop(df_drop,axis=1,inplace=True)
# 对test_X执行相同操作
test_X.drop(df_drop,axis=1,inplace=True)

(3)剔除存在多重共线性的特征变量

使用线性回归模型,需要特征变量之间不存在多重共线性。使用热力图展示特征时间的相关系数,初步观察特征之间的相关情况。

# 切分因变量和自变量 
train_X = train_df.drop(['年平均购买付费课程数'],axis=1 )
train_y = train_df.loc[:,['年平均购买付费课程数']] 
plt.rcParams['axes.unicode_minus'] = False  #负号显示

#热力图展示相关系数
figure = plt.subplots(figsize = (12,8))
sns.heatmap(data=train_X.corr(),annot=True,linewidths=0.5, fmt='.1f',cmap=plt.cm.Reds)

互联网教育-用户分析案例(驱动力分析&学员画像)_第45张图片
计算所有特征的VIF值,如左图所示。删除VIF>10的特征,再次计算所有特征的VIF值,对test_X执行相同操作。

# VIF多重共线性检验
import statsmodels
from statsmodels.stats.outliers_influence import variance_inflation_factor
# 计算当前所有特征的VIF值

vif = pd.DataFrame()
vif["Features"] = train_X.columns
vif["VIF_Factor"] = [variance_inflation_factor(train_X.values, i) for i in range(train_X.shape[1])]
vif["VIF_Factor"] = np.round(vif["VIF_Factor"].astype(np.float64),2)
vif

# VIF多重共线性  去掉首次上课日期,注册日期,高粘性用户_0
# 根据拟合结果,
vif.drop([0,2,10],axis=0,inplace=True)

row_num = vif.shape[0]
sub_X2 =train_X[pd.DataFrame(vif['Features'].values.tolist()).iloc[0:row_num].values.reshape(row_num,).tolist()] 

vif2 = pd.DataFrame()
vif2["Features"] = sub_X2.columns
vif2["VIF_Factor"] = [variance_inflation_factor(sub_X2.values, i) for i in range(sub_X2.shape[1])]
vif2["VIF_Factor"] = np.round(vif2["VIF_Factor"].astype(np.float64),2)
vif2

互联网教育-用户分析案例(驱动力分析&学员画像)_第46张图片
互联网教育-用户分析案例(驱动力分析&学员画像)_第47张图片

sub_test_X = test_X[pd.DataFrame(vif['Features'].values.tolist()).iloc[0:row_num].values.reshape(row_num,).tolist()] 

互联网教育-用户分析案例(驱动力分析&学员画像)_第48张图片

(4)使用特征选择RFECV确定最佳特征的数量

在删除与y值相关性弱的特征变量后,使用特征选择RFECV方法实现特征选择,分以下两步进行。

  • 递归特征消除,用来对特征进行重要性评级,
  • 交叉验证,在特征评级后,通过交叉验证,选择最佳数量的特征

首先,对因变量做对数转换

# 对训练集取对数
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')

使用箱型图查看train_ln_y的分布情况,异常值共48条,使用临界值代替异常值。

# 箱型图看数据分布情况
fig = plt.figure(figsize=(10,5))
ax1 = fig.add_subplot(2,1,1)

color = dict(boxes = 'DarkGreen',whiskers = 'DarkOrange',medians = 'DarkBlue',caps = 'Gray')
# boxes表示箱体,whisker表示触须线,medians表示中位数,caps表示最大与最小值界限

# bc_y.plot.box(vert = False,grid = True,color = color,ax = ax1, label = '年龄分布',sym='r+')
train_ln_y.plot.box(vert = False,grid = True,color = color,ax = ax1, label = '年龄分布',sym='r+')
# sym参数表示异常值标记的方式

# 定义上边缘和下边缘,(上四分位数 + 1.5倍四分位数)和 (下四分位数-1.5倍四分位数)
s = train_ln_y.describe()
q1 = s.loc['25%']
q3 = s.loc['75%']
iqr = q3 - q1
mi = q1 - 1.5*iqr
ma = q3 + 1.5*iqr

# 得到异常值(上下边缘以外)
ax2 = fig.add_subplot(2,1,2)
error = train_ln_y[(train_ln_y < mi) |(train_ln_y > ma)]  
sub_df_c =  train_ln_y[(train_ln_y >= mi)& (train_ln_y <= ma)]
print('异常值共%i条'%(len(error)-np.isnan(error.values).sum()))#只写len(error)会把nan计算进去

#散点图画出异常值
plt.scatter(sub_df_c.index,sub_df_c,color = 'k',marker='.',alpha = 0.3)
plt.scatter(error.index,error,color = 'r',marker='.',alpha = 0.7)
plt.title('')
plt.show()

# 筛选出训练集中的异常值
df_mi = (train_ln_y < mi) 
df_ma = (train_ln_y > ma)
drop_abnormal_mi = df_mi[df_mi['年平均购买付费课程数'] == True].index.tolist()
drop_abnormal_ma = df_ma[df_ma['年平均购买付费课程数'] == True].index.tolist()

# 训练集中,使用临界值替换异常值
t = np.arange(len(drop_abnormal_mi)).reshape(len(drop_abnormal_mi),1).astype(float)
t[:,0] = mi
train_ln_y.loc[drop_abnormal_mi,:] = t

t2 = np.arange(len(drop_abnormal_ma)).reshape(len(drop_abnormal_ma),1).astype(float)
t2[:,0] = ma
train_ln_y.loc[drop_abnormal_ma,:] = t2

互联网教育-用户分析案例(驱动力分析&学员画像)_第49张图片
RFECV方法实现特征选择

# 将训练集数据标准化
from sklearn.preprocessing import StandardScaler
s = StandardScaler()
train_X_standard = s.fit_transform(sub_X2)
train_X_standard = pd.DataFrame(data=train_X_standard, columns=list(sub_X2.columns))

# 将测试集数据标准化
test_X_standard = s.transform(sub_test_X)
test_X_standard = pd.DataFrame(data=test_X_standard, columns=list(sub_test_X.columns))

from sklearn.linear_model import LinearRegression
lr = LinearRegression()

lr.fit(train_X_standard,train_ln_y)
print(lr.score(train_X_standard,train_ln_y))

from sklearn.feature_selection import RFECV

rfecv = RFECV(estimator=lr, step=1, cv=5, n_jobs=-1,scoring="r2")
rfecv.fit(train_X_standard,train_ln_y)
print(rfecv.n_features_)
print(rfecv.estimator)
print(rfecv.ranking_)
print(rfecv.support_)
print(rfecv.grid_scores_)

plt.plot(range(1,len(rfecv.grid_scores_)+1),rfecv.grid_scores_,marker = 'o')
plt.xlabel("特征数量")
plt.ylabel("交叉验证$R^2$值")

print("剔除变量:",train_X_standard.columns.values[~rfecv.support_])
x_train_eli = rfecv.transform(train_X_standard)
x_test_eli = rfecv.transform(test_X_standard)
print(rfecv.estimator_.score(x_train_eli,train_y))
print(rfecv.estimator_.score(x_test_eli,test_y))

# 输出特征重要性条形图
plt.rcParams['axes.unicode_minus'] = False

li = list(zip(train_X_standard.columns.values[rfecv.support_],rfecv.estimator_.coef_[0]))
li.sort(key= lambda x: abs(x[1]),reverse=True)
sa = pd.Series(dict(li))
plt.figure(figsize=(15,15))
sns.barplot(y= sa.index,x= sa.values)
plt.grid()
plt.show()

结果显示:

  • 训练集-多元线性回归模型的R方为: 0.8116277006248216
  • 经过特征选择后,剩余的特征数量: 9
  • 经过特征选择后,使用缩减特征训练后的模型: LinearRegression()
  • 每个特征的等级(数值越小,特征越重要): [1 1 1 1 1 1 1 1 1]
  • 布尔数组(表示特征是否被选择):[ True True True True True True True True True]
  • 模型交叉验证的评分(对应数量特征):[0.69482763 0.78995774 0.79716303 0.80856304 0.80913564 0.81072245 0.81074097 0.8110685 0.81117516]
  • 剔除变量: []
  • 剔除边变量后,训练集多元线性回归模型的R方为:0.8009161579608666
  • 剔除变量后,测试集多元线性回归模型的R方为:0.7881717899723569
    互联网教育-用户分析案例(驱动力分析&学员画像)_第50张图片
    互联网教育-用户分析案例(驱动力分析&学员画像)_第51张图片
    根据特征选择RFECV的结果,不需要剔除多余特征变量,最佳特征的数量为9。对因变量贡献最大的特征是‘高粘性用户’,其次是‘最后上课日期’,‘课平均作业提交数’,‘年优秀学员数’

4. 第二次多元线性回归

from sklearn.linear_model import LinearRegression
lr = LinearRegression()

# 基于训练集对测试集进行预测
lr.fit(sub_X2,train_ln_y)
# 输出线性回归模型的系数
coef_df = pd.DataFrame(lr.coef_[0], sub_X2.columns, columns=['Coefficients'])
# 增加截距项
coef_df = coef_df.append(pd.DataFrame(lr.intercept_[0], columns=['Coefficients'],index=['(截距)']))
coef_df.sort_values(by= ['Coefficients'],ascending=True)
coef_df = coef_df.astype(np.float64)
coef_df

互联网教育-用户分析案例(驱动力分析&学员画像)_第52张图片
使用回归模型对测试集进行预测,得到R2值为:0.79,调整R2值为:0.79。
将预测结果和真实值进行对比,使用折线图进行可视化展示。

# 预测
y_hat = lr.predict(sub_test_X)

# 绘制因变量的预测值与实际值对比图
fig = plt.figure(figsize=(10,5))
plt.plot(range(len(y_hat)),y_hat,color='red',label='预测值',alpha = 0.3)
plt.plot(range(len(test_ln_y)),test_ln_y,color='black',label='真实值',alpha = 0.3)
plt.title('真实值与预测值',fontsize = 20)
plt.legend(fontsize= 10)
plt.show()

互联网教育-用户分析案例(驱动力分析&学员画像)_第53张图片
标准化后构建线性回归模型,分析驱动力
为了消除特征值大小对回归系数的影响,真实反映各个特征对因变量的贡献,需要将数据进行标准化处理。如下所示

# 将数据标准化
from sklearn.preprocessing import StandardScaler
s = StandardScaler()
X_standard = s.fit_transform(sub_X2)
train_X_standard = pd.DataFrame(data=X_standard, columns=list(sub_X2.columns)) 

# 创建线性回归模型实例
from sklearn.linear_model import LinearRegression
lr2 = LinearRegression()
# 拟合数据
lr2.fit(train_X_standard, train_ln_y)
# 输出线性回归模型的系数
coef_df2 = pd.DataFrame(lr2.coef_[0], train_X_standard.columns, columns=['Coefficients'])
# 增加截距项,并对系数大小进行排序
coef_df2 = coef_df2.append(pd.DataFrame(lr2.intercept_[0], columns=['Coefficients'],index=['(截距)'])).sort_values(by= ['Coefficients'],ascending=True)
coef_df2

互联网教育-用户分析案例(驱动力分析&学员画像)_第54张图片
对标准化后的测试集进行预测,对比测试集的真实值和预测值

# 将测试集数据标准化
from sklearn.preprocessing import StandardScaler
test_X_standard = s.transform(sub_test_X)
test_X_standard = pd.DataFrame(data=test_X_standard, columns=list(sub_test_X.columns))
# 预测
y_hat2 = lr2.predict(test_X_standard)

# 绘制y的预测值与实际值对比图
fig = plt.figure(figsize=(10,5))
plt.plot(range(len(y_hat2)),y_hat2,color='red',label='预测值',alpha = 0.3)
plt.plot(range(len(test_ln_y)),test_ln_y,color='black',label='真实值',alpha = 0.3)
plt.title('标准化后-真实值与预测值',fontsize = 20)
plt.legend(fontsize= 10)
plt.show()

互联网教育-用户分析案例(驱动力分析&学员画像)_第55张图片

5. 第二次线性回归模型检验及结果分析

为了检验模型的准确性,对标准化前后的模型计算 R 2 R^2 R2,判断模型的拟合优度。结果显示,标准化前 R 2 R^2 R2为0.79,调整 R 2 R^2 R2为0.79。标准化后, R 2 R^2 R2为0.79,调整 R 2 R^2 R2为0.79。相较第一次线性回归的0.46,已经有了明显的提升。这说明新特征的加入、特征变量选取的优化能明显提升此多元线性回归模型预测的准确性。

# 模型检验
from sklearn.metrics import r2_score
r2 = r2_score(test_ln_y, y_hat2)
print('R2值为:{}'.format(round(r2, 2)))

# 调整r2
n = sub_test_X.shape[0] # 行数
p = sub_test_X.shape[1] # 列数
adj_r2 = 1 - (1-r2)*(n-1)/(n-p-1)
print('调整R2值为:{}'.format(round(adj_r2, 2)))
# 标准化后,模型检验
from sklearn.metrics import r2_score
r2 = r2_score(test_y, y_hat2)
print('R2值为:{}'.format(round(r2, 2)))

# 调整r2
n = test_X.shape[0] # 行数
p = test_X.shape[1] # 列数
adj_r2 = 1 - (1-r2)*(n-1)/(n-p-1)
print('调整R2值为:{}'.format(round(adj_r2, 2)))

基于标准化后多元线性回归模型,将特征按照回归系数大小进行排序,如左图所示。回归系数绝对值越大,说明特征变量对因变量的影响越大,驱动效果越明显,绝对值排序,如右图所示。

# 驱动力排序
df1 = pd.DataFrame(index = coef_df2.index.tolist())
df1['正向驱动/负向'] = np.where(coef_df2['Coefficients']>0,'+','-')
df1 = pd.concat([coef_df2,df1],axis=1)
df1.index.name = '指标'

df1 =df1.reset_index()
df1.drop([7],axis = 0,inplace = True) #删掉截距

df1['Coefficients'] = abs(df1['Coefficients'])
df1 = df1.sort_values(by = 'Coefficients',ascending =False)
df1

互联网教育-用户分析案例(驱动力分析&学员画像)_第56张图片
将驱动因素及权重保存到《驱动力指标排序.csv》中。

df1.to_csv('./驱动力指标排序.csv',encoding = 'gbk')

为了有效分析驱动因素对“年平均购买付费课程数”的影响,重点关注回归系数大于0.1的变量。对“年平均购买付费课程数”驱动最大的是高粘性用户_yes,其次是最后上课日期,年平均优秀学员数,课平均作业提交数。

  • 正向驱动:高粘性用户_1越多,最后上课日期数值越大,年平均优秀学员数越多,注册到激活时长越长,学习周期越长,续费课程的次数越多,则“年平均购买付费课程数”越大
  • 负向驱动:课平均作业提交数越少,工作年限_0和工作年限_3的学员越少,则“年平均购买付费课程数”越大
    针对各驱动因素,从课程开发阶段,课程进行阶段,课程结束后三个阶段结合用户生命周期进行分析,提出对应运营策略,建议方案如下。
    互联网教育-用户分析案例(驱动力分析&学员画像)_第57张图片

五、学员画像及用户分层运营策略

使用K-means算法,通过肘部法则选取聚类数量(能选奇数不选偶数,能选少的不选多的,如果没有很强的肘部依据,尽量不要超过5个),对所有学员进行聚类,基于用户画像分层,提出对营销团队有价值的用户分层运营策略。

1. Kmeans模型实现用户画像分层

从《user_data.csv》读取数据,并查看空缺值和重复值,使用data.info()查看每一列数据的基本信息。此时,数据中不存在缺失值,不存在重复值。

# 读取数据
data = pd.read_csv('./user_data.csv', encoding='gbk')

# 查看空缺值
data.isna().sum()
data[data=='inf'].sum()

# 查看重复值
data[data.duplicated()==True]
data.info()

互联网教育-用户分析案例(驱动力分析&学员画像)_第58张图片
选取’作业平均分’,‘提交必做作业总数’,‘工作年限’,'年平均购买付费课程数’作为聚类变量,并绘制数据与’年平均购买付费课程数’之间的散点图,初步观察数据的分布。

sub_loc_df = data[['作业平均分','提交必做作业总数','工作年限','年平均购买付费课程数']]
# 可视化
import seaborn as sns
import matplotlib.pyplot as plt
# sns.pairplot(sub_loc_df,diag_kind='kde',kind='reg')
plt.figure(figsize=(15,5))
plt.rc('font',family='Microsoft YaHei') # 此语句确保绘图中的中文可以正常显示
plt.subplot(2,2,1)
sns.scatterplot(x="作业平均分", y="年平均购买付费课程数", data=sub_loc_df)
plt.subplot(2,2,2)
sns.scatterplot(x="提交必做作业总数", y="年平均购买付费课程数", 
data=sub_loc_df)
plt.subplot(2,2,3)
sns.scatterplot(x="工作年限", y="年平均购买付费课程数", data=sub_loc_df)
plt.show()

互联网教育-用户分析案例(驱动力分析&学员画像)_第59张图片
使用肘部法则和轮廓系数法选择聚类个数。肘部法则中,计算聚类个数分别为1-14时,所有点到其所属聚类质心距离的误差平方和,随着聚类个数增多,误差平方和主键下降,直到某一临界值,下降幅度明显变缓,此时,增加聚类中心不能有效降低误差平方和。此时的聚类个数是最佳的聚类个数,由左图可知,为5。轮廓系数法绘制的图型(右图)显示,最优聚类个数也是5。

# 导入kmeans包
from sklearn.cluster import KMeans
km_df = sub_loc_df

# 数据标准化
from sklearn.preprocessing import StandardScaler
km_df_standardize = StandardScaler().fit_transform(km_df)
km_df_standardize = pd.DataFrame(data=km_df_standardize, 
columns=list(km_df.columns)) 

# 肘部法则选择聚类个数
from scipy.spatial.distance import cdist
# 存放每次结果的误差平方和
cost = []
# 尝试不同的聚类个数
K = range(1, 15)
for k in K:
    kmeanModel = KMeans(n_clusters=k, random_state=99)
    kmeanModel.fit(km_df_standardize)
cost.append(kmeanModel.inertia_)
# inertia_是所有点到其所属聚类质心距离的误差平方和
# 肘部法则可视化
plt.xlabel('k')
plt.ylabel('cost')
plt.plot(K, cost, 'o-')
plt.show()

# 利用轮廓系数法寻找最优的聚类个数
from sklearn.metrics import silhouette_samples, silhouette_score
# 生成不同聚类个数下的轮廓系数
cost1=[]
k=range(2,15)
for i in k:
    km=KMeans(n_clusters=i,random_state=1)
    km.fit(km_df_standardize)
cost1.append(silhouette_score(km_df_standardize,km.labels_,metric='euclidean'))

# 绘制不同聚类个数下的轮廓系数折线图
fig=plt.figure(figsize=(10,5))
plt.plot(k,cost1,"o-")
plt.xlabel("k",fontsize=15)
plt.ylabel("cost1",fontsize=15)
plt.show()

互联网教育-用户分析案例(驱动力分析&学员画像)_第60张图片
运行Kmeans模型得到聚类结果,并将聚类结果可视化,从散点图可以看出,各个类别之间能较为清晰的区分出来,说明聚类效果较好。

# 训练k_means模型
km = KMeans(n_clusters=5, random_state=99)
km.fit(km_df_standardize)
# 将新标签组合到原来的数据框里面
km_label = pd.DataFrame(km.labels_, columns=['新标签'])
km_df = pd.concat([km_df, km_label],axis=1)
km_df.head()

# 将聚类结果可视化
plt.rcParams['axes.unicode_minus'] = False
sns.set_palette("dark",5)
plt.figure(figsize=(15,5))
plt.rc('font',family='Microsoft YaHei') # 此语句确保绘图中的中文可以正常显示
plt.subplot(2,2,1)
sns.scatterplot(x="作业平均分", y="年平均购买付费课程数", hue="新标签", 
data=km_df, palette="Set1")
plt.subplot(2,2,2)
sns.scatterplot(x="提交必做作业总数", y="年平均购买付费课程数", hue="新标签", 
data=km_df, palette="Set1")
plt.subplot(2,2,3)
sns.scatterplot(x="工作年限", y="年平均购买付费课程数", hue="新标签", 
data=km_df, palette="Set1")
plt.show()

互联网教育-用户分析案例(驱动力分析&学员画像)_第61张图片
互联网教育-用户分析案例(驱动力分析&学员画像)_第62张图片

2. 提炼用户画像并提出对应运营策略

聚类结果如下表所示。对每一类数据,取’作业平均分’,‘提交必做作业总数’,‘工作年限’,'年平均购买付费课程数’的中位数、最大值、最小值。增加每一类的人数,高粘性用户占比两列,增加对聚类结果的理解。绘制每一个类别的概率密度图,将学员分为5类。

final_loc_df = final_df[['作业平均分','提交必做作业总数','工作年限','年平均购买付费课程数','是否为一线城市']]
# 每一列绘制概率密度图
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
def density_plot(df):
    p = df.plot(kind ='kde',linewidth = 2,subplots =True,sharex = False)
    plt.subplots_adjust(left=None, bottom=0.1, right=0.9, top=None,
                wspace=0.8, hspace=0.8)
    #  调整子图间距,其中的wspace是子图之间的垂直间距,hspace是子图的上下间距 
    [p[i].set_ylabel('density') for i in range(5)]
    plt.legend()
    return plt
for i in range(5):
    density_plot(final_loc_df[final_df['新标签']==i])
print()

互联网教育-用户分析案例(驱动力分析&学员画像)_第63张图片
5类学员分别为“积极新人”、“积极进修者”,‘‘超级学员’’,‘‘核心学员’’,“核心小白”。
互联网教育-用户分析案例(驱动力分析&学员画像)_第64张图片
互联网教育-用户分析案例(驱动力分析&学员画像)_第65张图片
针对5类学员,根据用户学习行为特点,总结用户痛点,使用AARRR模型从用户获取、老客召回、激活、留存、促活、变现、传播角度分析,给出相应的运营策略建议。
互联网教育-用户分析案例(驱动力分析&学员画像)_第66张图片
互联网教育-用户分析案例(驱动力分析&学员画像)_第67张图片
互联网教育-用户分析案例(驱动力分析&学员画像)_第68张图片
互联网教育-用户分析案例(驱动力分析&学员画像)_第69张图片
互联网教育-用户分析案例(驱动力分析&学员画像)_第70张图片

你可能感兴趣的:(Python3,多元线性回归)