职业院校大数据技术——数据挖掘1,Kotlin可能带来的一个深坑

36 阅读5分钟

catalogue

前言

由于任务书里的描述不够清晰,本文代码只代表本人理解的需求完成,如有错误,请指出。
在这里插入图片描述

会用到的库和方法

import org.apache.spark.ml.linalg.{Vector,Vectors}
import org.apache.spark.ml.feature.{StandardScaler,OneHotEncoder, StringIndexer, StringIndexerModel, VectorAssembler}
import org.apache.spark.ml.functions.vector\_to\_array

// 使用VectorAssembler将所有特征组合成一个向量
val assembler = new VectorAssembler().setInputCols(numericalCol).setOutputCol("features")
val assembled = assembler.transform(product_info)

// 使用StandardScaler对数值特征进行规范化处理
// assembled对feature字段里面的每个值做.setWithStd(true).setWithMean(true)处理
val scaler = new StandardScaler().setInputCol("features").setOutputCol("scaledFeatures")
  .setWithStd(true)
  .setWithMean(true)
val scaled = scaler.fit(assembled).transform(assembled)

// 非数值类型的数据需要先进行StringIndexer处理后再进行onehot
// 其实就是把类型改为从0开始的键
val indexer: StringIndexerModel = new StringIndexer()
  .setInputCol("color")
  .setOutputCol("index\_color")
  .fit(data)
// 如果输入字段本身就数字类型,那么稀疏向量的个数是最大值+1,
// 因为默认从0开始表示第一个类型
val encoder = new OneHotEncoder()
      .setInputCol("index\_color")
      .setOutputCol("encoded\_color")
      .setDropLast(false)
    encoder.fit(indexData).transform(indexData)

val indexData: DataFrame = indexer.transform(data)
/\*\*
 \* 计算两个列表的杰卡德相似度
 \* @param list1
 \* @param list2
 \* @return 两个列表的杰卡德相似度
 \*/
  def jaccardSimilarity(list1: List[String], list2: List[String]): Double = {
    val set1 = list1.toSet
    val set2 = list2.toSet
    val intersection = set1.intersect(set2).size.toDouble
    val union = set1.union(set2).size.toDouble
    intersection / union
  }


StandardScaler是Spark ML库中的一个特征处理方法,用于对数值型特征进行标准化处理。标准化是一种常见的特征处理方法,它可以将数值型特征缩放到一个标准的范围,使得它们在数值上处于同一数量级,从而避免某些特征由于数值过大而在模型中占据主导地位。

具体来说,StandardScaler会对每个特征进行以下操作:

  1. 计算特征的平均值和标准差。
  2. 将特征的每个值减去平均值,然后除以标准差。
    这样处理后,每个特征的平均值会变为0,标准差会变为1。

例如,假设你有一个DataFrame,它包含两个字段:“length"和"price”。你可以使用VectorAssembler将这两个字段合并为一个向量列"features",然后使用StandardScaler对这个向量列进行标准化处理。假设"length"字段的平均值为a,标准差为b,"price"字段的平均值为c,标准差为d,那么StandardScaler会将"features"列中的每个向量

[

x

,

y

]

转换为

[

(

x

a

)

/

b

,

(

y

c

)

/

d

]

[x, y] 转换为 [(x - a) / b, (y - c) / d]

[x,y]转换为[(x−a)/b,(y−c)/d]。

基础知识

余弦相似度

  • A,B为向量,向量长度必须一致,这表示维度一致。
  • 公式如下:
    余弦相似度计算公式
  • 代码如下:

import org.apache.spark.ml.linalg.{Vector, Vectors}
import org.apache.spark.sql.functions.udf

// 定义一个UDF,用于计算两个向量的余弦相似度
val cosineSimilarity = udf((v1: Vector, v2: Vector) => {
  val dotProduct = v1.dot(v2)
  val norms = Vectors.norm(v1, 2) \* Vectors.norm(v2, 2)
  dotProduct / norms
}:Double)



上面的v1,v2可以看作向量A、B。

这段代码是用来计算两个向量的余弦相似度。余弦相似度是一种常用的相似度度量方法,它可以衡量两个向量之间的夹角的余弦值。如果两个向量的方向完全相同,那么它们的余弦相似度就是1;如果两个向量的方向完全相反,那么它们的余弦相似度就是-1;如果两个向量是正交的,那么它们的余弦相似度就是0。

