这篇文章参考《Spark快速大数据分析》,归纳spark技术核心的rdd及MLlib以及其中几个重要库的使用。
初始化操作
spark shell: bin/pyspark
每个spark应用都由一个驱动器程序(driver
program)来发起集群上的各种并行操作,驱动器程序包含应用的main函数,并且定义了集群上的分布式数据集,还对这些分布式数据集应用了相关操作,驱动器程序通过一个sparkcontext对象来访问spark(sc),这个对象代表对计算集群的一个连接。可以用它来创建rdd.
sc.textFile(“file-name”) #创建一个代表文件的rdd sc.parallelize([,,])#把一个已有的集合传递给spark bin/spark-submit python-file.py #初始化sparkContext: from pyspark import SparkConf,SparkContext conf=SparkConf().setMaster(“local”).setAppName(“MYAPP”) SC=SparkContext(conf=conf)
Rdd
rdd有两种操作:转化操作和行动操作,转化操作会由一个rdd生成一个新的rdd,行动操作会对rdd计算出一个结果。spark惰性计算转化操作,只有在第一个行动操作中用到时,才会真正计算。
常见的Rdd转化操作
- map():接收一个函数,把这个函数用于rdd的每个元素,将函数的返回结果作为结果rdd中对应元素的值。lambda表达式
- filter():接收一个函数,并将rdd中满足该函数的元素放入新的rdd中返回。
- flatmap():每个输入元素生成多个输出元素,一个简单应用是把输入的字符串切分为单词。
- distinct():生成一个只包含不同元素的新rdd。开销很大,因为它需要将所有数据通过网络进行混洗(shuffle).
- union(other):返回一个包含两个rdd中所有元素的rdd,会重复
- intersection(other):返回两个rdd中都有的元素。会去重复
- substract(other):只存在第一个rdd中,不存在第二个rdd中的,会suffle
- cartesian(other):计算笛卡尔集,返回所有可能的(a,b)对,用途:用户对各种产品的预期兴趣度,自身做笛卡尔积,用于求用户相似度的应用中。-开销大
- sample(with replacement,fraction,[seed]),采样rdd以及是否替换
常见的rdd行动操作
- collect():返回rdd中所有的元素
- count():rdd中元素
- countByvalue():各元素在rdd中出现的次数
- take(num):从rdd中返回num个元素
- top(num):返回最前面的num个元素
- takeOrderd(num)(ordering-func):从rdd中按照提供的顺序返回最前面的num个元素
- ruduce(func): 并行整合rdd中的所有数据
- fold(zero)(func):与reduce一样,但是需要提供初始值
- aggregate(zerovalue(seqop,combop))和reduce相似,但是通常返回不同类型的函数
- foreach(func):对rdd中每个元素使用给定的函数
键值对操作 pair Rdd
提供了并行操作各个键或跨节点重新进行数据分组的操作接口。
reduceByKey()可以分别规约每个键对应的数据
join()把两个rdd中键相同的元素组合在一起
创建pair rdd
提供了并行操作各个键或跨节点重新进行数据分组的操作接口。
reduceByKey()可以分别规约每个键对应的数据
join()把两个rdd中键相同的元素组合在一起
创建pair rdd
把普通的rdd转换成pair rdd,map操作传递的函数需要返回键值对
pairs=lines.map(lambda x: (x.split(“”)[0],x))
转化操作:
reduceByKey() 合并具有相同键的值
groupBykey() 对具有相同键的值进行分组
combineByKey(createCombiner,mergevalue, merge combiners,partitioner):使用不同的返回类型合并具有相同键的值
mapValues(func)对每个value应用函数,不改变键值
flatMapValues(func)对每个value应用一个返回迭代器的函数,然后对返回的每个元素都生成一个对应原键的键值对记录,通常用于符号化
keys() 返回一个仅包含键的rdd
values() 返回一个仅包含值得rdd
sortByKet() 返回一个根据键排序的rdd
针对两个pair rdd的转化操作 p43
subtractByKey(other) 删掉rdd中键与other rdd中的键相同的元素
MLlib
mllib只包含能够在集群上运行良好的并行算法。
预先安装gfortran线性代数运行库
数据类型
位于org.apache.spark.mllib包内:
vector:通过mllib.linalg.vectors类创建出来
from bumpy import array from pyspark.mllib.linalg import vectors
创建稠密向量
densevec1=array(1.0,2.0.3.0])#直接传numpy数组 densevec2=Verctors.dense([1.0,2.0,3.0])
创建稀疏向量,该方法只接收向量的维度以及非零位置和值
这些位置可以用一个dictionary来传递,或使用两个分别表示位置和值的list
sparsevec1=Vectors.sparse(4,{0:1.0,2:2.0}) sparsevec2=Vectors.sparse(4,[0,2],[1.0,2.0])
LabledPoint:在分类和回归这样的监督式学习中,表示带标签的数据点,包含一个特征向量和一个标签(由一个浮点数表示),在mllib.regression中
rating:用户对一个产品的评分,在mllib.recommendation中
各类Model类:是训练算法的结果,一般有一个predict()方法,用来对新的数据点或者数据点组成的rdd应用该模型进行预测
特征提取
mllib.feature
tf-idf:
HashingTF:从一个文档中计算出给定大小的词频向量,采用了hash法,要求每个“文档”都使用对象的可迭代序列来表示
#IDF计算逆文档频率 from pyspark.mllib.feature import HashingTF,IDF rdd=sc.wholeTextFiles(“data”).map(lambda(name,text):text.split()) tf=HashingTF() tfvectors=tf.transform(rdd).cache() #计算idf idf=IDF() idfmodel= idf.fit(tfvectors) tfidfvectors=idfmodel.transform(tfvectors)
缩放:归一化,考虑特征向量中各元素的幅值,并且在特征缩放调整为平等对待时表现最好,例如特征平均值为0,标准差为1
方法:创建一个StandardScaler类的对象,对数据集调用fit()函数来获取一个StandardScaleModel(也就是计算每一列得平均值和标准差),然后使用这个模型对象的transform()方法来缩放一个数据集。
正则化:把向量的长度正规化为1 Nomalizer.transform(rdd),一般情况下是L2范式,欧几里得距离。
word2Vec:是一个基于神经网络的文本特征化算法,需要传给他一个用string类的iterable表示的语料库。训练word2vec.fit(rdd)之后,得到一个word2vecModel,它可以用来将每个单词通过transform()转换为一个向量。算法模型的大小等于词库中单词数乘以向量的大小
统计 mllib.stat.Statistics
Statistics.colStats(rdd):计算由向量组成的rdd的统计性综述,保存着向量集合中每列的最小值、最大值、平均值和方差。
Statistics.corr(rdd,method)计算由向量组成的rdd中的列间的相关矩阵,使用皮尔逊相关或者斯皮尔曼相关,method必须是pearson或spearman中的一个
Statistics.corr(rdd1,rdd2,method)计算两个由浮点值组成的RDD的相关矩阵
Statistics.chiSqTest(rdd)计算由LabledPoint对象组成的rdd中每个特征与标签的皮尔逊独立性测试结果,返回一个ChiSqTestResult对象,其中有p-value、测试统计及每个特征的自由度。标签和特征必须是离散的。
线性回归
分类与回归,监督学习,都使用到mllib.regression.LabledPoint类,lable+freature向量
指用特征的线性组合来预测输出值,也支持L1和L2的正则回归,Lasso和ridge回归
mllib.regression.LinearRegressionWithSGD,LassoWithSGD,ridgeRegressionWithSGD.
SGD表示随机梯度下降法
这几个类都有几个可以用来对算法进行调优的参数:
numIterations,要运行的迭代次数,默认100
stepSize,梯度下降的步长
intercept:是否给数据加上一个干扰特征或者偏差特征也就是值始终为1的特征,默认值false
regParam:Lasso和ridge的正则化参数
form pyspark.mllib.regression import LabledPoint from pyspark.mllib.regression import LinearRegressionWithSGD points=#(创建LabledPoint组成的rdd) model= LinearRegressionWithSGD.train(points,iteration=200,intercept=True) print “weight: %s, intercept:%s”%(model.weights,model.intercept)
逻辑回归
是一种二元分类方法,用来寻找一个分割数据的线性分隔平面.可以支持SGD/LBFGS算法
http://blog.sina.com.cn/s/blog_eb3aea990101gflj.html
LogisticRegressionModel可以为每个点求出一个在0,1之间的得分,之后会基于一个阈值返回0和1,默认情况下对于0.5,他会返回1,可以通过setThreshold()改变阈值,也可以通过clearThreshold()去除阈值设置,这样的话predict()就会返回原始得分。
支持向量机
使用线性分割平面的二元分类算法,预期0或者1的标签,通过SVMWithSGD类,我们可以访问这种算法,返回SVMModel
朴素贝叶斯
多元分类算法,使用基于特征的线性函数计算将一个点分到各类中的得分,这种算法通常用于TF-IDF特征的额文本分类,mllib实现了多项朴素贝叶斯算法,需要非负的频次作为输入特征.
mllib.classification.NaiveBayes类来使用朴素贝叶斯算法,支持一个参数lambda_,用来进行平滑化,可以对一个由LabledPoint组成的rdd调用朴素贝叶斯算法,对于C个分类,标签值的范围是0-C-1,返回NaiveBayesModel,可以使用predict()预测对某个点最适合的分类,也可以访问训练好的模型的两个参数:各特征与各分类的可能性矩阵theta(对于C个分类和D个特征的情况,矩阵大小是C*D),以及先验概率的C维向量pi
决策树与随机森林
决策树可以用来分类也可以用来回归,以节点树德形式表示,每个节点基于数据的特征作出一个二元决定,而树德每个叶节点包含一种预测结果,优点:模型本身容易检查,既支持分类的特征,也支持连续的特征。
mllib.tree.DecisionTree类中的静态方法trainClassifier()和trainRegressor来训练决策树,训练方法接收如下参数:
data:由LabledPoint组成的rdd
numClasses:要使用的类别数量
impurity,节点的不纯净度,对于分类可以为gini或entropy,对于回归必须为variance.
maxDepth,树的最大深度(默认值:5)
maxBins:在构建各节点时将数据分到多个箱子中,推荐值32
categoricalFeaturesInfo,一个映射表,用于指定哪些特征是分类的,以及他们各自有多少个分类,例如,如果特征1是标签0或1的二元特征,特征2是一个标签为0,1,2的三元特征,就可以传递{1:2,2:3},如果没有特征是分类的,就传递一个空得映射表
train()方法会返回一个DecisionTreeModel对象,对象的predict()方法对一个新的特征向量预测对应的值,或者预测一个向量rdd,可以使用toDebugString()来输出这棵树
randomForest类可以用来构建一组树的集合,随机森林,randomForest.trainClassifier()和trainRegressor(),接收如下参数:
numTrees 构建树德数量,提高numTrees 可以降低对训练数据过度拟合的可能性。
featureSubsetStrategy 在每个节点上作决定时需要考虑的特征数量,可以是auto,all,sqrt,log2以及one third,越大的值所花费的代价越大。
seed所使用的随机数的种子
随机森林返回一个WeightedEnsembleModel对象,其中包含几个决策树(在WeakHypotheses字段中,权重由WeakHypothesisWeights决定),可以对RDD或者vector调用predict(),toDebugString()可以输出所有树
聚类
mllib.clustering.KMeans
调用train(),接收一个Vector组成的rdd作为参数,返回一个KmeansModel对象,可访问该对象的clusterCenters属性(聚类中心,是一个向量的数组),调用predict(),返回改点聚类最近的聚类中心
参数:
initializationMode 用来初始化聚类中心,可以是k-means|| 或者是random,前者是默认值,一般效果更好,但是代价高
maxIterations 运行的最大迭代次数 默认值是100
runs 算法并发运行的数目
协同过滤与推荐
协调过滤是一种根据用户对各种产品的交互与评分来推荐新产品的推荐系统技术
交替最小二乘 ALS,是协同过滤的常用算法,mllib.recommendation.ALS类中,ALS会为每个用户和产品都设一个特征向量,这样用户向量与产品向量的点积就接近他们的得分。
参数:
rank 使用的特征向量的大小,更大的特征向量会产生更好的模型,但是花销也比较大,默认是10
iterations 要执行迭代次数 默认值10
lambda 正则化参数
alpha 用来在隐式ALS中计算置信度的常量,默认值1.0
numUserBlocks.numProductBlocks
切分用户和产品数据的块的数目,用来控制并行度,传递-1,mllib自动决定要使用ALS,需要一个由mllib.recommendation.Rating对象组成的rdd,其中每个包含一个用户id,一个产品id,一个评分,id需要是一个32位的整形值,如果是大数字或者字符串,需要用哈希值,或者broadcast()一张从产品id到整形值的表。
ALS返回一个MatrixFactorizationModel对象来表示结果,可以调用predict()来对一个由(userid,numproduct)来为用户找到最值得推荐的前numproduct个产品,MatrixFactorizationModel对象很大,为每个用户和产品都存储了一个向量。模型生成的model.userFeatures和model.productFeatures保存在分布式文件系统上
默认情况是显示评分,隐式反馈需要调用ALS.trainImplicit()显示评分时,每个用户对一个产品的评分是一个得分预测出来的也是评分,隐式反馈,每个评分代表用户和给定产品发生交互的置信度,预测出来的也是置信度
降维
主成分分析PCA: 把数据映射到低维空间,让数据在低位空间表示的方差最大化,要计算这种映射,需要构建出正则化的相关矩阵,并使用这个矩阵的奇异向量和奇异值,与最大的一部分奇异值相对应的奇异向量可以用来重建原始数据的主要成分。
mllib.linalg.distributed.RowMatrix类来表示矩阵,然后存储一个由Vector组成的RDD,每行一个
scala的pca
import org.apache.spark.mllib.linalg.Matrix import org.apache.spark.mllib.linalg.distributed.RowMatrix val points: RDD[vector]=// val mat: RowMatrix=new RowMatrix(points) val pc: Matrix=mat.computePrincipalComponents(2) //将点投影到低维空间 val projected=mat.multiply(pc).rows //在投影出得二维数据上训练k-means模型 val model=KMeans.train(projected,10)
奇异值分解
SVD会把一个m*n的矩阵A分解为三个矩阵A~UTVT,U是一个正交矩阵,它的列被称为左奇异向量,T是一个对角线上德值均为非负数并且降序排列的对角矩阵,它的对角线上德值被称为奇异值,V是一个正交矩阵,它的列被称为右奇异向量
对于大型矩阵,通常不需要进行完全分解,只需要分解出靠前的奇异值和与之对应的奇异向量即可,这样可以节省存储空间,降噪,并有利于恢复低秩矩阵。如果保留前k个奇异值,那么结果矩阵就会是U:m*k,T:k*k,V:n*k
val svd: SingularValueDecomposition[RowMatrix,matrix]=mat.somputeSVD(20,computeU=true) val U: RowMatrix =svd.U //U是一个分布式RowMatrix val S: vector = svd.s //奇异值,用一个局部稠密向量表示 val V: Matrix=svd.V //V是一个局部稠密矩阵
模型评估
mllib.evaluation包,使用BinaryClassificationMetrics和MulticlassMetrics类,可以从(预测,事实)对组成的RDD上创建一个Metrics对象,然后计算诸如准确率、召回率、接受者操作特性ROC曲线下面积等指标,这些方法运行在一个非训练集上,生成由(预测、事实)对组成的RDD缓存值,如果内存中放不下,可以用persist(Storagelevel.DISK_ONLY)