项目简介

项目数据集是一个音乐服务的用户日志,包含了用户信息,歌曲信息,用户活动,时间戳等。大小128M。需要通过数据集中信息,预测出可能流失的用户,以便后续对相应用户采取挽留措施

项目思路

为了预测可能流失的用户,对日志进行分析,探索并提取与用户流失相关的变量;根据变量,使用Spark建立机器学习模型进行预测。具如下:
1.加载所需的库并实例化
2.加载与清洗数据
3.探索性数据分析
4.构建预特征
5.建模预测
6.结论汇总

项目实现

1.加载所需的库并实例化

加载所需的库:

项目涉及的库
1、pyspark.sql:进行类似SQL操作
2、pyspark.ml:进行机器学习
3、pandas 、numpy:对dataframe操作
4、matplotlib、seaborn: 绘图
5、time:记录代码块运行时间的库

实例化

spark=SparkSession.builder.getOrCreate()

2.加载与清洗数据

加载数据集

原始数据集是json格式,由于需上传github,压缩为bz2格式。

df=spark.read.json('mini_sparkify_event_data.json.bz2')

评估数据集

对数据先查看整体情况,再查看重点希望了解的列的情况。
1、查看整体情况:
(1)查看数据前几行的值,了解数据集概况,对数据集有整体认识。主要使用show()函数
(2)查看列数、每列的名称以及类型,并结合以上了解每列的含义。主要使用printSchema()函数
(3)查看数据行数。主要使用.count()函数
通过以上观察,我们可了解到:数据集共有286500行,18列;主要包含了用户信息,歌曲信息,用户活动,时间戳等信息。变量含义推测如下:

 |-- artist: string (歌手)|-- auth: string (含义暂不明确)|-- firstName: string (名字)|-- gender: string (性别)|-- itemInSession: long (含义暂不明确)|-- lastName: string (姓氏)|-- length: double (听歌时长)|-- level: string (等级)|-- location: string (地区)|-- method: string (具体含义暂不明确)|-- page: string (页面)|-- registration: long (注册时间)|-- sessionId: long (页面ID)|-- song: string (歌名)|-- status: long (含义暂不明确)|-- ts: long (含义暂不明确)|-- userAgent: string (用户使用平台信息)|-- userId: string (用户ID)

2、查看某一列的值分布:
通过dropDuplicates()去重查看唯一值;sort对于有数值的进行排序,便于查看

df.select('userId').dropDuplicates().sort('userId').show()
+------+
|userId|
+------+
|      |
|    10|
|   100|
|100001|
|100002|
+------+
only showing top 5 rows

通过对各列进行查看,我们发现:
userId列存在非NA的空值,需要删除

清理数据集

处理空值

先通过dropna(),处理userId、sessionId列空值;

df_clean=df.dropna(how="any",subset=["userId","sessionId"])

再通过filter(), 去除有空字符的行.

df_clean=df_clean.filter(df["userId"]!="")

3.探索性数据分析

建立注销客户的标签

项目提示使用churn作为模型的标签, 并且建议使用Cancellation Confirmation事件来定义客户流失.。
1、标记注销事件:新建一列churn_event列,标记page中的Cancellation Confirmation事件
2、标记注销用户:新建一列churn_user列,标记注销用户。具体方法是,只要用户churn_event中有标记注销,该用户所有的churn列均标记为注销

建立注销客户的标签

定义好客户流失后, 进行探索性数据分析, 观察留存用户和流失用户的行为。绘图观察主要使用了直方图、小提琴图。相比箱线图,小提琴图更能看出密度分布
1、注销与用户添加播放列表数量的关系

#提取Add to Playlist数据,查看用户添加至播放列表数量的分布
lifetime_songs=df_clean.where('page=="Add to Playlist"').groupby(['userId','churn_user']).count().toPandas()
#绘制小提琴图
ax=sns.violinplot(data=lifetime_songs,x='churn_user',y='count')

  • 相比于非注销用户,注销用户将歌曲添加至播放列表的数量较少,且数量的分布相对集中,其小提琴图形相对扁平

2、是否注销与添加好友数量关系

#提取Add Friend数据,观察用户添加好友分布
add_friend=df_clean.where('page=="Add Friend"').groupby(['userId','churn_user']).count().toPandas()
#绘制小提琴图
ax=sns.violinplot(data=add_friend,x='churn_user',y='count')

  • 相比于非注销用户,注销用户添加好友的数量大多处于较低水平;非注销用户添加好友数量从高水平到低水平均有分布,且非注销用户添加好友数量最大值远远大于注销用户的最大值

