【大数据分析】Ch.2:监督学习&协作过滤
[*]Supervised Learning[监督学习]
[*]
[*]Regression
[*]Classification
[*]Generalization, Overfitting, and Underfitting[泛化、过拟合和欠拟合]
[*]Gradient Descent Algorithm[梯度下降算法]
[*]Algorithm (Collaborating Filtering, Alternating Least Squares)
[*]
[*]Implicit feedback[隐式反馈]
[*]Alternating Least Squares[交替最小二乘]
[*]习题
Supervised Learning[监督学习] 即已知数据以及其对应的输出)去训练得到一个最优模型(这个模型属于某个函数的集合,最优则表示在某个评价准则下是最佳的),再利用这个模型将所有的输入映射为相应的输出,对输出进行简单的判断从而实现分类的目的,也就具有了对未知数据进行分类的能力。
Regression
回归:用于预测一个值,预测的结果往往是连续的。预测与实际结果一般会有偏差,偏差越小,我们认为这个回归分析越好。回归是对真实值的一种逼近预测。
图中的每一点x对应某地区的房子大小与价格的关系,房价与房子大小虽然是正相关,但是由于影响房价的因素还有很多(采光、近郊、学区房等),导致单一变量下的结果往往不理想。我们将这些数据作为“输入”,换句话说,就是我们给算法提供了一套“标准答案”。之后,我们希望算法去学习标准输入和标准答案之间的联系,以尝试对于我们其他的输入给我们提供更为标准的答案。
将上图抽象成一个更简单的模型:A到达B且尽可能遍历更多的节点。首先要明确,A到B的路径不止一条,根据机器学习提供的算法不同,计算机产生的初始分析实例也不同。为了便于理解我们这里用AB点的连线表示。对于A-B间的直线,我们可以用y=ax+b表示,而曲线可能就是高次函数。这里我们不讨论他们最短的距离,讨论的是哪条路径能够经过更多的点,或与图中节点间的差值最小,并尝试基于此模型下是否能够创建一个新的模型来超越我们提供给它的几种方法。图中的节点就是我们给定的数据和其对应的标准答案(对应到坐标轴上),而路径就是我们绘出的函数图像,可能是直线也可能是曲线,对于直线而言,我们就是根据给定输入(节点)去推演并找出合适的a和b,a与b会切实影响点与直线间的距离,就是影响着对应的预测结果。
Classification
分类问题是用于将事物打上一个标签,通常结果为离散值。例如判断一幅图片上的动物是一只猫还是一只狗,分类通常是建立在回归之上。分类的结果没有逼近这一概念,只有对和错,是就是,不是就是不是。与回归相似的,给定一组数据与标准答案,然后开始尝试寻找其中的规律,找出一个清晰的界限并为以后的数据进行明确分类。
上图中:肿瘤大小的区分良性与恶心肿瘤。根据数据可以推测出一个大致的区间,大小在多少左右就可能恶心肿瘤或者良性肿瘤。但是这个区间内的数据仍然不好给出清晰的界限。
然后我们增加了一个变量年龄:年龄与肿瘤大小。这样能够将之前一组变量不能清晰区分的区间缩小,从而便于我们更容易的划分出一个分界点。对于这个例子,我们实际上就是需要找到图中所示的斜线 a x 1 + b x 2 + c ax_1+bx_2+c ax1+bx2+c,对我们而言找到参数abc的值就是最重要的。得到的函数与实际实例值之间的差距越小,我们的分类分析结果就越好。
Generalization, Overfitting, and Underfitting[泛化、过拟合和欠拟合]
首先我们应该思考的问题是:根据一组数据绘制出函数图像是否是误差越小越好?
答案并不是肯定的。我们还是根据上面的例子来看。
红线,蓝线已经分析过,我们如果绘制出来一个新的函数,其图像如图中黄线。它完美覆盖了所有的输入点,也就说其与给定数据的差值非常小(甚至没有差距),那么这种情况真的是一种好多学习结果吗?
举个例子,我给你出一份模拟试题,希望你根据模拟试题来总结做题思路,方便你正式考试时拿高分。然后你只做这一份题,做了N遍,导致这份题你可以做100分但是给你换一份题,你却仍然考低分。这种情况被称为过拟合。过拟合是指给的太过贴近于训练数据的特征了,在训练集上表现非常优秀,近乎完美的预测/区分了所有的数据,但是在新的测试集上却表现平平,不具泛化性,拿到新样本后没有办法去准确的判断。
泛化:指针对一类问题的解决能力,类比高三数学试卷,是针对所有包含高三数学范围内的数学试卷的做题能力,而不是仅仅针对给定一份模拟题的做题能力。
拟合:相对于过拟合,是指数据学习结果具有良好的泛化性能。能够针对一类问题得出误差比较小的答案。
欠拟合:与过拟合相反,即便是给定的数据也具有非常大的误差,这一版出现在机械学习的初期阶段。
泛化,过拟合,拟合的关系如图所示。机械学习初期,训练刚刚开始,模型完成度低且得到的结果精度也低,此时处于欠拟合状态。随着训练的增加、模型的精细化,训练结果与精度都会越来越高,对应的泛化性也会越来越高。但是达到某一阙值之后,泛化性降低,特化性增高,对该组数据的处理能力(精度)会持续提高,模型也趋于完善,此时处于过拟合状态。而这一阙值就是拟合状态,我们应当尽可能找到该点来创建一个机械学习的模型,从而创建出一个具有更好普适性的解决模型。
Gradient Descent Algorithm[梯度下降算法]
以上图为例,我们想要实际构造一个能够表达这些特征值的函数,思路如下。
通过训练数据集和一个算法得到一个模型,然后只要输入一个符合该特征的新变量,按照预测能够输出一个近似正确(理想)答案的值就可以。
这里要用到的最小(成本)开销函数如图所示,这个函数的目的是找到实现令该函数达到最小值的 θ 0 和 θ 1 \theta_0和\theta_1 θ0和θ1。
过程:随机将某一点初始定位最低点值为 J ( θ 0 , θ 1 ) J(\theta_0,\theta_1) J(θ0,θ1),然后,按照梯度下降算法,不断更新 J ( θ 0 , θ 1 ) J(\theta_0,\theta_1) J(θ0,θ1)的值,直到 J ( θ 0 , θ 1 ) J(\theta_0,\theta_1) J(θ0,θ1)值不再变化,则认为找到了最小值点,然后求出该点的坐标 ( θ 0 , θ 1 ) (\theta_0,\theta_1) (θ0,θ1)。
这个算法本身类比一下贪婪算法,每一步都找最大负坡度的路径下降,直到走到J函数值不再变化,认为该点已经是最低点。举个例子:下山,想要下山但是不知道具体的方向该怎么走,身为超人的你决定为了造福后世找出一条下山路径。你就朝下降坡度最大的方向走,每走一步都根据新的坡度变化而决定方向,直到你以这种方式走到无法再用这种方式前进,这就是一条路径。(当然会存在可能用这种方法找到的最低点并不是真正的最低点,只是一个山洼类的地形),因此需要多次进行数据处理,找到不同的多种路径,然后确认到多组数据中真正的最小值以及其对应路径才能够让数据整体更加合理。
Anyway,现在找到了最低点。然后怎么求出两个参数呢?也用到了一个公式。
Learning Rate:
学习率:上图中的α。学习率如果太大,就可能出现一步走的太大而错过最低点的情况;学习率太小,则进度会非常缓慢。所以找到一个合适的学习率,对下降曲线微分前进是最效率的,同样找到这个点就是我们要做的事情。
Algorithm (Collaborating Filtering, Alternating Least Squares) 本次实验数据来源于Audioscrobbler,音乐推荐引擎。对于一首音乐,如何评价他呢?因为一首音乐可能100个人听也未必有1人会评价他,而评价的这个人又是基于个人意愿或处于某些客观环境下,导致评价可能不够准确,所以影响音乐标准的评价要素有很多。
Implicit feedback[隐式反馈]
首先我们来介绍一下隐式反馈的概念。隐式反馈的理解我们根据下面一组例子来表达:
[*]用户直接说出自己的要求,喜欢或者不喜欢,归类到计算机上就是“用户直接搜索这附近最好吃的炸鸡店在哪?”。用户用一些潜在的心里表现表达自己的想法就是隐式反馈,比如”用户将附近最好吃的炸鸡店在哪输入搜索引擎后,并没有点击搜索,而是删除掉了这条信息“。我们来解读一下这里人类的行为:用户想吃炸鸡,但是出于某些原因放弃了,但是这说明他是喜欢炸鸡的。
大数据统计时,只统计表数据就会漏掉很多喜欢吃炸鸡的人数,因为他们虽然喜欢但是出于某些原因放弃了,当你需要统计“喜欢吃炸鸡的人数”时数据的精度就会比真实情况低,就会对市场价值做出误算。
隐式反馈的典例:将物品添加到购物车但是没有买(说明用户想买,但是出于一些原因没有买,但是说明了TA喜欢的物品类型,在推送时如果针对其喜好推送,总有他看中买入的,从此就能增加平台的销售额)。
隐式反馈数据集应该越大越好,越大其表现的精度越准确,哪怕该数据集内数据不多。举个例子,同样是将物品放入购物车然后从购物车删除这个动作,我们应该将他解读为想要这东西但是出于某些原因放弃了还是点错了呢?这样单凭这一项数据就很难区分这一点,就无法过滤出有效数据,因此我们应该增加一些协同数据来共同过滤这个选项,比如时间戳。时间戳记录其删除和放入购物车的时间,如果时间戳间隔小说明一定是 放错了,否则则可能是想买。同理再追加其他协同数据集如浏览次数等。
总而言之,隐式反馈相比对用户喜好进行建模更加困难。但是整体上也更加准确。因此我们需要一种算法来找出隐式反馈数据集。
协同过滤“:判定两个用户可能因为年龄相同而拥有相似的品味并不是协同过滤的一个例子;判断两个用户可能都喜欢同一首歌,因为他们播放了许多其他相同的歌曲是协同过滤的正确例子。
基于内容的推荐是大数据以及机器学习的典型应用,你想看哪种类型的书或者电影,如果能够知道你的观看记录一定能得到有效的归纳。
例题:
如图所示,简单分析一下图标中的各项数据,然后再做分析。第一栏里是5个电影,第二栏是4个用户,第三个是电影的要素统计。
用户数据:每部电影后面有一个分数,分数的数值表达该用户对该电影的喜爱程度。
电影特征:表格中分了两类,分别是浪漫和动作两要素。我们拿第一部电影Love at last来说,它的浪漫指数0.9而动作指数0,也就说可以说这部电影很浪漫但是完全没有动作戏,也就说当我们考虑是否推荐这部电影给其他用户时,我们要考虑的结果是用户喜欢浪漫电影,而且有可能不喜欢动作电影。
然后我们对电影特征进行处理,用向量来表示,如上图。其中向量x2和x3分别是电影的浪漫与动作指数,而x1则默认为1。这里设定为1的理由是,当我们想要表达和计算这组特征值时,我们的最终目的是绘出符合用户偏好的函数图像,也就说是一条线。而直线的表达方式是 a x 1 + b x 2 + c = 0 ax_1+bx_2+c=0 ax1+bx2+c=0,将他用向量表示也是一个1*3的矩阵,因此如果我们不给特征向量增加一个数值,无法进行行列运算,而实际构造 a x 1 + b x 2 + c = 0 ax_1+bx_2+c=0 ax1+bx2+c=0远不如矩阵的效率和可实现性高。
计算过程:
[*]如果用户 j j j评价过电影 i i i则 r ( i , j ) = 1 r(i,j)=1 r(i,j)=1,否则为0
[*]如果用户 j j j未评价过电影 i i i则其对电影的评价值为 y ( i , j ) y^{(i,j)} y(i,j)
[*]用户 j j j喜好用 θ j \theta^j θj表示
[*]x i x^i xi表示电影的特征
[*]对于每个用户与电影存在关系: ( θ j ) T ( x i ) : y ( i , j ) (\theta^j)^T(x^i) :y^{(i,j)} (θj)T(xi):y(i,j)。前者是我们预测的对该电影的评价,后者是其本人真正的对该电影的评价
[*]m j m^j mj表示J用户对电影的评价
[*]我们的最终目的是求出 θ j \theta^j θj
理论差值应该越小越好,这个值越小说明与实验数据的差距越小,也就说数据预测越精确,而后面加的泛化控制变量是因为随着数据的精确,越来越偏向过拟合,这个变量用来尽可能保持一个较大的值,从而限制整个值过小
到现在为止,我们有了一套能够较精确计算对应出合理数值的方法。但是,实际上的操作真的只有这些么?
实际上电影特征值并不好获取,图标中 浪漫与动作指数没有那么容易获取。
那么如果这个数据无法获取,那么又改怎么处理呢,如下图:
这次我首先假设,我们知道关于用户的特征值,即:用户知道自己有多喜欢动作电影和浪漫电影。
就能够得到上图的数据,然后我们有对应的 θ \theta θ和某个具体的特征值,我们就可以推算出一个大体的x值。从而有下面的式子
换汤不换药,这次是已知 θ \theta θ求解x。上次是已知x求解 θ \theta θ。
然后我们就发现,在A未知时,可以通过B求出A;而B未知时又可以通过A求出B的互补关系。基于这种关系,我们就可以构造一个协作过滤算法。
在这个过程中,我们随机选定一个x或者 θ \theta θ,我们可以用二者中的一个推出另一个;然后用新推导出的一个再推导出新的另一个,从此可以进行反复更新。
在这种模式下,如果将已知数据用矩阵表达出来。
所以,低秩矩阵分解本质上和协同过滤是相同的算法。
Alternating Least Squares[交替最小二乘]
回到实验问题中来,在这个实验中。有数千万的播放数据,但是某种意义上它又很小,因为数据的分布是稀疏的(大多数数据是0),平均每个用户播放了171位歌手,累计1600万首歌曲。
所以为了处理系数矩阵:
使用矩阵分解在????行和????列:用户????播放了歌手????的歌,分解只能近似因为????很小,如果k足够大则对计算机计算能力的要求会相应提高。矩阵通常规模很大,并且通常是稀疏矩阵,因为一个用户不可能给所有商品评分。矩阵中缺失的评分,称为missing item.接下来将这个矩阵分解为两个子矩阵,使得两个子矩阵能近似得到原矩阵。
以此法获得的XYT矩阵,他们的乘积也会逼近原矩阵A。然后我们使用交替最小二乘来不断推演他们的值:即Y位置,随机定义一个Y,用Y套公式得出X,当然这个X一定不是正确的的,因此我们要最小化标准误差,我们重复这个过程来用Y计算每个????,再用X计算????,直到收敛于体面的解决模型。
习题
import org.apache.spark.ml.evaluation.RegressionEvaluator
import org.apache.spark.ml.recommendation.ALS
import org.apache.spark.sql.SQLContext
import org.apache.spark.sql.types.{StructType, StructField, StringType, IntegerType, DoubleType, DateType}
val ADS = StructType(Array(StructField("artist id", IntegerType),StructField("artist name", StringType)))
val UADS = StructType(Array(StructField("user id", IntegerType),StructField("artist id", IntegerType),StructField("play count", IntegerType)))
val AAS = StructType(Array(StructField("bad id", IntegerType),StructField("good id", IntegerType)))
val AD=spark.read.option("delimiter","\t").schema(ADS).csv("Data/pdm/artist_data.txt")
val AA=spark.read.option("delimiter","\t").schema(AAS).csv("Data/pdm/artist_alias.txt")
val UAD=spark.read.option("delimiter"," ").schema(UADS).csv("Data/pdm/user_artist_data.txt")
val SUAD=UAD.sample(false,0.1)
val Array(train, test) = SUAD.randomSplit(Array(0.8, 0.2))
train.count()
test.count()
val als=new ALS().setMaxIter(10).setRegParam(0.001).setUserCol("user id").setItemCol("artist id").setRatingCol("play count")
val model=als.fit(train)
var prediction=model.transform(test)
prediction.show()
结果:
文档来源:51CTO技术博客https://blog.51cto.com/u_14758357/3050039
页:
[1]