网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
)
/
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。
这段代码中的每一行都有特定的作用:
- val dotProduct = Vectors.dot(v1, v2):这行代码计算了向量v1和v2的点积。点积是将两个向量的对应元素相乘,然后将结果相加得到的一个标量。公式中对应分子的计算。
- val norms = Vectors.norm(v1, 2) * Vectors.norm(v2, 2):这行代码计算了向量v1和v2的范数(也就是长度),然后将结果相乘。范数是将向量的每个元素的平方相加,然后取平方根得到的一个标量。公式中对应分母的计算。
- 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()
// 对price、weight进行规范化(StandardScaler)
val vectorCol = Array("price","weight")
val assembler = new VectorAssembler().setInputCols(vectorCol).setOutputCol("feature")
val assembled= assembler.transform(sku)
val Scaler = new StandardScaler().setInputCol("feature").setOutputCol("selectFeature")
.setWithMean(true)
.setWithStd(true)
var scaled = Scaler.fit(assembled).transform(assembled)
.withColumn("selectFeature", vector_to_array(col("selectFeature")))
.withColumn("price",col("selectFeature").getItem(0))
.withColumn("weight",col("selectFeature").getItem(1))
// scaled.show()
val categoryColNames:Array[String] = Array("spu\_id","tm\_id","category3\_id")
// 如果类别字段是从1开始的,就使用下面的代码
scaled = categoryColNames.foldLeft(scaled){
(tmpDf,colName)=>{
tmpDf.withColumn(colName,col(colName)-1)
}
}
// 对类别字段做OneHot处理
val encoder = new OneHotEncoder()
.setInputCols(categoryColNames)
.setOutputCols(Array("spu\_idOH","tm\_idOH","category3\_idOH"))
.setDropLast(false)
val encoded = encoder.fit(scaled).transform(scaled)
val result = encoded.drop(categoryColNames: _\*)
.select(
col("id").cast("double"),
col("price"),
col("weight"),
col("spu\_idOH"),
col("tm\_idOH"),
col("category3\_idOH")
)
// 这里id还是整型,国赛要求是double
result.orderBy("id")
}
def feature2(): Unit ={
// 只要第一行,节省计算量
val output = skuFeature().limit(1)
val assembler = new VectorAssembler().setInputCols(Array("id","price","weight","spu\_idOH","tm\_idOH","category3\_idOH"))
.setOutputCol("V")
val assembled = assembler.transform(output)
println("--------------------第一条数据前10列结果展示为:---------------------")
val V: SparseVector = assembled.first().getAs[SparseVector]("V")
// 注意每个类型字段都被额外加了一个元素在下标为0的位置
val result = (0 to 9).map(V(_)).mkString(",")
println(result)
}
/\*\*
\*
\* @param targetUser 目标用户
\* @param top10UserId 通过feature1获得
\*/
def recmd_sys(top10UserId:Array[Int],targetUser:Int=6708): Unit ={
// 筛除需要使用的数据
val UserBuySku = order_detail().filter(col("user\_id").isin(top10UserId) || col("user\_id")===targetUser).cache()
// 剔除目标用户购买过的商品
val userT = UserBuySku.filter(col("user\_id")===targetUser) // user id == targetUser 的数据
val top10UserBuySku= UserBuySku.join(userT,Seq("sku\_id"),"left\_anti") // 返回不存在6708用户买过的商品数据
.dropDuplicates("sku\_id") // 去重商品,避免留下多个用户买过的同一商品
val sku_feature = skuFeature()
// sku\_feature所有字段做为向量
val assembler = new VectorAssembler().setInputCols(sku_feature.columns).setOutputCol("V")
val assembled = assembler.transform(sku_feature)
.select(
col("id").cast("Long"),
col("V")
)
// 跟上各自商品的特征
val joinOn = col("sku\_id")===col("id")
val userTWithV = userT.join(assembled,joinOn)
val top10UserBuySkuWithV = top10UserBuySku.join(assembled,joinOn)
val result = userTWithV.alias("u").crossJoin(top10UserBuySkuWithV.alias("t"))
.withColumn("cosineSimilarity",cosineSimilarity(col("u.V"),col("t.V")))
.groupBy("sku\_id").agg(mean("cosineSimilarity").alias("cosineSimilarity"))
println("------------------------推荐Top5结果如下------------------------")
result.orderBy(col("cosineSimilarity").desc).limit(10)
.collect().map(x=>(x.getLong(0),x.getDouble(1)))
.zipWithIndex
.foreach(x=>{
println(s"相似度top${x.\_2}(商品id:${x.\_1.\_1},平均相似度:${x.\_1.\_2})")
})
}
def main(args: Array[String]): Unit = {
// feature1() // 参数填入任务书指定的用户id
// feature2() // 特征2的结果
// recmd\_sys() // 推荐系统的结果,参数有注释
spark.stop()
}
}
结语
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
4595)]
[外链图片转存中…(img-fW3sXLab-1715644904596)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新