3、是否注销与性别关系

#提取性别与用户ID列,观察注销与性别间关系
gender_churn=df_clean.dropDuplicates(["userId","gender"]).groupby(["churn_user","gender"]).count().toPandas()
#绘制直方图
ax=sns.barplot(x='gender',y='count',hue='churn_user',data=gender_churn)

  • 男性用户注销账户的绝对人数以及比例均比女性大

4.构建特征

变量选择

结合经验及以上的分析,构建以下变量:
1、听歌情况方面的变量:

  • 用户听歌数量:听歌数量越大,说明用户愿意使用该服务,注销几率越小。
  • 用户单次(同一sessionId)听歌最大数量:单次听歌数量越大,说明用户愿意使用该服务,注销几率越小
  • 播放的歌手数量:播放过的歌手数量越多,侧面说明用户听歌越多,越愿意使用该服务,注销几率越小。
    2、从page中提取动作建立变量:
  • 差评量:差评越多,说明用户不喜欢该服务,注销几率越大。
  • 添加播放列表量:用户将歌曲加进播放列表,一般可说明用户喜欢该音乐;添加的量越多,用户愿意使用该服务的可能性越大,注销可能性越小。
  • 添加好友量:添加好友量越多,说明用于越愿意在改服务中交友分享,注销几率越小。
    3、其他
  • 用户等级:用户曾经有付费,说明用户对该服务还是感兴趣的,注销几率相对小

变量提取

1用户听歌数量
获取每个用户点击页面NextSong的数量信息计数,获得用户添加进播放列表数量

feature_1=df_clean.select('userId','page').where(df_clean.page=="NextSong").groupBy('userId').count().withColumnRenamed('count','song_total')

2用户单次(同一sessionId)听歌最大数量
获取每个sessionId点击页面NextSong数量信息并计数,并按用户求最大值,可获得用户单次(同一sessionId)听歌最大数量

feature_5=df_clean.where('page=="NextSong"').groupBy('userId','sessionId').count().groupBy(['userId']).agg({'count':'max'}).withColumnRenamed('max(count)','max_songs_played')

3播放的歌手数量
#获取每个用户点击页面NextSong时的artist信息并计数,可获得用户听过的歌手数量

feature_6=df_clean.filter(df_clean.page=="NextSong").select("userId","artist").dropDuplicates().groupby("userId").count().withColumnRenamed("count","artist_total")

4差评量
获取每个用户点击页面Thumbs Down的数量信息计数,可获得用户差评量

feature_4=df_clean.select('userID','page').where(df_clean.page=='Thumbs Down').groupBy('userId').count().withColumnRenamed('count','Thumbs Down')

5添加播放列表量
获取每个用户点击页面Add to Playlist的数量信息计数,可获得用户添加进播放列表数量

feature_2=df_clean.select('userId','page').where(df_clean.page=='Add to Playlist').groupBy('userId').count().withColumnRenamed('count','add_to_playlist')

6添加好友量
获取每个用户点击页面Add Friend的数量信息计数,可获得用户添加好友书量

feature_3=df_clean.select('userId','page').where(df_clean.page=='Add Friend').groupBy('userId').count().withColumnRenamed('count','add_friend')

7是否曾经付费/等级
将level中free/paid转换为0/1;只有用户曾经付费,标记为1

windowval_feature=Window.partitionBy('userId')
feature_7=df_clean.select('userId','level').replace(['free', 'paid'],['0','1'],'level').select('userId', col('level').cast('int'))
feature_7=feature_7.withColumn('level_max',max('level').over(windowval_feature)).drop('level').dropDuplicates()

整理标签列
后续建模时,真实标记列默认为label列,将churn_user列重命名为label

label=df_clean.select('userId',col('churn_user').alias('label')).dropDuplicates()

变量聚合

1、通过join将变量连接,选用并集

df_feature=feature_1.join(feature_2,'userId','outer')\.join(feature_3,'userId','outer')\.join(feature_4,'userId','outer')\.join(feature_5,'userId','outer')\.join(feature_6,'userId','outer')\.join(feature_7,'userId','outer')\.join(label,'userId','outer')

2、无值的,用0填充

df_feature=df_feature.fillna(0)

3、删除索引

df_feature=df_feature.drop('userId')

5.建模预测

模型选用逻辑回归、支持向量机与随机森林。根据项目说明,选用 F1 score 作为主要优化指标。

