标准差(Standard Deviation):又常称均方差,反映了数字集的离散程度 (对方差做根号)
向量:点积(数量积) 对应坐标乘积和
向量积
一阶范数 表示向量元素之和
二阶范数 表示向量长度
无限大-范数 表示向量元素绝对值的最大值
点积/二阶范数 = 角度
稳定性是指系统受到瞬时扰动,扰动消失后系统回到原来状态的能力,而鲁棒性是指系统受到持续扰动能保持原来状态的能力。
1.公开数据集
2.探索可视化数据
3.处理和转换数据
过滤非规整或由值缺失的数据
填充非规整或缺失的数据(零值,中值,相邻)
对异常值做鲁棒处理(一些极值并不一定是错的,需要做鲁棒回归)
异常值转换,值域覆盖过大,可以使用对数 或者 高斯核 进行转换
4.数据中提取特征
数值特征
类别特征 (可以提取成一个二元特征向量)
文本特征 (词袋 表示法 分词 过滤 替换 向量化<二元特征向量>)
其他特征 (大部分其他特征等最终都会转成数值)
派生特征 (时间->小时->早中晚->二元特征向量)
名义变量 没有顺序关系
有序变量
正则化特征:减去平均数,特征对齐
标准正则转换,平均值 和 标准差(平均方差),代表数值的离散程度
正则化特征向量:
=======================================================================
基于spark的推荐引擎
推荐 + 搜索
1.适用场景:
可选项众多:用户不知道如何搜索
偏个人喜好:
2.分类:
基于内容的过滤:
先提取物品本身的内容和属性
可以将用户标识为:他所接触的物品属性的综合。
协同过滤
根据用户的偏好行为,来划分相似的用户群,基于用户的推荐
根据用户的偏好行为,来划分相似的物品集,基于物品的推荐
(最近邻模型)
3.矩阵分解
因子矩阵
https://blog.csdn.net/xuejianxinokok/article/details/79230190
A 高阶特征权重矩阵 (高阶特征 可雪,乐碧 由 可乐雪碧芬达组成)
B 低阶特征权重矩阵 (低阶特征 可乐雪碧芬达 由 能量,蛋白质等)
矩阵分解的目标,将一个稀疏的特征矩阵(低阶) 转换成 ----> 高阶的特征权重矩阵(便于预测,存储等)
(最小二乘法)
步骤:
1.提取特征:
val ratings = rawRatings.map { case Array(user, movie, rating) =>
Rating(user.toInt, movie.toInt, rating.toDouble) }
生成一个打分的矩阵
2.训练模型:
显示评级数据的训练模型
rank :ALS模型因子的个数,特征矩阵中的隐含特征个数
iterations :对应运行时的迭代次数,ALS每次迭代都能降低误差,但一般10次后就不会有什么变化了
lambda : 正则参数 应该通过用测试数据 进行交叉验证
val model = ALS.train(ratings, 50, 10, 0.01) [MatrixFactorizationModel 因式分解后的矩阵模型 RDD]
model.userFeatures [RDD]
model.productFeatures [RDD]
|------------------------------------------------------------------------
| 隐式反馈数据的训练模型 (待看)
|
| trainImplicit alpha 和 lambda 两个正则化参数,通过测试数据交叉验证。
| alpha参数越搞,训练的模型越认为用户和他所评级的电影之间没有相关性。
3.使用模型
为用户推荐物品:(预测)
计算用户对物品的预计评级,预计得分可视作相应用户因子向量和物品因子向量的点积(数量积)。
val predictedRating = model.predict(789, 123) 用户对某个产品的预期得分 Double
val topKRecs = model.recommendProducts(789, 10) 用户对所有产品前十的推荐(根据预期得分) Array[Rating]
topKRecs.map(rating => (titles(rating.product),rating.rating)).foreach(println) 转成电影名
val moviesForUser = ratings.keyBy(_.user).lookup(789) ratings就是Rating(user movie rating)这个结构的数据
moviesForUser.sortBy(-_.rating).take(10).map(rating => (titles(rating.product), rating.rating)).foreach(println)
找到某个物品相似的其他物品 (分类)
import org.jblas.DoubleMatrix 线性代数库
val aMatrix = new DoubleMatrix(Array(1.0, 2.0, 3.0))
两个向量的点积与各向量范数(或长度 二阶范数)的乘积的商
def cosineSimilarity(vec1: DoubleMatrix, vec2: DoubleMatrix): Double = {
vec1.dot(vec2) / (vec1.norm2() * vec2.norm2())
}
val itemId = 567
val itemFactor = model.productFeatures.lookup(itemId).head
val itemVector = new DoubleMatrix(itemFactor) //评估的product
val sims = model.productFeatures.map{ case (id, factor) =>
val factorVector = new DoubleMatrix(factor)
val sim = cosineSimilarity(factorVector, itemVector)
(id, sim)
}
val sortedSims = sims.top(K)(Ordering.by[(Int, Double), Double] { case
(id, similarity) => similarity })
使用余弦函数判断相似度
=============================================================================
高级文本处理技术
词袋模型(词向量空间模型) 和 TF-IDF模型
|--------------------------------------------
| 可以使用特征哈希垂类高维数据(高维向量)
| 避免维护下标映射
| 降低向量的维度
特征提取:
val path = "/PATH/20news-bydate-train/*"
val rdd = sc.wholeTextFiles(path)
val text = rdd.map { case (file, text) => text } //RDD 所有的文本
println(text.count)
val newsgroups = rdd.map { case (file, text) => file.split("/").takeRight(2).head } //RDD (分类+id) 文档数
val countByGroup = newsgroups.map(n => (n, 1)).reduceByKey(_ + _).collect.sortBy(-_._2).mkString("\n")
println(countByGroup)
//分词过滤逻辑整合
def tokenize(line: String): Seq[String] = {
line.split("""\W+""")
.map(_.toLowerCase)
.filter(token => regex.pattern.matcher(token).matches)
.filterNot(token => stopwords.contains(token))
.filterNot(token => rareTokens.contains(token))
.filter(token => token.size >= 2)
.toSeq
}
val tokens = text.map(doc => tokenize(doc)) //RDD 所有文本对应的分词
println(tokens.first.take(20))
//提取词干
NLTK OpenNLP Lucene
//特征向量
import org.apache.spark.mllib.linalg.{ SparseVector => SV } //SparseVector 稀疏向量
import org.apache.spark.mllib.feature.HashingTF
import org.apache.spark.mllib.feature.IDF
val dim = math.pow(2, 18).toInt
val hashingTF = new HashingTF(dim) //26万的维度向量
val tf = hashingTF.transform(tokens) //hash做下标,同时算词频,得到词频向量 RDD 所有文档的词频向量
tf.cache
//向量值tf
val v = tf.first.asInstanceOf[SV]
println(v.size)
println(v.values.size)
println(v.values.take(10).toSeq)
println(v.indices.take(10).toSeq)
//tf-idf
val idf = new IDF().fit(tf) //根据所有文档的词频向量,算出idf向量
val tfidf = idf.transform(tf) //根据idf向量和词频向量 生成tfidf向量 (每个文档的tfidf向量)
val v2 = tfidf.first.asInstanceOf[SV]
println(v2.values.size)
println(v2.values.take(10).toSeq)
println(v2.indices.take(10).toSeq)
模型训练
文本相似度
val hockeyText = rdd.filter { case (file, text) => file.contains("hockey") }
val hockeyTF = hockeyText.mapValues(doc => hashingTF.transform(tokenize(doc)))
val hockeyTfIdf = idf.transform(hockeyTF.map(_._2)) //算出hokey这个类别 各doc的tfidf向量
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)
文本分类器
朴素贝叶斯:
import org.apache.spark.mllib.regression.LabeledPoint
import org.apache.spark.mllib.classification.NaiveBayes
import org.apache.spark.mllib.evaluation.MulticlassMetrics
val newsgroupsMap = newsgroups.distinct.collect().zipWithIndex.toMap // 话题和下标的映射
val zipped = newsgroups.zip(tfidf)
val train = zipped.map { case (topic, vector) => LabeledPoint(newsgroupsMap(topic), vector) } //话题下标 向量 A分类 特征向量集合 B分类 特征向量集合 ....
train.cache
val model = NaiveBayes.train(train, lambda = 0.1)
验证:
val testPath = "/PATH/20news-bydate-test/*"
val testRDD = sc.wholeTextFiles(testPath)
val testLabels = testRDD.map { case (file, text) =>
val topic = file.split("/").takeRight(2).head
newsgroupsMap(topic)
}
val testTf = testRDD.map { case (file, text) => hashingTF.transform(tokenize(text)) }
val testTfIdf = idf.transform(testTf)
val zippedTest = testLabels.zip(testTfIdf)
val test = zippedTest.map { case (topic, vector) => LabeledPoint(topic, vector) } //测试集 对应的主题 和 特征
val predictionAndLabel = test.map(p => (model.predict(p.features), p.label))
val accuracy = 1.0 * predictionAndLabel.filter (x => x._1 == x._2).count() / test.count()
val metrics = new MulticlassMetrics(predictionAndLabel)
println(accuracy)
println(metrics.weightedFMeasure)