这段代码中的每一行都有特定的作用:

  1. val dotProduct = Vectors.dot(v1, v2):这行代码计算了向量v1和v2的点积。点积是将两个向量的对应元素相乘,然后将结果相加得到的一个标量。公式中对应分子的计算
  2. val norms = Vectors.norm(v1, 2) * Vectors.norm(v2, 2):这行代码计算了向量v1和v2的范数(也就是长度),然后将结果相乘。范数是将向量的每个元素的平方相加,然后取平方根得到的一个标量。公式中对应分母的计算。
  3. dotProduct / norms:这行代码计算了点积除以范数的结果。这就是余弦相似度。

23年国赛题代码

每个feature函数和它调用的子函数表示每个特征工程的任务代码。

为什么要这么写呢?
因为不可能一步到位,所以分步完成每一个任务。

注意:代码中数据获取皆从mysql中获取,任务书可能要求是hive、hudi。

package Bds

import Bds.DataFrameUtils._  // 这是封装的一个获取各种数据仓库配置项的模块
import org.apache.spark.ml.feature._
import org.apache.spark.ml.linalg._
import org.apache.spark.ml.functions.vector\_to\_array
import org.apache.spark.sql.DataFrame
import org.apache.spark.sql.expressions.Window
import org.apache.spark.sql.functions._

object dataMining {
  val spark = getSparkSession("dataM")
  spark.sparkContext.setLogLevel("OFF")
  // 获取mysql配置项
  val mySQLConfig = getMySQLCf("shtd\_store","sku\_info","bigdata1")

  def order_detail(): DataFrame ={
    mySQLConfig("dbtable") = "order\_info"
    val order = spark.read.format("jdbc").options(mySQLConfig).load()
    mySQLConfig("dbtable") = "order\_detail"
    val detail = spark.read.format("jdbc").options(mySQLConfig).load()
    mySQLConfig("dbtable") = "sku\_info"
    val sku_info = spark.read.format("jdbc").options(mySQLConfig).load()

    // 连接三个表即可剔除不存在现有维表的数据
    order.join(detail,order("id")===detail("order\_id"))
      .select(order("user\_id"),detail("sku\_id"))
      .join(sku_info,col("sku\_id")===col("id"))
      // 不确定种类是指sku\_id还是category3\_id,这里用的是category,如果使用sku\_id注释掉下面这一行即可
      .select(col("user\_id"),col("category3\_id").as("sku\_id"))
      .dropDuplicates("user\_id","sku\_id")
  }

  def feature1(targetUser:Int=6708): Unit ={
    val userBuySku = order_detail()

    val resultDf = userBuySku.filter(col("user\_id")=!=targetUser).join(
      userBuySku.filter(col("user\_id")===targetUser),
      Seq("sku\_id"),"semi"
    ).groupBy("user\_id").count()
    val result = resultDf.orderBy(desc("count")).limit(10)
      .collect().map(_.getLong(0)).mkString(",")
    println("-------------------相同种类前10的id结果展示为:--------------------")
    println(result)

  }


  def skuFeature(): DataFrame ={
    // 读取商品数据
    val sku = spark.read.format("jdbc").options(mySQLConfig).load()



![img](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/55f27956dde34b1280a70a0662b7ccfb~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5py65Zmo5a2m5Lmg5LmL5b-DQUk=:q75.awebp?rk3s=f64ab15b&x-expires=1751909496&x-signature=wFInUjhxda2wOowF1%2FwEWtozfzM%3D)
![img](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/6f67d7dd45584059862354a2b2e88551~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5py65Zmo5a2m5Lmg5LmL5b-DQUk=:q75.awebp?rk3s=f64ab15b&x-expires=1751909496&x-signature=0m6PRBOAszZZ1%2FwT8s7bDhK%2F4Ko%3D)
![img](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/d0a3a56f05d24532b7f02072d4ba79e6~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5py65Zmo5a2m5Lmg5LmL5b-DQUk=:q75.awebp?rk3s=f64ab15b&x-expires=1751909496&x-signature=et8niImFK7QQAAkIDNHPGSm8CTA%3D)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**


**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化资料的朋友,可以戳这里获取](https://gitee.com/vip204888)**