准备数据

将数据转换为向量形式,标准化,并分成训练集、测试集和验证集

#用VectorAssembler将数据集转换为可供模型计算的结构(向量形式)
cols=["song_total","add_to_playlist","add_friend","Thumbs Down","max_songs_played","artist_total","level_max"]
assembler=VectorAssembler(inputCols=cols,outputCol="features_vec")
df_feature=assembler.transform(df_feature)#用StandardScaler标准化数据
scaler=StandardScaler(inputCol="features_vec",outputCol="features",withStd=True)
scalerModel=scaler.fit(df_feature)
df_feature=scalerModel.transform(df_feature)#按60%,40%,40%比例拆分为训练集、测试集和验证集
train,validation,test=data.randomSplit([0.6,0.2,0.2],seed=42)

模型选择

模型选择思路

  • 选用逻辑回归、支持向量机、随机森林进行对比,这几个模型一般不需要很多参数调整就可以达到不错的效果。他们的优缺点如下:
    1、逻辑回归:优点:计算速度快;缺点:容易产生欠拟合
    2、支持向量机:数据量较小情况下解决机器学习问题。缺点:对缺失数据敏感
    3、随机森林:优点:有抗过拟合能力。通过平均决策树,降低过拟合的风险性。缺点:大量的树结构会占用大量的空间和利用大量时间

模型训练

  • Random Forest
#创建并训练模型,通过time()记录训练时间
rf=RandomForestClassifier(seed=42)#初始化
start=time()#开始时间
model_rf=rf.fit(train)#训练
end=time()#结束时间
print('The training process took{} second'.format(end-start))#验证模型效果
results_rf=model_rf.transform(validation)#验证集上预测
evaluator=MulticlassClassificationEvaluator(predictionCol="prediction")#评分器
print('Random Forest:')
print('F-1 Score:{}'.format(evaluator.evaluate(results_rf,{evaluator.metricName:"f1"})))#计算F-1 Score
  • LogisticRegression、LinearSVC
    逻辑回归、支持向量机模型代码与随机森林与结构基本一致

计算结果

  • LogisticRegression模型:F-1 Score为0.7096;耗时121s
  • LinearSVC模型:F-1 Score为0.7096;耗时214s
  • Random Forest模型:F-1 Score0.7096;耗时215s
    LogisticRegression、Random Forest的F-1 Score一致,且较LinearSVC的高。为了避免过拟合,选取Random Forest作为最终模型,选用并通过调节模型参数尝试获取更优模型

模型调优

调优思路

  • 如上所述,选用Random Forest进行调优。
  • 使用3折交叉验证及参数网络对模型进行调优。
  • 选择FI-score作为衡量模型

指标选择
1、指标对比

  • Accuracy预测正确的结果占总样本的百分比,评估模型准确程度;
  • Recall在实际为正的样本中被预测为正样本的概率,评估模型能预测覆盖到多少正例;
  • Precision在所有被预测为正的样本中实际为正的样本的概率,评估预测为正样本的结果中,我们有多少把握可以预测正确
  • F1 Score同时考虑了Recall与 Precision。

2、指标选择

  • 因为流失客户在总的客户量中占比较少,数量类别不平衡。如采用accuracy作为指标,如果模型一直预测客户不流失,很容易就可以得到很好的结果,而该结果没有使用上意义
  • 由于Recall与Precision可能存在矛盾:如果预测比较“谨慎”,Precision提升,但是覆盖正例范围减少,Recall减小。为了覆盖更多正例“大胆”预测,Recall上升,但Precision会减少。
  • 就这个项目而言,如果我们为了找到更多的流失客户(扩大Recall),我们要把很多的资源用在挽留本来就不会流失的客户上(Precision低),如果我们为了精准挽留客户(提高Precision),便会导致很多没预测到的流失客户流失(Recall上升)。
  • 为了综合考虑,我们选用F1 Score指标

*参数调优

  • 对随机森林的两个参数:树的最大深度(maxDepth)、训练的树的数量(numTrees)进行了优化。
  • 对于最大深度尝试10及20两个值,对于树的数量尝试50及100两个值。
  • 原代码的基础上,对训练部分的代码做调整。
