mllib中的数据类型

本文是对官方文档的翻译整理

1、数据类型

Local vector(本地向量)
Labeled point(带标签数据点)
Local matrix(本地矩阵)
Distrubuted matrix(分布式矩阵):RowMatrix、IndexedRowMatrix、CoordinateMatrix、BlockMatrix
MLlib支持存储在单个机器上的本地的向量和矩阵,以及一个或多个RDD组成的分布式矩阵。本地向量和本地矩阵是用作公共接口的简单数据模型,底层的线性代数运算由Breeze提供。在监督学习中的样本被称为带标签数据点。

1.1、Local vector

本地向量有两种类型,密集型和稀疏型。密集型向量由一系列的双精度数构成,而稀疏型向量由索引和值构成,其中索引是从0开始的整型数(不同语言中向量或数组的索引起始值并不一样,比如在R语言中索引是从1开始)。比如向量(1.0,0.0,3.0),它的密集型表示方法为[1.0,0.0,3.0],而稀疏型表示方法为(3,[0,2],[1.0,3.0]),其中3表示向量的维度是3维,0和2代表非0维度的索引值(稀疏本来的意思是有大量0元素,因而只要知道总共有几个元素,哪些是非0的就可以方便的进行后续的计算,降低存储空间和cpu的消耗),1.0和3.0是对应维度上的幅度值。
MLlib中本地向量的来源:
密集型向量:
Numpy.array():
**python’s list:**比如[1,2,3]
在Spark中自动将Numpy.array()和python里的list()视为密集型向量
稀疏型向量:
**MLlib’s 稀疏向量:**在pyspark.mllib.linalg下的Vectors包内
scipy.sparse.csc_matrix():
在Spark中自动将以上两种数据类型视为稀疏型向量
在Spark中np.array()比list()产生的密集型向量效率要高,而mllib自带的Vectors也要比scipy产生的稀疏向量的计算效率要高。
下面是一个例子:

