用户画像篇·模型标签之用户行为性别预测

一、性别预测问题

  • 用户注册时,所填写的性别,存在大概率的随意性;
  • 不能完全作为用户画像的性别参考;

所以在无法通过直接手段获得用户真实性别的情况下,需要通过用户的各种行为特征,来对用户的性别进行预测。

二、特征数据选取

(1)比如选取以下的用户特征数据:
category1: 	 30天内买得最多的品类
category2:	     30天内买得第二多的品类
category3:      30天内买得第三多的品类
brand1:         30天内买得最多的品牌
brand2:         30天内买得第二多的品牌
brand3:         30天内买得第三多的品牌
day30_buy_cnts: 30天内的购买单数
day30_buy_amt:  30天内的消费总金额
还可以加:       30天兴趣关键词中的top10个等等...
(2)经验样本数据
label,gid,category1,category2,category3,brand1,brand2,brand3,day30_buy_cnts,day30_buy_amt
0.0,1,105.0,106.0,102.0,1101.0,1108.0,1109.0,20.0,100.0
0,2,105,107,102,1101,1108,1105,25,80
0,3,106,104,102,1102,1108,1109,20,100
0,4,106,107,105,1103,1108,1105,30,90
0,5,112,107,105,2103,1108,1105,38,60
1,6,112,116,112,2101,2107,2109,10,3000
1,7,115,117,112,2103,2107,2105,9,1800
1,8,112,118,113,2102,2108,2109,10,1009
1,9,116,113,118,2103,2106,2105,5,2000
1,10,115,117,102,2101,2108,2105,8,800
(3)待测试数据
label,gid,category1,category2,category3,brand1,brand2,brand3,day30_buy_cnts,day30_buy_amt
0.0,1,105.0,106.0,102.0,1101.0,1108.0,1109.0,5.0,320.0
0,2,105,116,102,102,2107,1105,35,180
1,3,112,116,112,2101,1108,2109,10,3000
1,4,115,117,106,2103,2107,2105,9,1800

三、算法选择·朴素贝叶斯

因为我们选择的品牌、品类不是具体的数值,代表的而是分类,所以不能用逻辑回归,而选择用朴素贝叶斯算法。

问题:

但是使用朴素贝叶斯算法,特征值要都是很明确的,不是随机变化性的。
但是我们选取的最后两个特征:单数和总金额,是会产生很多很多可能性的值,在同类中是变化不明确的,特征值是很多的。那该怎么办呢?

处理:

将最后面的两个特征值的区间化(离散化),把连续变化的特征值, 转成只有有限的若干几种取值。


四、代码详解

  • 使用了朴素贝叶斯算法和向量机,做了两者的比较。
(1)工具类
import org.apache.spark.ml.linalg.Vectors
import scala.collection.mutable

object VecUtil {
  /**
    * 将一个double数组,转为vector
    */
  val arr2Vec = (arr:mutable.WrappedArray[Double])=> Vectors.dense(arr.toArray)
  
  }
(2)主代码
package cn.doitedu.ml.gender

import cn.doitedu.commons.util.SparkUtil
import cn.doitedu.ml.util.VecUtil.arr2Vec
import org.apache.log4j.{Level, Logger}
import org.apache.spark.ml.classification.NaiveBayes
import org.apache.spark.mllib.classification.SVMWithSGD
import org.apache.spark.mllib.linalg
import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.mllib.regression.LabeledPoint
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.Row

object GenderPredict {