rf=RandomForestClassifier()#初始化模型
f1_evaluator=MulticlassClassificationEvaluator(metricName='f1')#选用f1-score来衡量优劣
paramGrid=ParamGridBuilder().addGrid(rf.maxDepth,[10,20]).addGrid(rf.numTrees,[50,100]).build()#建立可选参数的网络,主要对maxDepth、numTrees调整
crossval_rf=CrossValidator(estimator=rf,estimatorParamMaps=paramGrid,evaluator=f1_evaluator,numFolds=3)#3折交叉验证
cvModel_rf=crossval_rf.fit(train)#训练
  • 调优训练结果中,(10,50)的F1-score:0.7438;(10,100)的F1-score:0.7515;(20,50)的F1-score:0.7438;(20,100)的F1-score:0.7515。
  • 其中maxDepth=10;numTrees=100,以及maxDepth=20;numTrees=100的F1-score较高,为最优参数。选择最优参数,对验证集进行预测

*调优结果
选择最优结果在验证集预测

results_rf_cv=cvModel_rf.transform(validation)
  • 对比调优前后的模型在验证集上预测结果,调优前F-1 Score0.7096;调优后F-1 Score:0.7227,F-1 Score有提升
  • 故使用调优后模型在测试集进行最终预测

对测试集预测

在测试集预测

results_final=cvModel_rf.transform(test)
evaluator=MulticlassClassificationEvaluator(predictionCol="prediction")
print('Test:')
print('Accuracy:{}'.format(evaluator.evaluate(results_final,{evaluator.metricName:"accuracy"})))
print('F-1 Score:{}'.format(evaluator.evaluate(results_final,{evaluator.metricName:"f1"})))

在测试集上运算后:F-1 Score:0.6591,和在验证集的结果上相比,F-1 Score有下降。模型存在在过拟合

6.结论汇总

总结&反思

过程总结

  • 这个项目中,我们建立了一个预测流失用户的模型。
  • 在数据集中,我们删除了没有用户ID和sessionID的数据;对流失用户建立了标识,并结合对特征与是否流失间关系的探索,并建立了7个特征
  • 然后我们选择3个模型:逻辑回归,SVM和随机森林进行比较。根据比较结果。选择了随机森林预测最后结果。
  • 接着我们使用交叉验证和参数网络搜索调优随机森林的参数,对测试集进行预测。预测结果F-1 Score:0.6591

遇到的挑战
1、指标的构建。

  • 一方面,原始数据集中,可以直接用于预测的特征并不多,需要构建。本次构建的变量,大多需要从page中记录的动作提取
  • 另一方面,即便有现成的特征,也需要作一定转换。如level是现成的特征,但是一些用户既有付费的数据,也有免费的数据,无法说明用户到底是付费还是不付费。需要处理后才使用
  • 最后,构建哪些特征,需要经验积累。尽管可以通过逐一构建变量,逐一对比效果,但是需要耗费很多时间。

2、参数调优

  • 从原理上,尝试的参数组合越多,便越能知道调节的方向。但是,对过多的参数的尝试,程序很长的时间都跑不出结果,时间成本变高了

过程反思

  • 对比各未经优化的模型间F-1 Score,各模型相差不大。随机森林调优前后的提升也并不大。后续想有较大幅度提升,除了选取更优模型,更多可能需要从创建更合适的特征变量入手
  • 数据集中,现成的可用于预测的特征并不多;我们需要重新构造特征来预测流失用户。而从数据集中构造变量,除了需要探索、熟悉手上的数据;还需要经验与知识的积累

改进

1、相比于完整数据集(12G),数据量并不大。如果进一步增加数据量,可以得到预测效果更好的模型
2、用于预测流失用户的特征进一步增加完善,找到与数据集相关性更强的特征,以提升模型性能。如增加用户注销账户时的的等级作为特征;或者对未理解未探索的特征进一步研究
3、选用决策树、梯度提升树等其他算法,观察accuracy与f1分数变化,对比已使用的算法,选取更优模型

参考文献

机器学习概念回顾、精确率、召回率、F1-score、准确率、AUC、ROC曲线

精确率、召回率、F1 值、ROC、AUC 各自的优缺点是什么

随机森林介绍、关键参数分析

