基于K-均值的app列表聚类分析优化

目录

一、过滤词表筛选

二、模型更新

三、app类型处理

1. 统计app类型占比

2. 新增app类型特征


基于K-均值的app列表聚类分析中,初步完成用户app列表特征聚类。我们在评估中发现以下几个问题:

  • 某些同类用户app列表出现大量相同的国民app(如支付宝、微信、QQ、腾讯视频等)和系统app(如日志和备份、相机等);
  • 部分app属性对应有app类别,这部分信息没有利用起来;

针对以上问题,主要做了一下优化:

  • 统计app名称词表,挑选top N作为过滤词表;
  • 统计具有app类别占比,如果占比较高(60%以上),则将app名称和app类别均提取为稀疏向量,作为K-均值模型特征,否则还是以app名称作为输入特征;

一、过滤词表筛选

hive(odps/spark) sql统计app名称词表

SELECT  t2.app_name
        ,t2.cnt
        ,t2.updated_client
FROM    (
            SELECT  app_name
                    ,COUNT(1) cnt
                    ,t1.updated_client
            FROM    (
                        SELECT  app_list_json
                                ,updated_client
                        FROM    user_app_list_all_parsed
                        WHERE   dt = '${dt}'
                    ) t1
            LATERAL VIEW EXPLODE(SPLIT(t1.app_list_json, ';')) appTable AS app_name
            GROUP BY app_name
                     ,t1.updated_client
        ) t2
ORDER BY t2.cnt DESC
LIMIT   100
;

筛选出app词表如下

app名称 count system
alipays 13370011 ios
alipayshare 13369783 ios
天气 12284068 android
微信 11062865 android
QQ 10659983 android
Pico TTS 10636702 android
手机淘宝 10627003 android
支付宝 10596229 android
网络位置 10516984 android
指南针 10187484 android
相册 9516585 android
tenvideo 9307299 ios
腾讯视频 9204797 android
爱奇艺 9039991 android
抖音短视频 8957105 android
云服务 8838426 android
... ... ...

二、模型更新

为了避免国民app和系统app导致用户趋于大同,需要对样本进行过滤处理,如下

    import spark.implicits._
    // 加载textFile
    val df = spark.read.textFile(Constants.SAMPLE).map(row=>{
      val rows = row.split(",")
      AppList(rows(0).toLong,rows(1).split(";").filter(!Constants.APP_FILTER_VOCABULARY.split(",").contains(_)))
    }).toDF("uid","app_list").repartition(numPartitions)

其他过程保持不变。

重新迭代模型,得到ssd随k均值变化趋势,如下

采用手肘法,选取最佳k=26。

三、app类型处理

1. 统计app类型占比

同样采用hive(odps/spark) sql统计app类型占比

SELECT  COUNT(1) cnt
        ,COUNT(DISTINCT t3.app_name) cdnt
FROM    (
            SELECT  t1.app_name
                    ,t2.app_name app_name1
                    ,t1.app_category
            FROM    (
                        SELECT  *
                        FROM    dw_user_app_list_android
                        WHERE   dt = '${dt}'
                    ) t1
            LEFT OUTER JOIN (
                                SELECT  *
                                FROM    app_vocabulary
                                WHERE   dt = '${dt}'
                                AND     updated_client = 3
                            ) t2
            ON      t1.app_name = t2.app_name
        ) t3
WHERE   t3.app_name1 IS NOT NULL;

发现,具有app类型占比仅有1/6,大量数据缺失,不太适合作为聚类特征。

2. 新增app类型特征

假如具有app类型占比在60%以上,可以新增app类型特征处理。如下

    // app_list和app_category_list列转化为稀疏特征向量
    val vectorizerWords = Array("app_list","app_category_list")
    var flag = false
    val cvm = if(!fs.exists(new Path(Constants.COUNTVECTOR))){
      flag = true
      val vectorizers = vectorizerWords.map(col=>{
        new CountVectorizer().setInputCol(col).setOutputCol(col + "_cv").setMinDF(1).fit(df)
      })
      val cvms = new Pipeline().setStages(vectorizers)
      cvms.fit(df)
    }else{
      CountVectorizerModel.load(Constants.COUNTVECTOR)
    }
    if(flag){
      cvm.write.overwrite().save(Constants.COUNTVECTOR)
    }
    val result = cvm.transform(df).select("uid","app_list_cv","app_category_cv")
    result.cache()
    println("countVectorizer处理后分区数量:" + result.rdd.getNumPartitions)
    result.show(10,false)

    // result在Kmeans迭代寻优多次用到,因此加载内存
    val map = new util.HashMap[Int,Double]()
    // k-means聚类
    val ks = Range(minSeq, maxSeq)
    var minSsd = 0.0
    ks.foreach(cluster => {
      val ks = vectorizerWords.map(col=>{
        new KMeans()
          .setK(cluster)
          .setMaxIter(maxIter)
          .setFeaturesCol(col)
          .setPredictionCol(col + "_cv")
      })
      val kmeans = new Pipeline().setStages(ks)
      val kmm = kmeans.fit(result)

参考资料

https://blog.csdn.net/baymax_007/article/details/87986743

猜你喜欢

转载自blog.csdn.net/baymax_007/article/details/88222563