import numpy as np
import scipy.sparse as sps
from pyspark.mllib.linalg import Vectors
dv1=np.array([1.0,0.0,3.0])#密集型
dv2=[1.0,0.0,3.0]#密集型
sv1=Vectors.sparse(3,[0,2],[1.0,3.0])
sv2=sps.csc_matrix((np.array([1.0,3.0]),np.array([0,2]),shape=(3,1))

1.2、Labeled point

带标签数据点带有类别标签,是本地向量数据类型,即可以是密集型也可以是稀疏型。带标签数据点在Mllib中是用双精度的,即可以用来分类也可以用来回归建模,是有监督学习方法中的数据源。在二分类模型中,标签是0,1;在多类别数据中,标签从0开始递增,如0,1,2……

from pyspark.mllib.linalg import SparseVector
from pyspark.mllib.regression import LabeledPoint
#建立密度型标签数据点
pos=LabeledPoint(1.0,[1.0,0.0,3.0])
neg=LabeledPoint(0.0,[3,[0,2],[1.0,3.0]])

Spark RDD 到 LabelPoint的转换(包含构造临时数据的方法)
或者参考官网由LabeledPoint作为元素构成的rdd如果要查看,不能用top()这类函数,但collect()可以,当然collect()要注意数据量的问题。稀疏数据
在平常的应用中稀疏数据很常用,mllib支持读取一种称为LIBSVM的数据格式,它是LIBSVM和LIBLINEAR的默认格式,它是存储在本地txt文本中的数据格式,标准结构如下:

label index1:value1 index2:value2 ……

排在最前面的是标签数据,后面是具体数据点,每个数据点由索引和值构成,索引是从1开始升序排列的,在mllib中将LIBSVM数据读入之后,索引会自动调整为从0开始。由于有索引,我们只需要存储非0数据(还没实践验证),这大概就是这类数据被称为稀疏数据的原因。可以在网上下到这样的文件,sample_libsvm_data.txt,我截取开头的4行数据如下:

0 128:51 129:159 130:253 131:159 132:50 155:48 156:238 157:252 158:252 159:252 160:237 182:54 183:227 184:253 185:252 186:239 187:233 188:252 189:57 190:6 208:10 209:60 210:224 211:252 212:253 213:252 214:202 215:84 216:252 217:253 218:122 236:163 237:252 238:252 239:252 240:253 241:252 242:252 243:96 244:189 245:253 246:167 263:51 264:238 265:253 266:253 267:190 268:114 269:253 270:228 271:47 272:79 273:255 274:168 290:48 291:238 292:252 293:252 294:179 295:12 296:75 297:121 298:21 301:253 302:243 303:50 317:38 318:165 319:253 320:233 321:208 322:84 329:253 330:252 331:165 344:7 345:178 346:252 347:240 348:71 349:19 350:28 357:253 358:252 359:195 372:57 373:252 374:252 375:63 385:253 386:252 387:195 400:198 401:253 402:190 413:255 414:253 415:196 427:76 428:246 429:252 430:112 441:253 442:252 443:148 455:85 456:252 457:230 458:25 467:7 468:135 469:253 470:186 471:12 483:85 484:252 485:223 494:7 495:131 496:252 497:225 498:71 511:85 512:252 513:145 521:48 522:165 523:252 524:173 539:86 540:253 541:225 548:114 549:238 550:253 551:162 567:85 568:252 569:249 570:146 571:48 572:29 573:85 574:178 575:225 576:253 577:223 578:167 579:56 595:85 596:252 597:252 598:252 599:229 600:215 601:252 602:252 603:252 604:196 605:130 623:28 624:199 625:252 626:252 627:253 628:252 629:252 630:233 631:145 652:25 653:128 654:252 655:253 656:252 657:141 658:37
1 159:124 160:253 161:255 162:63 186:96 187:244 188:251 189:253 190:62 214:127 215:251 216:251 217:253 218:62 241:68 242:236 243:251 244:211 245:31 246:8 268:60 269:228 270:251 271:251 272:94 296:155 297:253 298:253 299:189 323:20 324:253 325:251 326:235 327:66 350:32 351:205 352:253 353:251 354:126 378:104 379:251 380:253 381:184 382:15 405:80 406:240 407:251 408:193 409:23 432:32 433:253 434:253 435:253 436:159 460:151 461:251 462:251 463:251 464:39 487:48 488:221 489:251 490:251 491:172 515:234 516:251 517:251 518:196 519:12 543:253 544:251 545:251 546:89 570:159 571:255 572:253 573:253 574:31 597:48 598:228 599:253 600:247 601:140 602:8 625:64 626:251 627:253 628:220 653:64 654:251 655:253 656:220 681:24 682:193 683:253 684:220
1 125:145 126:255 127:211 128:31 152:32 153:237 154:253 155:252 156:71 180:11 181:175 182:253 183:252 184:71 209:144 210:253 211:252 212:71 236:16 237:191 238:253 239:252 240:71 264:26 265:221 266:253 267:252 268:124 269:31 293:125 294:253 295:252 296:252 297:108 322:253 323:252 324:252 325:108 350:255 351:253 352:253 353:108 378:253 379:252 380:252 381:108 406:253 407:252 408:252 409:108 434:253 435:252 436:252 437:108 462:255 463:253 464:253 465:170 490:253 491:252 492:252 493:252 494:42 518:149 519:252 520:252 521:252 522:144 546:109 547:252 548:252 549:252 550:144 575:218 576:253 577:253 578:255 579:35 603:175 604:252 605:252 606:253 607:35 631:73 632:252 633:252 634:253 635:35 659:31 660:211 661:252 662:253 663:35
1 153:5 154:63 155:197 181:20 182:254 183:230 184:24 209:20 210:254 211:254 212:48 237:20 238:254 239:255 240:48 265:20 266:254 267:254 268:57 293:20 294:254 295:254 296:108 321:16 322:239 323:254 324:143 350:178 351:254 352:143 378:178 379:254 380:143 406:178 407:254 408:162 434:178 435:254 436:240 462:113 463:254 464:240 490:83 491:254 492:245 493:31 518:79 519:254 520:246 521:38 547:214 548:254 549:150 575:144 576:241 577:8 603:144 604:240 605:2 631:144 632:254 633:82 659:230 660:247 661:40 687:168 688:209 689:31

我们可以把数据加载到本地节点的内存中。

from pyspark.mllib.utils import MLUtils
examples=MLUtils.loadLibSVMFile(sc,data/mllib/sample_libsvm_data.txt)

1.3、Local Matrix

本地矩阵也是存储在本地机器上的数据格式。像其他场合的矩阵一样,都有行、列索引和对应的元素值,索引是整型、值是以双精度型。mllib中的矩阵都是按列排列的(比如将二维的矩阵用一维的数组来表示的时候,第一列的元素放在最前面,第二列的元素次之,而不是第一行的元素排在最前面然后第二行)。mllib中的矩阵也有密集型和稀疏型,密集型矩阵的表示由行数、列数、其对应元素值按列依次排列的一个数组组成,稀疏型矩阵采用Compressed Sparse Column(CSC)格式,关于稀疏型数据的表示方法可参考。CSC格式数据是将列索引进行压缩的格式,表示方法:行数、列数、列索引的偏移值和非0元素个数组成的数组、行索引组成的数组、非0元素按列排序组成的数组。其他的都好理解,关键是利用列索引的偏移进行列索引压缩,下面先看一个例子:

from pyspark.mllib.linalg import Matrix, Matrices
#创建一个密集型矩阵[[1.0 4.0),[2.0 5.0],[3.0 6.0]],注意这里是按传统的以行为一组来表示的,以mllib中不同
dm2=Matrices.dense(3, 2, [1, 2, 3, 4, 5, 6])
print(dm2)
#创建一个稀疏型矩阵[[9.0 0.0),[0.0 8.0],[0.0 6.0]]
sm2=Matrices.sparse(3, 2, [0, 1, 3], [0, 1, 2], [9, 8, 6])
print(sm2)

我们可以分析一下上例中稀疏型矩阵的列索引偏移值和非0元素个数[0,1,3],0代表第1列里第1个非0元素在总的非0元素中的相对索引值,1代表第二列元素第1个非0元素在总的非0元素里的相对索引值,1-0=1说明第1列的元素个数为1,这样我们结合行索引就可以把第1列的全部元素定位出来;同样的方法可以确定其他列的元素位置;3表示所有非0元素的个数,减掉倒数第二个偏移量这里是1,恰恰就是最后1列的元素个数,同样结合对应的行索引就可以定位最后一列元素的位置。我们也可以虚拟出一列,把3当成第4列第1个元素的相对索引值,这样就可以把各列元素个数的计算统一起来。总结起来就是,通过各列第1个非0元素在总非0元素中的相对索引值可以确定各列的元素个数,结合行索引就可完全确定所有元素的位置。从这里也可以看到,CSC是一种无损压缩的格式。

1.4 分布式矩阵

分布式矩阵由长整型的行列索引和双精度的值构成,分布式矩阵存储在1个或多个RDD中。到目前为止,在mllib中总共有4种分布式矩阵。需要注意的是,从一种分布式矩阵变换成另一种分布式矩阵可能需要数据的全局移动(在不同节点的机器间移动),因而可能需要极大的内存、cpu和网络通信开销。
分布矩阵所依赖的RDD必须是确定的,因为我们需要缓存矩阵的大小(皮之不存,毛将焉覆)。
4种分布式矩阵分别是RowMatrix、IndexRowMatrix、coordinateMatrix、BlockMatrix。RowMatrix是最基本的分布式矩阵,它是基于行的,就是一行是完整的,完整的行存储在本地节点上,不同节点存储不同的行。而操作这种数据矩阵通常都是对每行都进行同样的操作,也就是说它是矩阵的哪一行并不重要,因而这种数据矩阵的一个特点就是行索引无意义。特征向量的集合就是这样的一类数据矩阵。一般情况下,RowMatrix的列数都不会太大,也就是单独的一行不会太长,这样便于在单节点存储和操作,也便于将某一行的数据传输到驱动器中去。IndexRowMatrix是在RowMatrix的基础上增加了行索引,这样可以定位到矩阵的某一行,否则就无法进行RDD的join操作。CoordinateMatrix是用COO格式来存储的,关于COO参考。BlockMatrix具有元组的结构(Int,Int,Matrix)。
RowMatrix:
RowMatrix可以通过以向量形式存储的RDD来创建。

from pyspark.mllib.linalg.distributed import RowMatrix
#首先创建一个以向量形式存储的RDD.
rows = sc.parallelize([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
#在以向量形式存储的RDD基础上创建RowMatrix
mat = RowMatrix(rows)
#查看矩阵的行数和列数
m = mat.numRows()  # 4
n = mat.numCols()  # 3
#以另一种方式来查看矩阵的行数
rowsRDD = mat.rows
print(m)
print(n)
print(rowsRDD.collect())

输出结果如下:

4
3
[DenseVector([1.0, 2.0, 3.0]), DenseVector([4.0, 5.0, 6.0]), DenseVector([7.0, 8.0, 9.0]), DenseVector([10.0, 11.0, 12.0])]

IndexedRowMatrix
IndexedRowMatrix与RowMatrix很像,只不过有行索引。每一行都由长整型的索引和一个本地向量构成。
IndexedRowMatrix可以由IndexedRows构成的RDD转换成来,IndexedRow由(long,vector)形式的元组组成。IndexRowMatrix转化为RowMatrix.

from pyspark import SparkContext
from pyspark.sql import SparkSession
#import json
sc=SparkContext()
SparkSession(sc)
from pyspark.mllib.linalg.distributed import IndexedRow, IndexedRowMatrix
#先创建一个由IndexedRow构成的RDD.
#可以通过IndexedRow这个类来创建
indexedRows = sc.parallelize([IndexedRow(0, [1, 2, 3]),IndexedRow(1, [4, 5, 6]),IndexedRow(2, [7, 8, 9]),IndexedRow(3, [10, 11, 12])])
#也可以直接用元组来创建
indexedRows = sc.parallelize([(0, [1, 2, 3]), (1, [4, 5, 6]),(2, [7, 8, 9]), (3, [10, 11, 12])])
#由IndexedRows构成的RDD来创建IndexedRowMatrix
mat = IndexedRowMatrix(indexedRows)
#测试一下该矩阵的行、列数
m=mat.numRows()
n=mat.numCols()
rowsRDD=mat.rows
print(m)
print(n)
print(rowsRDD.collect())
#将IndexedRowMatrix类型数据转换成RowMatrix
rowMat=mat.toRowMatrix()

运行结果如下:

4
3
[IndexedRow(0, [1.0,2.0,3.0]), IndexedRow(1, [4.0,5.0,6.0]), IndexedRow(2, [7.0,8.0,9.0]), IndexedRow(3, [10.0,11.0,12.0])]

CoordinateMatrix
CoordinateMatrix由行、列索引和对应值构成,可以通过MatrixEntry来创建,传入MatrixEntry的参数形式为(long,long,float),即矩阵元素的行、列索和值。CoordinateMatrix可以通过函数toRowMatrix()转换为RowMatrix,通过toIndexRowMatrix()转换为IndexRowMatrix,能过toBlockMatrix()转换为BlockMatrix.

from pyspark import SparkContext
from pyspark.sql import SparkSession
#import json
sc=SparkContext()
SparkSession(sc)
from pyspark.mllib.linalg.distributed import CoordinateMatrix, MatrixEntry
# 通过MatrixEntry类来创建一个由MatrixEntry元素构成的RDD
entries = sc.parallelize([MatrixEntry(0, 0, 1.2), MatrixEntry(1, 0, 2.1), MatrixEntry(6, 1, 3.7)])
#也可以通过形如(long, long, float)的元组来创建
entries = sc.parallelize([(0, 0, 1.2), (1, 0, 2.1), (2, 1, 3.7)])
#通过由MatrixEntries构成的RDD来创建CoordinateMatrix
mat = CoordinateMatrix(entries)
#查看矩阵的行列数
m = mat.numRows()# 3
n = mat.numCols()# 2
print(m)
print(n)
#创建CoordinateMatrix后,后续也可以直接获取其非0元素
entriesRDD = mat.entries
print(entriesRDD.collect())
# 转换成RowMatrix.
rowMat = mat.toRowMatrix()
#转换成IndexedRowMatrix.
indexedRowMat = mat.toIndexedRowMatrix()
#转换成BlockMatrix.
blockMat = mat.toBlockMatrix()

运行结果如下:

3
2
[MatrixEntry(0, 0, 1.2), MatrixEntry(1, 0, 2.1), MatrixEntry(2, 1, 3.7)]

BlockMatrix
BlockMatrix,我们可以把这类矩阵叫做由矩阵块组成的矩阵,可以由MatrixBlock来创建,MatrixBlock的形式为((Int,Int),Matrix),式中(Int,Int)代表子矩阵在大矩阵中的位置,而子矩阵Matrix本身本身又是rowPerBlock行,colPerBlock列的矩阵。BlockMatrix支持加法和乘法这样的操作,还可以用validate()函数去验证BlockMatrix的设置是否正确。

from pyspark import SparkContext
from pyspark.sql import SparkSession
#import json
sc=SparkContext()
SparkSession(sc)
from pyspark.mllib.linalg import Matrices
from pyspark.mllib.linalg.distributed import BlockMatrix
#创建由子矩阵组的RDD
#blocks=sc.parallelize([((0,0),Matrices.dense[1.0,2.0,3.0,4.0,5.0,6.0])),((0.1),Matrices.dense[7, 8, 9, 10, 11, 12]))])
blocks=sc.parallelize([((0,0),Matrices.dense(3,2,[1.0,2.0,3.0,4.0,5.0,6.0])),((0,1),Matrices.dense(3,2,[7, 8, 9, 10, 11, 12]))])
mat=BlockMatrix(blocks,3,2)#从这里可以看到每个子矩阵的行列数应该一样,而且传到BlockMatrix中的参数,也就是子矩阵的行列数
m=mat.numRows()
n=mat.numCols()
print(m)
print(n)
blocksRDD=mat.blocks
print(blocksRDD.collect())
#转化为其他矩阵
localMat=mat.toLocalMatrix()
indexedRowMat=mat.toIndexedRowMatrix()
coordinateMat=mat.toCoordinateMatrix()

结果如下:

3
4
[((0, 0), DenseMatrix(3, 2, [1.0, 2.0, 3.0, 4.0, 5.0, 6.0], 0)), ((0, 1), DenseMatrix(3, 2, [7.0, 8.0, 9.0, 10.0, 11.0, 12.0], 0))]

2、Spark 集成算法的数据格式及评估方法

不全不准,先放这里,以后再慢慢加

类别

算法名称

数据格式

评估方法

聚类

Kmeans

RDD(Local Vector)

分类

DecisionTree(决策树)

RDD(LabelPoint)

ACU,F-measure,ROC

分类

RadomForest(随机森林)

RDD(Local Vector)

ACU,F-measure,ROC

分类

LogisticRegression(逻辑回归

RDD(Local Vector)

ACU,F-measure,ROC

分类

NaiveBayes(朴素贝叶斯)

RDD(Local Vector)

ACU,F-measure,ROC

分类

SVM(支持向量机)

RDD(Local Vector)

ACU,F-measure,ROC

回归

LinearRegression线性回归

RDD(Local Vector)

自定义

回归

Lasso

RDD(Local Vector)

自定义

回归

RidgeRegression岭回归

RDD(Local Vector)

自定义

推荐

ALS

RDD[rating]

ml中的数据类型

数据类型

官网:pyspark.ml.linalg module

pyspark.ml.linalg.Vectors

向量又分为:密集型和稀疏型

>>> Vectors.dense([1, 2, 3])
DenseVector([1.0, 2.0, 3.0])
>>> Vectors.dense(1.0, 2.0)
DenseVector([1.0, 2.0])
>>> Vectors.sparse(4, {1: 1.0, 3: 5.5})
SparseVector(4, {1: 1.0, 3: 5.5})
>>> Vectors.sparse(4, [(1, 1.0), (3, 5.5)])
SparseVector(4, {1: 1.0, 3: 5.5})
>>> Vectors.sparse(4, [1, 3], [1.0, 5.5])
SparseVector(4, {1: 1.0, 3: 5.5})

pyspark.ml.linalg.Matrices

也分为密集型和稀疏型
static dense(numRows, numCols, values)
static sparse(numRows, numCols, colPtrs, rowIndices, values)[

DataFrame-based API

官网:

A DataFrame is a Dataset organized into named columns. It is conceptually equivalent to a table in a relational database or a data frame in R/Python, but with richer optimizations under the hood. DataFrames can be constructed from a wide array of sources such as: structured data files, tables in Hive, external databases, or existing RDDs. The DataFrame API is available in Scala, Java, Python, and R. In Scala and Java, a DataFrame is represented by a Dataset of Rows. In the Scala API, DataFrame is simply a type alias of Dataset[Row]. While, in Java API, users need to use Dataset<Row>to represent a DataFrame.

创建DataFrames 的入口SparkSession

from pyspark.sql import SparkSession

spark = SparkSession \
    .builder \
    .appName("Python Spark SQL basic example") \
    .config("spark.some.config.option", "some-value") \
    .getOrCreate()

With a SparkSession, applications can create DataFrames from an existing RDD, from a Hive table, or from Spark data sources.

#spark中创建dataframe的例子
# spark is an existing SparkSession
df = spark.read.json("examples/src/main/resources/people.json")
# Displays the content of the DataFrame to stdout
df.show()
# +----+-------+
# | age|   name|
# +----+-------+
# |null|Michael|
# |  30|   Andy|
# |  19| Justin|
# +----+-------+

libsvm数据格式

首先介绍一下 libSVM的数据格式,libsvm数据格式可以直接保存成txt文件,并利用libsvm接口从txt文件中读取。

Label 1:value 2:value …

Label:是类别的标识,比如上节train.model中提到的1 -1,你可以自己随意定,比如-10,0,15。当然,如果是回归,这是目标值,就要实事求是了。
Value:就是要训练的数据,从分类的角度来说就是特征值,数据之间用空格隔开
比如:

-15 1:0.708 2:1056 3:-0.3333

需要注意的是,如果特征值为0,则这列数据可以不写,因此特征冒号前面的(姑且称做序号)可以不连续。如:

-15 1:0.708 3:-0.3333

表明第2个特征值为0,从编程的角度来说,这样做可以减少内存的使用,并提高做矩阵内积时的运算速度。我们平时在matlab中产生的数据都是没有序号的常规矩阵,所以为了方便最好编一个程序进行转化。

spark提供了方便的工具类来加载这些数据

libsvm格式中,索引是从1开始的,但spark load svm的时候会将它改为从0开始,即将文件中所有的索引ID-1.

Spark Dataset