音乐服务流失用户预测相关推荐

  1. 音乐平台Sparkify流失用户预测

    Sparkify 流失用户分析 Sparkify是一个国外的音乐平台,本文将介绍预测Sparkify流失用户的过程.我们使用的数据是Sparkify的用户使用log,其中包含用户听的歌曲,时长,艺术家 ...

  2. 用户都跑了,你却还分不清流失用户和流失率

    PMCAFF(www.pmcaff.com):互联网产品社区,是百度,腾讯,阿里等产品经理的学习交流平台.定期出品深度产品观察,互联产品研究首选. 外包大师(www.waibaodashi.com): ...

  3. 银行流失用户分析及预测模型

    自学的一个银行流失客户预警的小项目 0.引言-银行流失用户分析 银行客户流失是指银行的客户终止在该行的所有业务,并销号.但在实际运营中,对于具体业务部门,银行客户流失可以定位为特定的业务终止行为. 商 ...

  4. 10年运营老兵,教你召回流失用户

    运营干货,5000余字,教你低成本召回流失用户 < 背景 > 电商平台A成立近10年,算不上行业TOP,但在细分领域发展不错. 2018年不景气,App日活从年初50万一路下跌,到现在运营 ...

  5. 华为分析服务| 基于用户生命周期 寻找增长机会点

    在当下的环境里,几乎所有应用都面临着巨大的用户增长挑战.这其中最主要的原因是互联网的人口红利衰退.用户数量以及增速越来越低,甚至在部分垂类里出现了负增长.电商.生活.游戏等行业的竞争也不断加大,同时, ...

  6. 企业网络推广期间对于易流失用户群体企业网络推广有话说

    对于企业网站来说,在搜索引擎中的推广运营而言,企业网站持续获取用户才是维持企业网络推广长期运营的根本,在获取用户的同时也要做好防止用户流失的措施,避免企业网站出现"铁打的网站流水的用户&qu ...

  7. 451 Research发布《2019年数据中心服务和基础设施预测》

    日前,451 research 发布<2019年数据中心服务和基础设施预测>报告,对数据中心发展趋势做出5项关键预测. 趋势一 数据中心供应商将与CSP厂商加强合作 据451 resear ...

  8. 谁在为网易云音乐2亿用户的即时通讯保驾护航?

    继2015年7月用户数破亿后,网易云音乐的发展与口碑一直让业界瞩目.近日,网易云音乐更是在北京的发布会上对外宣布用户数突破2亿,同比增长超过100%. 网易云音乐副总裁丁博透露,目前网易云音乐曲库收录 ...

  9. 微软关闭音乐服务器,微软关闭Zune音乐服务 Zune播放器变为MP3

    腾讯科技讯 11月16日消息,据外电报道,下载音乐或者串流播放网络歌曲,但Zune播放器仍可作为音乐继续播放器使用. 微软推出首款Zune音乐播放器和相应的Zune数字音乐服务还要追溯到2006年,但 ...

最新文章

  1. 面试大法——算法、Python、机器学习等笔试面经资源|干货收藏
  2. HTML table 标签的 frame 属性
  3. MAC EI Capitan上更新系统自带SVN版本号(关闭SIP方能sudo rm)
  4. centos mysql 5.6.19_Centos5.8 安装 MySQL5.6.19
  5. 不用临时变量交换两个变量的值
  6. html网页放大时文字不换行_WEB前端-html基础
  7. matlab heaviside,Matlab编写的Lyapunov指数计算程序汇总.doc
  8. redis内存知识点
  9. android 字体淡入淡出,如何让文字在Android中淡入淡出?
  10. mysql_use_result与mysql_store_result异同点
  11. c语言汉诺塔问题详解
  12. Silverlight:针式打印机文字模糊的改善办法
  13. OSI七层协议模型与记忆口诀
  14. 20 个有用的 Go 语言微服务开发框架吐血总结!!!
  15. readxmls r语言_R语言批量爬取NCBI基因注释数据
  16. 内核层读写应用层文件,使用filp_open函数——完美
  17. 换算rem的宽度和高度不生效 chrome字体最小为12px
  18. MOSFET管驱动电路图
  19. 量子计算机治愈癌症,如果量子计算机实现了,癌症可以治愈吗?
  20. 关于 电脑分配IP地址可以连接局域网但无法上互联网 的解决方法

热门文章

  1. W5500以太网控制器芯片(四):实现DNS功能
  2. Adobe Photoshop CC 国际认证考试学习指南(一)
  3. spring boot生成二维码
  4. troublemaker中文谐音_trouble maker歌词的中文译音
  5. 评:首只做空中国股市ETF在美上市
  6. 尝试用分区助手往硬盘盒子里迁移系统
  7. robotframework-ride生成新建机器人标志的快捷方式
  8. mac brew cask安装软件提示:Error: Unknown command: cask
  9. Python-基于ARIMA模型股票趋势预测
  10. Golang源码探究 —— chan