使用 Spark DataFrame 构建统计类特征 (scala版)

有这样一句话:数据和特征决定了机器学习的上限而模型和算法只是逼近这个上限而已。

在利用SparkML进行特征转换前,使用SparkDataFrame可以很方便的进行提炼数据中的统计类特征 。

下面给出一个利用SparkDataFrame进行二分类问题的特征工程的小栗子。


问题描述:

现有一二分类问题,提供了(用户id,行为,行为日期,等级,标签)原始数据。标签列为Label列,请根据原始数据进行特征工程。

原始数据:

val dataDF = List(
  ("id1", "click",1,1,1.0),
	("id1", "view",2,2,1.0),
  ("id2", "buy",3,3,0.0),
	("id2", "click",1,4,0.0),
	("id2", "click",2,5,1.0),
  ("id3", "buy",3,6,1.0),
  ("id3", "view",5,7,1.0),
	("id3", "view",1,8,1.0),
	("id3", "view",5,9,0.0),
	("id3", "view",6,10,0.0),
  ("id5", "view",1,11,1.0),
  ("id5", "click",3,12,.0)).toDF("id", "action","date","grade","label")
//date列表示该行为出现在第几天
dataDF.show()

要构建的特征,以及使用的方法概要:

  1. 各行为(action列)频次特征:使用groupBy/agg/alias 方法近统计,使用pivot将各行为展开。
  2. 各行为转化率(action列)特征:使用withColumn方法新增列。
  3. 最近行为距今时间间隔/行为平均时间 特征:使用withColumn新增列,groupBy/agg聚合/pivot展开/.toDF重命名列。
  4. 使用 join 的 left_outer 方法进行特征合并

下面进行详细介绍:

1. 构建 各"action"频次特征

使用groupBy/agg/alias 方法近统计,使用pivot将各行为展开。

//1.新增取值为1的一列,使用agg(sum)聚合得到各行为频次,使用alias重命名得到列"action_count"
val actionFeaTmpDF = dataDF.withColumn("tmp", lit(1)).groupBy("id","action").agg(sum("tmp").alias("action_count")) 

//2.展开各行为频次列
val actionFeaDF = actionFeaTmpDF.groupBy("id").pivot("action").agg(sum("action_count"))//再展开得到特征

scala> actionFeaTmpDF.show
+---+------+------------+
| id|action|action_count|
+---+------+------------+
|id1| click|           1|
|id5| click|           1|
|id1|  view|           1|
|id2|   buy|           1|
|id3|   buy|           1|
|id2| click|           2|
|id3|  view|           4|
|id5|  view|           1|
+---+------+------------+

scala> actionFeaDF.show
+---+----+-----+----+                                                           
| id| buy|click|view|
+---+----+-----+----+
|id3|   1| null|   4|
|id5|null|    1|   1|
|id1|null|    1|   1|
|id2|   1|    2|null|
+---+----+-----+----+

2. 构建 各"action"行为转化率特征

使用withColumn方法新增列。

var actiontransformDF = actionFeaDF.withColumn("clickbuyratio",col(s"click")/(col(s"buy")))///点击->购买转化率.withColumn("viewbuyratio",col(s"view")/(col(s"buy"))) //曝光购买转化率
scala> actiontransformDF.show
+---+----+-----+----+-------------+
| id| buy|click|view|clickbuyratio|
+---+----+-----+----+-------------+
|id3|   1| null|   4|         null|
|id5|null|    1|   1|         null|
|id1|null|    1|   1|         null|
|id2|   1|    2|null|          2.0|
+---+----+-----+----+-------------+

3. 构建 最近行为距今时间间隔/行为平均时间特征

使用withColumn新增列,groupBy/agg聚合/pivot展开/.toDF重命名列

//假设今天是第9天 
val last_actionFea = dataDF.withColumn("today",lit(9)).withColumn("last_uc_actiondiff",col("today")-col("date")).groupBy("id").pivot("action").agg(min("last_uc_actiondiff")).toDF("id","last_buy_diff","last_click_diff","last_view_diff") 
//1. 行为距今时间间隔(用户最近一次行为距今是几天)
scala> last_actionFea.show
+---+-------------+---------------+--------------+                              
| id|last_buy_diff|last_click_diff|last_view_diff|
+---+-------------+---------------+--------------+
|id3|            6|           null|             3|
|id5|         null|              6|             8|
|id1|         null|              8|             7|
|id2|            6|              7|          null|
+---+-------------+---------------+--------------+
//可见,id3最近一次view行为是第6天,last_view_diff = 3 

//2. 行为平均时间(用户平均多久进行一次该行为?)
val avg_actionFea = dataDF.withColumn("today",lit(9)).withColumn("last_uc_actiondiff",col("today")-col("date")).groupBy("id").pivot("action").agg(max("last_uc_actiondiff")-min("last_uc_actiondiff") /count("last_uc_actiondiff")).toDF("id","avg_buy_diff","avg_click_diff","avg_view_diff")

scala> avg_actionFea.show
+---+------------+--------------+-------------+
| id|avg_buy_diff|avg_click_diff|avg_view_diff|
+---+------------+--------------+-------------+
|id3|         0.0|          null|         7.25|
|id5|        null|           0.0|          0.0|
|id1|        null|           0.0|          0.0|
|id2|         0.0|           4.5|         null|
+---+------------+--------------+-------------+

4. 特征合并

使用 join 的 left_outer 方法进行特征合并

val trainDF = dataDF.join(actionFeaDF,Seq("id"),joinType = "left_outer").join(actiontransformDF,Seq("id"),joinType = "left_outer").join(last_actionFea,Seq("id"),joinType = "left_outer").join(avg_actionFea,Seq("id"),joinType = "left_outer")

这样就得到了我们的训练数据

scala> trainDF.show
+---+------+----+-----+-----+----+-----+----+----+-----+----+-------------+-------------+---------------+--------------+------------+--------------+-------------+
| id|action|date|grade|label| buy|click|view| buy|click|view|clickbuyratio|last_buy_diff|last_click_diff|last_view_diff|avg_buy_diff|avg_click_diff|avg_view_diff|
+---+------+----+-----+-----+----+-----+----+----+-----+----+-------------+-------------+---------------+--------------+------------+--------------+-------------+
|id1| click|   1|    1|  1.0|null|    1|   1|null|    1|   1|         null|         null|              8|             7|        null|           0.0|          0.0|
|id1|  view|   2|    2|  1.0|null|    1|   1|null|    1|   1|         null|         null|              8|             7|        null|           0.0|          0.0|
|id2|   buy|   3|    3|  0.0|   1|    2|null|   1|    2|null|          2.0|            6|              7|          null|         0.0|           4.5|         null|
|id2| click|   1|    4|  0.0|   1|    2|null|   1|    2|null|          2.0|            6|              7|          null|         0.0|           4.5|         null|
|id2| click|   2|    5|  1.0|   1|    2|null|   1|    2|null|          2.0|            6|              7|          null|         0.0|           4.5|         null|
|id3|   buy|   3|    6|  1.0|   1| null|   4|   1| null|   4|         null|            6|           null|             3|         0.0|          null|         7.25|
|id3|  view|   5|    7|  1.0|   1| null|   4|   1| null|   4|         null|            6|           null|             3|         0.0|          null|         7.25|
|id3|  view|   1|    8|  1.0|   1| null|   4|   1| null|   4|         null|            6|           null|             3|         0.0|          null|         7.25|
|id3|  view|   5|    9|  0.0|   1| null|   4|   1| null|   4|         null|            6|           null|             3|         0.0|          null|         7.25|
|id3|  view|   6|   10|  0.0|   1| null|   4|   1| null|   4|         null|            6|           null|             3|         0.0|          null|         7.25|
|id5|  view|   1|   11|  1.0|null|    1|   1|null|    1|   1|         null|         null|              6|             8|        null|           0.0|          0.0|
|id5| click|   3|   12|  0.0|null|    1|   1|null|    1|   1|         null|         null|              6|             8|        null|           0.0|          0.0|
+---+------+----+-----+-----+----+-----+----+----+-----+----+-------------+-------------+---------------+--------------+------------+--------------+-------------+
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值