按照上面公式同样可以计算出上面案例中用户之间的相似度。
欧几里得相似度注重目标之间的差异,与目标在空间中的距离直接相关,而余弦相似度是不同目标在空间中的夹角,更加表现在前进趋势上的差异。一般来说,欧几里得相似度用来表现不同目标的绝对差异性,分析目标用户之间的相似度与差异情况。而余弦相似度更多是对目标从方向趋势上区分(分离状态),对特定坐标数字不敏感。

余弦相似度计算实战

下面以余弦相似度为例进行实战演习,模拟不同用户对不同电影之间的评分来计算用户之间的相似性。
首先是数据的输入,这里使用以数组的形式初始化进行模拟。代码如下:
//实例化环境 val conf=new SparkConf() .setAppName("ConsineSimilar") .setMaster("local") val sc=new SparkContext(conf) //初始化用户 val users=sc.parallelize(Array("aaa","bbb","ccc","ddd","eee")) //设置电影名 val films=sc.parallelize(Array("smzdm","yixb","znh","nhsc","fcwr"))
下面是核心代码,使用余弦相似度公式来计算不同用户之间的相似度。
/** * 计算余弦相似性 * @param user1 * @param user2 * @return */ def getCollaborateSource(user1:String,user2:String): Double ={ //获得第一个用户的评分 val user1FilmSource = source.get(user1).get.values.toVector //获得第二个用户的评分 val user2FileSource = source.get(user2).get.values.toVector //对欧几里得公式分子部分进行计算 val member = user1FilmSource.zip(user2FileSource).map(num=>num._1*num._2).reduce(_+_).toDouble //求出分母第一个变量的值 val temp1 = math.sqrt(user1FilmSource.map(num => { math.pow(num, 2) }).reduce(_+_)).toDouble //求出分母第二个变量的值 val temp2 = math.sqrt(user2FileSource.map(num => { math.pow(num,2) }).reduce(_+_)).toDouble //求出分母 val denominator = temp1*temp2 //返回结果 member/denominator }
主函数:
def main(args: Array[String]): Unit = { //初始化分数 getSource() //设定目标对象 val name="bbb" //迭代进行计算 users.foreach(user=>{ println(name + " 相对于 "+user +"的相似性分数为: "+getCollaborateSource(name,user)) }) val frist=users.sortBy((user=>getCollaborateSource(name,user)),false,1).first() println("-----------------------------------------------------------") println("相似度最高的用户为:"+frist) }
最后打印结果如下:
bbb 相对于 aaa的相似性分数为: 0.7089175569585667 bbb 相对于 bbb的相似性分数为: 1.0000000000000002 bbb 相对于 ccc的相似性分数为: 0.8780541105074453 bbb 相对于 ddd的相似性分数为: 0.6865554812287477 bbb 相对于 eee的相似性分数为: 0.6821910402406466 ----------------------------------------------------------- 相似度最高的用户为:bbb
如果你想和我们一起学习交流,共同进步,欢迎加群: