第二章 数据驱动的机器学习系统的组成
1. 机器学习系统组成:
数据收集->数据清洗与转换->模型训练->模型测试->模型部署与整合->模型监控与反馈(同时监控模型的准确度相关指标以及业务指标,模型反馈是指通过用户的行为来对模型的预测进行反馈)
2. 数据预处理
数据过滤(只需要部分原始数据或者满足条件的事件数据)
处理数据丢失、不完整或者有缺陷(填充缺陷数据或者过滤)
处理可能引发异常或者错误的数据(过滤)
合并多个数据源(时间数据与内部数据或者外部数据合并)
数据汇总
3. 数据转换
1) 类别数据编码为数值表示(比如男女,编码成0,1)
2) 文本数据提取有用信息
3) 处理图像或者音频数据
4) 数值数据->类别数据,以减少某个变量可能值数目
5) 对数值特征进行转换
6) 对特征进行正则化、标准化,以保证同一个模型下的不同输入变量的值域相同
7) 特征工程是对现有变量进行组合或者转换生成新特征的过程
4. 交叉验证法
为特定任务选择最优建模方法活着对特定模型最佳参数选择
训练集建立模型,测试集评估模型,即为交叉验证法
5. 批处理或者实时方案选择
在线学习:对新到达的数据立即更新模型,典型的是梯度下降法,可以考虑SparkStreaming
另一种策略是在周期性批处理中进行重新计算,若有新的数据到来则只对更复杂的模型进行近似更新
6. 完整的机器学习流程
1) 收集用户、用户行为与电影标题相关的数据
2) 将这些数据转为特征
3) 模型训练,包括训练-测试与模型选择环节
4) 将已训练的模型部署到在线服务系统,并用于离线处理
5) 通过推荐和目标页面将模型结果反馈到MovieStream站点
6) 将模型结果返回到MovieStream的个性化营销渠道
7) 使用离线模型为MovieStream的各个团队提供工具,以帮助理解用户行为,内容目录特点,业务收入驱动因素等
第三章 Spark上数据的获取、处理与准备
采用数据集http:///files.grouplens.org/datasets/movielens/ml-100k.zip
数据文件:u.user(用户属性文件)、u.item(电影元数据)、u.data(用户对电影的评级)
探索数据非常有必要,有利于发现数据的不规整情况
1.数据清洗:
1) 对非规整数据和缺失数据进行填充(零值,全局期望或者中值或者根据相邻或者类似的数据点来做插值)
2) 过滤掉或者删除掉非规整或有值确实的数据
3) 对异常值做鲁棒处理(鲁棒回归处理异常值或者极值)
4) 对可能的异常值进行转换(对数或者高斯核对)
2.从数据中提取有用特征
特征:可用于模型训练的变量,主要分为:
1) 数值特征:包括实数或者整数
2) 类别特征:可能是状态集合中的一种(1~k编码)
3) 文本特征:文本内容
4) 其他特征:数值(派生特征包括平均值,中位值,方差,和,差,最大值或者最小值以及计数)
时间戳特征处理:将时间戳特征->小时特征(10点)->时间段特征(7~12点)->类别特征(afternoon)
文本特征处理:自然语言处理包括如下:
1) 分词
2) 删除停用词(the,and或者but)
3) 提取词干(复数->单数)
4) 向量化(二元向量用0,1表示是否存在某个词)
基本思路:对所有文本内容进行分词,统计单词总数(去掉停用词以及提取了词干后)n,为每个文本内容创建一个大小为n的向量(初始值全部为0),然后遍历每个文本内容中的单词判断是否在字典中,若在则单词对应的序号位置置为1
当得到特征向量后,需要对数值数据进行正则化:
1) 正则化特征:对数据集中的单个特征进行转换,比如减去平均值或者进行标准正则转换(使得该特征的平均值和标准差分别为0和1)
2) 正则化特征向量:对数据中的某一行的所有特征进行转换,使得转换后的特征向量的长度标准化,即缩放向量的各个特征是的向量的范数为1(常指1阶或者2阶范数)
第四章 构建基于Spark的推荐引擎
1. 推荐适用场景:
1) 可选项众多:从众多可选项中推荐给用户最合适的
2) 偏个人喜好:根据相似喜好用户的信息来帮助他们发现所需物品
2. 典型的推荐算法:
1) 基于内容的过滤
根据物品的内容或者属性(通常为文本内容,有标题、名称、标签以及该物品的其他元数据)分以及某些相似度定义,求出该物品类似的物品
2) 协同过滤
基于用户的协同过滤:找到相似喜好的用户,根据他们的喜好计算出各个物品的综合得分,再根据得分来推荐物品
基于物品的协同过滤:根据现有用户对物品的偏好或者评分,来计算出物品之间的某种相似度,此时相似用户评级相同的那些物品被认为更相近,一旦有了物品的相似度,便可用用户接触过的物品来表示这个用户,然后找出和这些都是已知物品相似的物品,并把它们推荐给用户
基于模型的协同过滤:对用户-物品的偏好建模
Spark推荐模型只包含矩阵分解的实现(ALS,交替最小二乘法)
显式矩阵分解:由用户所提供的自身偏好数据,包括对物品的评级,点赞,喜欢以及对物品的评价,组成用户-物品的稀疏矩阵,对这一稀疏矩阵(U*I)可以分解为(基于用户)U*k与(基于物品)k*I的因子矩阵,从而找到隐含特征,要计算给定用户对某个物品的预计评分,则从用户因子矩阵取相应的行点乘物品因子矩阵的相应的列
除此之外,对于物品之间相似度计算,可以转换为两物品因子向量之间相似度的计算
隐式矩阵分解:隐式反馈数据隐含在用户与物品的交互中,二元数据(用户是否观看了某个电影或者是否购买了某个商品(user,movie))和计数数据(用户观看了某个电影的次数),Mllib将输入的评级数据视为两个矩阵(二元偏好矩阵P和信心权重矩阵C),然而通过率用户因子向量与物品因子向量的点乘得到偏好矩阵(某个用户对某个商品的偏好)
最小二乘法:基本思想是迭代式求解一系列最小二乘回归问题,每次迭代时,固定用户因子矩阵或者物品因子矩阵中的一个,然后用此矩阵以及评级数据来更新另一个矩阵,之后被更新的矩阵被固定住,再更新另外一个矩阵,直到模型收敛。
3. ALS模型的关键参数
1) rank:隐含因子个数,一般越多越好,但是考虑到训练效果与内存开销之间的权衡,合理取之为10到200
2) iterations:迭代次数,10次左右就已经收敛了
3) lambda:正则参数控制模型的过拟合情况,通过用非样本数据进行交叉验证来调整,一般取0.01
4. ALS模型训练
1)训练显式评分数据:
valmodel:MatrixFactorizationModel=ALS.train(ratings,50,10,0.01),其用户因子和物品因子分别保存在(id,factor)对类型的RDD中,分别称为userFeatures和productFeatures
2)训练隐式反馈数据
val model=ALS.trainInplicit()多了个alpha参数指定信心权重所应达到的基准线,该值越高锁训练出来的模型越认为用户与他没评级过的电影之间没有相关性
5. ALS模型预测
valpredictedRating:Double=model.predict(userID,productID); //用户对商品的评分
返回评分最高的前num个物品:
val topKRecs=model.recommendProducts(userId,K)//给用户推荐K个评分最高的商品
物品推荐:相似度是比较两个物品的向量得到的,相似度衡量方法包括皮尔森相关系数,针对实数向量的余弦相关度,针对二元向量的杰卡德相似系数
采用余弦相似度:
def cosineSimilarity(vec1:DoubleMatrix,vec2:DoubleMatrix):Double={
vec1.dot(vec2)/(vec1.norm2() *vec2.norm2())
} //0表示两个向量互不相关,1表示两个向量完全相似,-1表示不仅不相关,而且完全不同
找到10个与某个商品最相似的商品进行推荐:
val itemFactor=model.productFeatures.lookup(itemId).head //找到itemId对应的商品因子向量
val itemVector=newDoubleMatrix(itemFactor)
valsims=model.productFeatures.map{case (id,factor)=>
val factorVector=newDoubleMatrix(factor)
valsim=cosineSimilarity(factorVector,itemVector)
(id,sim)
}
val sortedSims=sims.top(10)(Ordering.by[(Int,Double),Double]){case(id,simlarity) => similarity}
6. ALS模型评估
典型的评估指标:均方差和K值平均准确率
均方差(MSE)直接衡量“用户-商品”评级矩阵的重建误差,常用于显示评级情况,每个商品的真实评分与预测评分的差值平方和再除以商品总数
均方根误差(RMSE):在MSE基础上取平方根
K值平均准确率(APK):每个用户相当于一个查询,每个“前K个”推荐物组成的集合相当于一个查到的文档结果集合,用户度电影的实际评级对应着文档的实际相关性,APK用于衡量模型对用户感兴趣和会去接触的物品的预测能力
全局K值平均准确率(MAPK):计算每个用户的APK累加后再求平均值
Spark Mllib提供了内置的评估函数:
1) MSE
val predictdAndTrue=ratingsAndPredictions.map{case((user,product),(predicted,actual))=>(predicted,actual)}
valregressionMetrics=new RegressionMetrics(predictedAndTrue)
regressionMetrics.meanSquaredError求得MSE
regressionMetrics.rootMeanSquaredError求得RMSE
3) MAP(全局平均准确率)
valpredictedAndTrueForRanking=allRecs.join(userMovies).map{case(userId,(predicted,actualWithIds))=>
valactual=actualWithIds.map(_._2)
(predicted.toArray,actual.toArray)
}
valrankingMetrics=new RankingMetrics(predictedAndTrueForRanking)
rankingMetrics.meanAveragePrecision
第五章 Spark构建分类模型
5.1 分类模型种类
二分类:线性模型,决策树,朴素贝叶斯
多分类:决策树,朴素贝叶斯
1) 线性模型:对样本的预测结果进行建模,y=f(wTX)
y是目标变量,w是权重向量,x为特征向量
给定输入数据的特征向量和目标值,存在一个权重向量能够更好对数据进行拟合,拟合的过程在于最小化模型输出与实际值的误差
逻辑回归:是一个概率模型,对于二分类而言它的输出等价于模型预测某个数据点属于正类的概率估计,其中逻辑回归适用的连接函数为逻辑连接:
1/(1+exp(-wTx))
逻辑回归的损失函数为逻辑损失:
log(1+exp(-ywTx))
正类为1,负类为-1
线性支持向量机(SVM):它可与基于模型对正负的估计预测类别
SVM的连接函数:它是对等连接函数,因此预测的输出表示为
y=wTx
当wTx大于等于0,SVM对数据点标记为1,否则为0
SVM的损失函数为合页损失,定义为:
max(0,1-ywTx)
朴素贝叶斯:通过计算数据点在某个类别的概率进行预测(假定各特征之间条件独立)
属于某个类别的概率表示为若干概率乘积的函数,包括某个特征在给定某个类别条件下出现的概率以及该类别的概率(先验概率),这两种改良可以通过数据的概率估计得到,分类过程就是在给定特征和类别概率情况下选择最可能的类别
除此之外Mllib实现了多项朴素贝叶斯,假设特征分布是多项分布,表示特征的非负频率统计
决策树:决策树可以表达复杂的非线性模式和特征相互关系,不要求数据归一化或者标准化,决策树算法是一种自上而下始于根节点的方法,在每个步骤中通过评估特征分裂的信息增量,最后选出分割数据集最优的特征。信息增益通过计算节点不纯度(即节点标签不相似或不同质的程度)减去分割后的两个子节点不纯度的加权和,有两个评估方法用于选择最好分割:基尼不纯和熵
决策树与贝叶斯不受特征标准化影响
5.2评估模型的性能
决策树需要明确指出预测阈值
评估指标:
1) 准确率:真阳性的数目/真阳性(被正确预测的类别为1的样本)和假阳性(被错误预测为类别1的样本)的总和
2) 召回率(评价结果的完整性):真阳性的数目/真阳性+假阴性(被错误预测为0的样本)
3) ROC曲线:包括分类器的真阳性率(TPR,类似于召回率),假阳性率(FPR,假阳性的样本数/假阳性+真阴性),ROC下的面积(通常称为AUC)表示平均值,1表示性能很好,0.5表示随机性能
5.3模型改进以及参数调优
1)特征标准化
(x-u)/sqrt(variance)
使得每个特征进行标准化,使得均值为0,标准差为1,基本思想是每个特征值减去列的均值,然后除以列的标准差进行缩放
SparkMllib提供了StandardScaler进行归一化
valscaler=new StandardScaler(withMean=true,withStd=true).fit(vectors) //根据特征矩阵创建归一器
//归一化处理
valscaleredData=data.map(lp=>LabelPoint(lp.label,scaler.transform(lp.features)))
2) 类别特征->数值特征(1~k编码)
3) 使用正确的数据格式(1~k编码的类型特征更符合朴素贝叶斯模型)
4) 模型参数调优
常见的两种优化方式SGD(在所有模型默认实现)与L-BFGS(只在逻辑回归中实现)
逻辑回归与SVM由于都是采用梯度下降法(SGD)作为优化函数,因此参数相同:
迭代次数(为了让结果收敛到某个值,即最小化损失函数时的最优权重向量)
步长(用于控制算法在最陡的梯度方向上应该前进多远,较大的步长收敛较快,但容易收敛到局部最优解),步长过大对性能有负面影响
正则化(在损失函数中添加一项关于模型权重向量的函数,使得损失增加,避免训练数据中过拟合,正则化过大又会导致模型欠拟合,性能变差),典型的有SimpleUpdater(无正则化,即逻辑回归的默认配置),Squared2Updater(L2正则化,即SVM模型的默认值),L1Updater(L1正则化,得到一个稀疏的权重向量)
决策树:maxDepth控制决策树的最大深度,深度越大,模型越复杂,单更好的拟合数据,其常用的不纯度度量包括Gini或者Entropy
树的深度与不纯度调优,想通不纯度方式的条件下,数的深度越深,性能越好,但过拟合程度越严重
朴素贝叶斯中:平滑度lambda对性能没有影响
原始数据集分为训练集(训练模型),评估集(用于模型参数调优),测试集(观察模型的性能)
第六章 Spark构建回归模型
6.1 回归模型
回归模型可以处理取任意实数的目标变量,因此可以预测任何目标
Spark Mllib提供了两大回归模型:线性模型和决策树
线性回归模型本质上和线型分类模型一样,唯一的区别在于线型回归使用的损失函数,相关连接函数和决策函数不同,Mllib提供了最小二乘回归模型
决策树通过改变不纯度的度量方法用于回归分析
最小二乘回归模型的损失函数是平方损失:
1/2 * (wTx-y)2
相关的连接函数和决策函数是对等连接函数,回归模型不设置阈值,因此模型的预测函数是y=wTx
线型回归模型的正则化分为L2正则化时的岭回归,L1正则化时的LASSO
决策树回归模型:决策树在用于回归时也要使用对应的不纯度度量方法,这里的不纯度度量方法指方差
6.2 提取特征
线型模型提取特征:特征向量=数值特征(转化为浮点型)+类别特征(1~k编码)
决策树模型提取特征:特征向量=数值特征(直接转化为浮点型)
6.3 训练模型
线型回归模型训练:
LinearRegressionWithSGD.train(data:LabelPoint,iterations:int,step:float,intercept:Boolean)
决策树回归模型训练:
DecisionTree.trainRegressor(data_dt,{})
6.4 评估模型的性能
常见的评估指标:均方误差(MSE),均方根误差(RMSE),平均绝对误差(MAE),R-平方系数(R-squared coefficient)(0~1的一个值,表示拟合数据的好坏)
6.5 改进模型性能
由于线型模型的假设为正态分布,但实际却不是,因此需要对目标变量进行转换(对数变换,取平方根)
6.5 模型参数调优
1) 创建训练集和测试集来评估参数
valdata_with_idx=data.zipWithIndex().map((k,v)=>(v,k))
test=data_with_idx.sample(False,0.2,42)
train=data_with_idx.subtractByKey(test)
2) 参数设置对线型模型的影响
采用RMSLE作为性能指标
参数影响:
迭代次数:随着迭代次数增加,性能先增加后减少
步长:较小的步长和较大的迭代次数可以收敛到较好的解
L2正则化:随着正则参数增加,模型性能先增加后减少
L1正则化:随着正则参数增加,权重向量中0的个数增加
当使用一个较大的正则化参数时,RMSLE的性能急剧下降
截距:截距项的使用(设置为True),可以使得回归模型性能稍微上升
2) 参数设置对决策树回归模型的影响
最大的树深度(maxDepth):树深度越大,越可能出现过拟合现象,因此需要取合适的值
最大的划分数(maxBins):划分数越大,越可能出现过拟合现象,因此需要取合适的值
第七章Spark构建聚类模型
7.1 典型的聚类算法
聚类算法等价于分类算法的无监督模式(即无分类标签),由模型根据输入数据产生输出类别
Mllib库提供了K-means算法:其目标函数是最小化所有类簇的方差之和
迭代过程(随机初始化K个类中心):
1)将每个样本分配到欧拉距离最近的类中心所在簇
2)重新计算每个类簇的类中心
K-均值迭代算法的结束条件是达到最大的迭代次数或者收敛(每个类簇中样本与类中心的平方差之和不再变化)
初始化方法(k-means++是随机初始化的并行版本):随机给每个样本分配一个类簇
K-均值变种(fuzzy K-means模糊K-均值,每个样本属于多个类簇,即每个样本被表示为K维的关系向量)
混合模型(模糊K-均值的扩展),样本的数据由某种概率分布产生,每个样本由K个概率分布的权重表示
层次聚类:每个类簇包含多个子类簇,分为凝聚聚类(1.每个样本作为一个类簇,2.计算与其他类簇的相似度,3.找到最相似的类簇合并产生新的类簇,4.重复过程直到最上层只留下一个类簇)和分裂聚类
7.2 从数据中提取正确的特征
1)提取电影的题材标签包括电影ID,标题,题材
2)训练推荐模型:根据Ratings数据(userId,itemId,rating)
提取ALS模型的隐式用户因子矩阵和商品因子矩阵
3)归一化
检查userVectors和itemVectors的RowMatrix.computeColumnSummaryStatistics()得到每个特征的平均值与标准差,若没有特别的离群点影响聚类结果,因此不需要归一化
7.3 训练聚类模型
Mllib提供了随机和K-means++两种初始化方法,后者为默认初始化,K-means通常不能收敛到全局最优解,经过损失函数的评估,选择性能最好的一次训练作为最终模型
valmovieClusterModelConverged=KMeans.train(movieVectors,numClusters,100) //分别为特征向量,K值,迭代次数
valuserClusterModelConverged=KMeans.train(userVectors,numClusters,100) //分别为特征向量,K值,迭代次数
7.4 对聚类模型进行预测
val movieCluster= movieClusterModelConverged.predict(movieVec)
基本思路:
1) movie元信息(id,title,genres)与movie因子向量(id,factors)进行join操作得到(id,(title,geners),factors)
2) factors->vector valcluser=model.predict(vector) //得到每个电影所属类簇cluster
3) 计算vector与cluster的欧拉距离dist
4) 返回(id,titile,genres,cluster,dist)
5) 对上述数据集根据cluster进行分组,然后按照dist进行排序
6) 每个类簇按照排好的顺序取20部电影打印,然后人工分析
7.5 评估聚类模型的性能
主要分为内部评估(评估过程使用训练集)和外部评估(评估过程使用训练集外数据)
内部评估指标:WCSS、Davies-Bouldin指数、Dunn指数、轮廓系数
外部评估指标:Rand measure、F-measure、雅卡尔系数等用于评估预测值和真实标签的误差
Mllib提供了computeCost方便计算给定RDD的性能
7.6 聚类模型参数调优
随着K(类簇中心数目)的增加,WCSS会出现下降,然后又增加,选择拐点(突然下降速度变平缓),则此时K最优
第八章Spark应用于数据降维
降维:简而言之排出数据中的噪音并保留原始数据的隐含结构
8.1 降维方法种类:
1)PCA(主成分分析法):PCA处理一个数据矩阵,抽取矩阵中k个主向量,每个主向量彼此不相关。计算结果中,第一个主向量表示输入数据的最大变化方向,之后的每个主向量依次代表不考虑之前计算过的所有方向时最大的变化方向,即返回的k个主成分代表了输入数据可能的最大变化,由于主成分向量上有着与原始数据矩阵相同的特征维度,因此需要使用映射来进行一次降维,把原来的数据投影到主向量表示的k维空间
2)SVD(奇异值分解法):只保留前k个奇异值,因此公式如下:
X=Um*k*Ek*k*Vk*n
8.2 提取图片特征
利用java的AWT组件将彩色图->灰度图->特征向量
8.3 正则化
在利用PCA进行降维时,通畅需要对输入数据进行标准化,只需要输入特征减去平均值
8.4 训练降维模型
PCA训练模型的处理数据为RawMatrix,因此需要利用RDD[Vector]再封装一次,指定K值
8.5 使用降维模型
需要通过降维模型,将原始数据投影到主成分表示的k维空间,通过矩阵乘法把图像矩阵和主成分矩阵相乘以实现投影,则得到n个10维向量,降维后的数据可作为新的机器学习模型输入
8.6 SVD与PCA的关系
SVD=U*S*V
V等于PCA计算的K个主成成分向量
U*S等于PCA的投影矩阵
8.7 评价降维模型
合适大的K可以代表原始数据的变化和特征
第九章Spark高级文本处理技术
9.1 TF-IDF(词频权重技术)
TF-IDF(词频-逆文本技术):表示每个单词t在文档d中所占权重
tf-idf(t,d)=tf(t,d)*idf(t)
idf(t)=log(N/d)
参数解释:
tf(t,d):单词t在文档d中出现的频率
idf(t):逆文档频率,即log(总的文档数N/包含单词t的文档数d)
9.2 特征哈希:
对文本或者分类特征进行哈希计算,得到哈希值,在哈希表中当前哈希值对应的值赋予1.0(表示当前特征出现)
缺陷在于:
1) 不能通过下标(1.0)反过来找到对应的特征
2) 可能会造成哈希冲突
*文档分词,包括过滤非单词字符,过滤包含数字单词,移除停用词,移除单字符词,移除低频词
*提取词干:复数->单数,(ing,ed,adj,n)->v,通过NLP方法
*训练TFIDF模型
val dim= math.pow(2, 18).toInt
val hashingTF = new HashingTF(dim)//设置维度的目的是为了避免哈希冲突
val tf = hashingTF.transform(tokens)// 采用特征哈希,每个单词项对应一个哈希值(下标),哈希值对应的value即为词频tf
val idf= new IDF().fit(tf) //训练IDF模型,即逆文档频率
val tfidf = idf.transform(tf) //tfidf是一个稀疏矩阵,其维度是218,每个稀疏向量表示一个文档,包括文档中每个单词项的哈希值以及tfidf(每个文档中的单词所占权重)
*使用TF-IDF模型
1)分析文档的相似度(余弦相似度)
val hockeyText= rdd.filter { case (file, text) => file.contains("hockey") }//找到棒球相关的所有文件
// note that the 'transform' method used below is the one which works on asingle document
// in the form of a Seq[String], rather than the version which works on an RDD ofdocuments
val hockeyTF = hockeyText.mapValues(doc =>hashingTF.transform(tokenize(doc)))//对每个文档进行分词,训练得到tf,(file,tf)
val hockeyTfIdf = idf.transform(hockeyTF.map(_._2))//计算每个文件的tfidf
// compute cosine similarity using Breeze
import breeze.linalg._
val hockey1 = hockeyTfIdf.sample(true, 0.1, 42).first.asInstanceOf[SV]
val breeze1 = new SparseVector(hockey1.indices, hockey1.values, hockey1.size)
val hockey2 = hockeyTfIdf.sample(true, 0.1, 43).first.asInstanceOf[SV]
val breeze2 = new SparseVector(hockey2.indices, hockey2.values, hockey2.size)
//val cosineSim = (breeze1.dot(breeze2))/((norm(breeze1) * norm(breeze2))) //余弦相似度
//println(cosineSim)
3) 文档分类器
valnewsgroupsMap = newsgroups.distinct.collect().zipWithIndex.toMap //新闻类别标记
val zipped = newsgroups.zip(tfidf) //每个文档的主题与tfidf向量关联
val train = zipped.map { case (topic, vector) =>LabeledPoint(newsgroupsMap(topic), vector) }
train.cache
val model = NaiveBayes.train(train, lambda = 0.1)
9.3 Word2Vec模型
Word2Vec把每个单词当作一个向量,最常用的情况是使用单词的向量表示基于单词的含义计算两个单词的相似度,Mllib使用了一种skip-gram模型,考虑了单词出现的上下文来学习词向量表示的模型
*训练Word2Vec模型:
val word2vec = new Word2Vec()
word2vec.setSeed(42) // we do this to generate the same results each time
val word2vecModel = word2vec.fit(tokens) //tokens的每个元素表示一个文档,即词序列
word2vecModel.findSynonyms("hockey",20).foreach(println) //基于词含义计算得到与hockey最相似的前20个单词
第十章Spark Streaming在实时机器学习上的应用
在线学习:不断接受新的训练数据,从而更新模型,可以接近实时响应(每次一个小批量地训练数据)