  def main(args: Array[String]): Unit = {
    Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
    val spark = SparkUtil.getSparkSession(this.getClass.getSimpleName)


    // 加载样本数据
    val sample = spark.read.option("header","true").option("inferSchema",true).csv("userprofile/data/gender/sample")
    sample.show(100,false)

    // 特征处理
    // 特征字段:category1,category2,category3,brand1,brand2,brand3,day30_buy_cnts,day30_buy_amt

    // 将 day30_buy_cnts,day30_buy_amt 进行离散化处理,并封装成向量
    sample.createTempView("sample")
    spark.udf.register("arr2Vec",arr2Vec)
    val features = spark.sql(
      """
        |select
        |label,
        |arr2vec(
        |array(
        |category1,
        |category2,
        |category3,
        |brand1,
        |brand2,
        |brand3,
        |case  when day30_buy_cnts<10 then 0.0
        |      when day30_buy_cnts>=10 and day30_buy_cnts<20 then 1.0
        |      when day30_buy_cnts>=20 and day30_buy_cnts<30 then 2.0
        |      when day30_buy_cnts>=30 and day30_buy_cnts<40 then 3.0
        |      else 4.0
        |end,
        |case  when day30_buy_amt<100 then 0.0
        |      when day30_buy_amt>=100 and day30_buy_amt<200 then 1.0
        |      when day30_buy_amt>=200 and day30_buy_amt<500 then 2.0
        |      when day30_buy_amt>=500 and day30_buy_amt<1000 then 3.0
        |      when day30_buy_amt>=1000 and day30_buy_amt<2000 then 4.0
        |      when day30_buy_amt>=2000 and day30_buy_amt<5000 then 5.0
        |      else 6.0
        |end
        |)
        |) as features
        |from sample
        |
      """.stripMargin)

    features.show(100,false)

    // 构造朴素贝叶斯算法工具
    val bayes = new NaiveBayes()
        .setFeaturesCol("features")
        .setLabelCol("label")
        .setSmoothing(1.0)
    // 训练模型
    val bayes_model = bayes.fit(features)


    // 构造支持向量机分类算法工具(SVM)
    val labledPointFeatures = features.rdd.map({
      case Row(label:Double,features:org.apache.spark.ml.linalg.Vector)
        => {
        // 将ml中的Vector转成mllib中的Vector
        val arr: Array[Double] = features.toArray
        val vec = Vectors.dense(arr)
        LabeledPoint(label,vec)
      }
    })
    // 训练svm模型
    val svm_model = SVMWithSGD.train(labledPointFeatures,20)


    // 加载测试数据
    val test = spark.read.option("header","true").option("inferSchema",true).csv("userprofile/data/gender/test")
    test.show(100,false)
    test.createTempView("test")
    val test_features = spark.sql(
      """
        |select
        |label,
        |arr2vec(
        |array(
        |category1,
        |category2,
        |category3,
        |brand1,
        |brand2,
        |brand3,
        |case  when day30_buy_cnts<10 then 0.0
        |      when day30_buy_cnts>=10 and day30_buy_cnts<20 then 1.0
        |      when day30_buy_cnts>=20 and day30_buy_cnts<30 then 2.0
        |      when day30_buy_cnts>=30 and day30_buy_cnts<40 then 3.0
        |      else 4.0
        |end,
        |case  when day30_buy_amt<100 then 0.0
        |      when day30_buy_amt>=100 and day30_buy_amt<200 then 1.0
        |      when day30_buy_amt>=200 and day30_buy_amt<500 then 2.0
        |      when day30_buy_amt>=500 and day30_buy_amt<1000 then 3.0
        |      when day30_buy_amt>=1000 and day30_buy_amt<2000 then 4.0
        |      when day30_buy_amt>=2000 and day30_buy_amt<5000 then 5.0
        |      else 6.0
        |end
        |)
        |) as features
        |
        |from test
        |
      """.stripMargin)
    // 用朴素贝叶斯模型对测试数据进行性别预测
    val predict1 = bayes_model.transform(test_features)
    predict1.show(100,false)


    // 将测试数据变成mllib的LabeledPoint形式,用svm来预测
    val test_vec: RDD[linalg.Vector] = test_features.rdd.map({
      case Row(label:Double,features:org.apache.spark.ml.linalg.Vector)
      => {
        // 将ml中的Vector转成mllib中的Vector
        val arr: Array[Double] = features.toArray
        val vec = Vectors.dense(arr)
        vec
      }
    })
    val predict2: RDD[Double] = svm_model.predict(test_vec)
    predict2.take(100).foreach(println)
    spark.close()
  }
}

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值