请参照下面的链接
hadoop 和 spark 集群搭建
useid | age | gender | occupation | zipcode |
---|---|---|---|---|
1 | 24 | M | technician | 85711 |
2 | 53 | F | other | 94043 |
3 | 23 | M | writer | 32067 |
// python code
from pyspark import SparkConf,SparkContext
from pyspark.sql import SparkSession
from pyspark.sql import Row
spark = SparkSession.builder.appName("python spark SQL basic example").getOrCreate()
sc = spark.sparkContext
userrdd = sc.textFile("hdfs://master:9000/u01/bigdata/user_test.txt").map(lambda line: line.split(","))
df = userrdd.map(lambda fields: Row(userid = fields[0],age = int(fields[1]),gender = fields[2],occupation = fields[3],zipcode = fields[4]))
schemauser = spark.createDataFrame(df)
schemauser.createOrReplaceTempView("user")
schemauser.describe("userid","age","gender","occupation","zipcode").show()
// spark-submit
/data/spark/bin/spark-submit --master yarn \
--deploy-mode cluster \
--num-executors 2 \
--executor-memory '1024m' \
--executor-cores 1 \
/data/project/spark/python/load.py
// 注意如果有错误,将错误解决了,还是报同样的错误,那基本上可以肯定是缓存在作怪,需要删除当前目录下 "metastore_db" 这个目录。python 代码还可以直接提交 spark-submit load.py 只是这种方式使用的 spark standalone 集群管理模式
// scala code
package spark.mllib
import org.apache.spark.sql.Row
import org.apache.spark.sql.types._
import scala.collection.mutable
import org.apache.spark.{SparkConf,SparkContext}
object loadData {
def main(args: Array[String]) {
val userSchema: StructType = StructType(mutable.ArraySeq(
StructField("userid",IntegerType,nullable = false),
StructField("age",IntegerType,nullable = false),
StructField("gender",StringType,nullable = false),
StructField("occupation",StringType,nullable = false),
StructField("zipcode",StringType,nullable = false)
))
val conf = new SparkConf().setAppName("load data")
val sc = new SparkContext(conf)
val sqlContext = new org.apache.spark.sql.SQLContext(sc)
val userData = sc.textFile("hdfs://master:9000/u01/bigdata/user_test.txt").map {
lines =>
val line = lines.split(",")
Row(line(0).toInt,line(1)toInt,line(2),line(3),line(4))
}
val userTable = sqlContext.createDataFrame(userData,userSchema)
userTable.registerTempTable("user")
userTable.describe("userid","age","gender","occupation","zipcode").show
sqlContext.sql("SELECT max(userid) as useridMax FROM user").show()
}
}
// spark-submit
/data/spark/bin/spark-submit --master yarn \
--deploy-mode cluster \
--num-executors 2 \
--executor-memory '1024m' \
--executor-cores 1 \
--class spark.mllib.loadData ./target/scala-2.11/mergefile_2.11-2.2.1.jar
关于 getOrCreate() 这个函数的使用方法详情见下面的链接
python builder API 使用简介
userTable.describe(“userid”,”age”,”gender”,”occupation”,”zipcode”).show
这一行代码会输出一个表格
summary | userid | age | gender | occupation | zipcode |
---|---|---|---|---|---|
count | 943 | 943 | 943 943 | 943 | 943 |
mean | 472.0 | 34.05196182396607 | null | null | 50868.78810810811 |
stddev | 272.3649512449549 | 12.19273973305903 | null | null | 30891.373254138158 |
min | 1 | 7 | F | administrator | 00000 |
max | 99 | 73 | M | writer | Y1A6B |
# linux服务器导入python matplotlib.pyplot报错
import matplotlib as mpl
mpl.use('Agg')
# 再执行
import matplotlib.pyplot as plt
# 需要保存图片到指定的目录
plt.savefig("/home/yourname/test.jpg")
# 即使是能够保持图片,但是图片传到Windows平台打开是空白的,画图看来最好还是要在Windows平台上执行
# 完整的代码,在Windows 平台上运行
# coding:utf-8
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv("C:\\Users\\ljb\\Desktop\\catering_sale.csv")
print(df.count())
print(df.describe())
plt.figure()
bp = df.boxplot(return_type="dict")
# fliers 为异常数据标签
x = bp[ 'fliers' ][0].get_xdata()
y = bp[ 'fliers'][0].get_ydata()
y.sort()
print("x: ",x)
print("y: ",y)
# 用 annotate 添加注释
for i in range(len(x)):
plt.annotate(y[i],xy=(x[i],y[i]),xytext=(x[i] + 0.1 - 0.8/(y[i] - y[i-1]),y[i]))
plt.show()
/*
sale_date 200
sale_amt 198 从这里可以看出有2个空白的值
dtype: int64
sale_amt
count 198.000000
mean 2765.545152
std 709.557639
min 22.000000
25% 2452.725000
50% 2655.850000
75% 3023.500000
max 9106.440000
x: [ 1. 1. 1. 1. 1. 1.]
y: [ 22. 865. 1060. 4065.2 6607.4 9106.44]
*/
从上图可以看出有 6 个可能的异常值都在图上表现出来,但是具体是否异常,需要和销售人员确认
特征:用于模型训练的变量。可以看做数据的属性。
1. 如果这些数据是记录人,那特征就是年龄,性别,籍贯,收入等。
2. 如果这些数据记录的是某个商品,那特征就是商品类别,价格,产地,生成日期,销售数量等
特征数据分析,例子
# coding:utf-8
from pyspark.sql import SparkSession
from pyspark.sql import Row
import matplotlib.pyplot as plt
import sys
spark = SparkSession.builder \
.appName("Python Spark SQL basic example") \
.getOrCreate()
sc = spark.sparkContext
userrdd = sc.textFile("C:\\Users\\ljb\\Desktop\\user_test.txt").map(lambda line:line.split(","))
df = userrdd.map(lambda fields: Row(userid = fields[0],age = int(fields[1]),gender = fields[2],
occupation = fields[3],zipcode = fields[4]))
schemauser = spark.createDataFrame(df)
schemauser.createOrReplaceTempView("user")
age = spark.sql("SELECT * FROM user")
ages = age.rdd.map(lambda p:p.age).collect()
# 分析"年龄",这个特征,通过直方图的形式显示出来
plt.hist(ages,bins=10,color="lightblue",normed=True)
plt.show()
#hist 对这个函数做简要的说明
# 先看下源码:
def hist(x, bins=None, range=None, normed=False, weights=None, cumulative=False,
bottom=None, histtype='bar', align='mid', orientation='vertical',
rwidth=None, log=False, color=None, label=None, stacked=False,
hold=None, data=None, **kwargs):
ax = gca()
# Deprecated: allow callers to override the hold state
# by passing hold=True|False
washold = ax._hold
if hold is not None:
ax._hold = hold
from matplotlib.cbook import mplDeprecation
warnings.warn("The 'hold' keyword argument is deprecated since 2.0.",
mplDeprecation)
try:
ret = ax.hist(x, bins=bins, range=range, normed=normed,
weights=weights, cumulative=cumulative, bottom=bottom,
histtype=histtype, align=align, orientation=orientation,
rwidth=rwidth, log=log, color=color, label=label,
stacked=stacked, data=data, **kwargs)
finally:
ax._hold = washold
return ret
/*
返回的值是一个tuple(n.bins,patches) or ([n0, n1, ...], bins, [patches0, patches1,...]) (输入的数据是多重数据)
参数解释:
x: 一个数组,主要对这个数组中的数据画图,可以是多维数组。
bins:总共有几个条状,默认是10
color:表示直方图的颜色
*/
我们还可以进一步分析用户职业分布特征
# coding:utf-8
from pyspark.sql import SparkSession
from pyspark.sql import Row
import matplotlib.pyplot as plt
import sys
import numpy as np
spark = SparkSession.builder \
.appName("Python Spark SQL basic example") \
.getOrCreate()
sc = spark.sparkContext
userrdd = sc.textFile("C:\\Users\\ljb\\Desktop\\user_test.txt").map(lambda line:line.split(","))
df = userrdd.map(lambda fields: Row(userid = fields[0],age = int(fields[1]),gender = fields[2],
occupation = fields[3],zipcode = fields[4]))
schemauser = spark.createDataFrame(df)
schemauser.createOrReplaceTempView("user")
# 查询 occupation(职业),并按其分组,然后统计每个职业出现的次数,最后以职业出现的次数进行排序升序
count_occp = spark.sql("SELECT occupation,count(occupation) as cnt FROM user GROUP BY occupation ORDER BY cnt")
count_occp.show(21) # 显示前21行数据
# 获取职业名称及对应出现的次数,以便画出各职业总数图
# 把运行的结果转换成 RDD
x_axis = count_occp.rdd.map(lambda p:p.occupation).collect()
y_axis = count_occp.rdd.map(lambda p:p.cnt).collect()
pos = np.arange(len(x_axis))
width = 1.0
ax = plt.axes()
# 设置 x 的刻度
ax.set_xticks(pos + (width / 2))
ax.set_xticklabels(x_axis)
plt.bar(pos,y_axis,width,color="orange")
plt.xticks(rotation=30)
fig = plt.gcf()
fig.set_size_inches(16,10)
plt.show()
对比分析的例子
# coding:utf-8
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv("C:\\Users\\ljb\\Desktop\\catering_sale.csv",header=0,index_col='sale_date',parse_dates=True)
df1 = df.fillna(0)
df_ym = df1.resample("M",how="sum")
df2 = df_ym.to_period("M")
df2.plot(kind="bar",rot=30)
plt.show()
# matplotlib 可视化方法
# coding:utf-8
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
# 画图中能够显示中文
plt.rcParams[ 'font.sans-serif' ] = [ 'SimHei' ]
# 防止坐标轴上 "-" 号变成方块
plt.rcParams[ 'axes.unicode_minus' ] = False
# np.linspace(args1,args2,args3) 生成等差数列 args1:起始值,从什么数开始,args2:结束值,args3:生成多个数
x = np.linspace(0,10,100)
y = np.sin(x)
y1 = np.cos(x)
# 画布的长度是10,宽度是6
plt.figure(figsize=(10,6))
# label 标签在图上显示两个 $$ 括起来的部分:sin(x),线的颜色是红色,线的宽度是2
plt.plot(x,y,label="$sin(x)$",color="red",linewidth=2)
# "b--" 表示蓝色虚线
plt.plot(x,y1,"b--",label="$cos(x^2)$")
# 设置 X 轴标签
plt.xlabel(u"X 值")
# 设置 Y 轴标签
plt.ylabel(u"Y 值")
# 设置图像的标题
plt.title(u"三角函数图像")
# y 轴最大值:1.2和最小值:-1.2,这个没有多大意义,三角函数取值范围 -1 <= y <= 1
plt.ylim(-1.2,1.2)
# 显示图例,就是左上角会有红色线条表示 sin(x),蓝色虚线表示 cos(x^2)
plt.legend()
# 将图片保存至当前目录下
plt.savefig("fig01.jpg")
# 显示图片
plt.show()
# plot 可视化
# coding:utf-8
from pandas import DataFrame
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,10,100)
df = DataFrame({'sin(x)':np.sin(x),'cos(x)':np.cos(x)},index=x)
df.plot()
plt.show()
# coding:utf-8
import pandas as pd
import lxml
df = pd.read_csv("C:\\Users\\ljb\\Desktop\\catering_sale.csv",header=0)
# 显示缺失的数据
print(df[df.isnull().values == True])
# 使用 0 填补空值
print(df.fillna(0))
# 使用该列的平均值填补空值
print(df["sale_amt"].fillna(df["sale_amt"].count()))
# 使用该列的前一行值填补空值
print(df.fillna(method="pad"))
# 进入 Pyspark,读取数据
df = spark.read.csv("/sparkMLlib/catering_sale.csv",header=True)
# 转换数据类型
df1 = df.select(df['sale_date'],df['sale_amt'].cast("Double"))
# df 数据类型:DataFrame[sale_date: string, sale_amt: string]
# df1 数据类型:DataFrame[sale_date: string, sale_amt: double]
# 将 "sale_amt" 列,值为 22.0 替换成 200.0
df1.replace(22.0,200.0,'sale_amt')
# 去掉数据项前后的空格
# 如果所有的数据项前后都没有空格使用show()是看不出效果的,show() 的前面可能为了排版的需要有很多空格。
# 这个例子中第一行前后是有空格的,这样就很明显
In [3]: from pyspark.sql.functions import *
In [23]: df.select(trim(df.sale_date)).show()
+---------------+
|trim(sale_date)|
+---------------+
| 2015/2/28|
| 2015/2/27|
| 2015/2/26|
| 2015/2/25|
| 2015/2/24|
| 2015/2/23|
| 2015/2/22|
| 2015/2/21|
| 2015/2/20|
| 2015/2/19|
| 2015/2/18|
| 2015/2/16|
| 2015/2/15|
| 2015/2/14|
| 2015/2/13|
| 2015/2/12|
| 2015/2/11|
| 2015/2/10|
| 2015/2/9|
| 2015/2/8|
+---------------+
only showing top 20 rows
In [24]: df.select(df.sale_date).show()
+-------------+
| sale_date|
+-------------+
| 2015/2/28 |
| 2015/2/27|
| 2015/2/26|
| 2015/2/25|
| 2015/2/24|
| 2015/2/23|
| 2015/2/22|
| 2015/2/21|
| 2015/2/20|
| 2015/2/19|
| 2015/2/18|
| 2015/2/16|
| 2015/2/15|
| 2015/2/14|
| 2015/2/13|
| 2015/2/12|
| 2015/2/11|
| 2015/2/10|
| 2015/2/9|
| 2015/2/8|
+-------------+
only showing top 20 rows
# 只保留年份
In [27]: df.select(substring(trim(df.sale_date),1,4).alias('year'),df.sale_amt).show()
+----+--------+
|year|sale_amt|
+----+--------+
|2015| 2618.2|
|2015| 2608.4|
|2015| 2651.9|
|2015| 3442.1|
|2015| 3393.1|
|2015| 3136.6|
|2015| 3744.1|
|2015| 6607.4|
|2015| 2060.3|
|2015| 3614.7|
|2015| 3295.5|
|2015| 2332.1|
|2015| 2699.3|
|2015| null|
|2015| 3036.8|
|2015| 865|
|2015| 3014.3|
|2015| 2742.8|
|2015| 2173.5|
|2015| 3161.8|
+----+--------+
only showing top 20 rows
# substring(str,pos,len) 返回 str 子串,从 pos 位置(包含) 返回 len 长度的子串
数据预处理 | 算法 | 功能简介 |
---|---|---|
特征抽取 | TF-IDF | 统计文档的词频–> 逆向文件评率(TF-IDF) |
特征抽取 | Word2Vec | 将文档转换成向量 |
特征装换 | Tokeniziation | Tockenization 将文本划分为独立的个体 |
特征装换 | StopWordsRemover | 删除所有停用词 |
特征装换 | PCA | 使用 PCA 可以对变量集合进行降维 |
特征装换 | StringIndexer | StringIndexer 将字符串列编码为标签索引列 |
特征装换 | OneHotEncoder | 将标签指标映射为0/1 的向量 |
特征装换 | Normalizer | 规范每个向量以具有单位范数 |
特征装换 | StandardScaler | 标准化每个特征使得其有统一的标准差以及(或者)均值为0,方差为1 |
特征装换 | VectorAssembler | 将给定的多列表组合成一个单一的向量列 |
# 定义特征向量
featuresArray = ['season','yr','mnth','hr','holiday','weekday','workingda','weathersit','temp','atemp','hum','windspeed']
# 把各特征组合成特征向量 features
assembler = VectorAssembler(inputCols=featuresArray,outputCol='features')
# 选择贡献度较大的前 5 个特征
selectorfeature = ChisSqSelector(numTopFeatures=5,featuresCol="features",outputCol="selectedFeatures",labelCol='label')
数据归约:删除或减少数据的冗余性(降维就是数据归约其中的一种技术)、精简数据集等,使得归约后数据比原数据小,甚至小很多,但仍然接近于保持原数据的完整性,且结果与归约前后结果相同或几乎相同
数据预处理 | 算法 | 功能简介 |
---|---|---|
特征选择或降维 | VectorSlicer | 得到一个新的原始特征子集的特征向量 |
特征选择或降维 | RFormula | 通过 R 模型公式来将数据中的字段转换为特征值 |
特征选择或降维 | PCA | 使用 PCA 方法可以对变量集合进行降维 |
特征选择或降维 | SVD | |
特征选择或降维 | ChiSqSelector | 根据分类的卡方独立性检验来对特征排序,选取类别标签主要依赖的特征 |
import org.apache.spark.mllib.linalg.Matrix
import org.apache.spark.mllib.linalg.SingularValueDecomposition
import org.apache.spark.mllib.linalg.Vector
import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.mllib.linalg.distributed.RowMatrix
import org.apache.spark.{SparkContext,SparkConf}
object chooseFeatures {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("dataReduce").setMaster("local")
val sc = new SparkContext(conf)
val data = Array(Vectors.dense(1,2,3,4,5,6,7,8,9),
Vectors.dense(5,6,7,8,9,0,8,6,7),
Vectors.dense(9,0,8,7,1,4,3,2,1),
Vectors.dense(6,4,2,1,3,4,2,1,5),
Vectors.dense(4,5,7,1,4,0,2,1,8))
val dataRDD = sc.parallelize(data,2)
val mat : RowMatrix = new RowMatrix(dataRDD)
val svd = mat.computeSVD(3,computeU = true)
val U:RowMatrix = svd.U
val s:Vector = svd.s
val V:Matrix = svd.V
println("U: " ,U)
println("V: " ,V)
println("s: " ,s)
val pc:Matrix = mat.computePrincipalComponents(3)
println("pc: ",pc)
/*
output:
(U: ,org.apache.spark.mllib.linalg.distributed.RowMatrix@972170)
(V: ,-0.33309047675110115 0.6307611082680837 0.10881297540284612
-0.252559026169606 -0.13320654554805747 0.4862541277385016
-0.3913180354223819 0.3985110846022322 0.20656596253983592
-0.33266751598925126 0.25621153877501424 -0.3575093420454635
-0.35120996186827147 -0.24679309180949208 0.16775460006130793
-0.1811460330545444 0.03808707142157401 -0.46853660508460787
-0.35275045425261 -0.19100365291846758 -0.26646095393100677
-0.2938422406906167 -0.30376401501983874 -0.4274842789454556
-0.44105410502598985 -0.4108875465911952 0.2825275707788212 )
(s: ,[30.88197557931219,10.848035248251415,8.201924156089822])
(pc: ,-0.3948204553820511 -0.3255749878678745 0.1057375753926894
0.1967741975874508 0.12066915005125914 0.4698636365472036
-0.09206257474269655 -0.407047128194367 0.3210095555021759
0.12315980051885281 -0.6783914405694824 -0.10049065563002131
0.43871546256175087 -0.12704705411702932 0.2775911848440697
-0.05209780173017968 0.10583033338605327 -0.6473697692806737
0.422474587406277 -0.27600606797384 -0.13909137208338707
0.46536643478632944 -0.172268807944553 -0.349731653791416
0.4376262507870099 0.3469015236606571 0.13076351966313637 )
*/
算法选择的原则:
- 业务需求、数据特征、算法适应性。个人经验等
- 选择几种算法进行比较
- 采用集成学习的方式,复合多种算法也是选项之一。如:先采用聚类方法对数据进行聚类,然后对不同的类别数据进行预测和推荐
- 从简单和熟悉的算法入手,然后不断的完善和优化
spark ML 目前支持的算法
类型 | spark ML 目前支持的算法 |
---|---|
分类 | 逻辑回归,分二项逻辑回归 (Binomial logistic regression) 和多项逻辑回归(Multinomial logistic regression) |
分类 | 决策树分类 (Decision tree classifier) |
分类 | 随机森林分类 (Random forest classifier) |
分类 | 梯度提升决策树分类 (Gradient-boosted tree classifier) |
分类 | 多层感知机分类 (Multilayer perceptron classifier) |
分类 | 一对多分类 (One-vs-Rest classifier) |
分类 | 朴素贝叶斯 (native Bayes) |
回归 | 线性回归 (Linear regression) |
回归 | 广义线性回归 (Generalized liner regression) |
回归 | 决策树回归 (Decision tree regression) |
回归 | 随机森林回归 (Random forest regression) |
回归 | 梯度提升决策树回归 (Gradient-boosted tree regression) |
回归 | 生存回归 (Survival regression) |
回归 | 保序回归 (Isotonic regression) |
推荐 | 协同过滤 (Collaborative filtering) |
聚类 | K-均值(k-means) |
聚类 | 高斯混合模型 (Gaussian Mixture Model) |
聚类 | 主题模型 (latent Dirichlet allocation LDA) |
聚类 | 二分 K 均值 (bisecting k-means) |
package spark.mllib
import org.apache.spark.ml.classification.LogisticRegression
import org.apache.spark.ml.evaluation.{
BinaryClassificationEvaluator,
MulticlassClassificationEvaluator
}
import org.apache.spark.mllib.evaluation.RegressionMetrics
import org.apache.spark.sql.{DataFrame, SparkSession}
object modelAssess {
def main(args: Array[String]): Unit = {
val path = args(0)
// sparkSession 是 Spark SQL 的入口,数据结构是 DataFrame。sc Spark CORE 的入口,数据结构是 RDD,从 Spark 2.0 及以后应尽量使用 DataFrame和DataSet
val spark: SparkSession = SparkSession.builder
.appName("modelAsess")
.master("yarn")
.config("spark.testing.memory", "471859200")
.getOrCreate
// DataFrame.read return DataFrameReader。read 默认支持的格式 parquet,hive 支持的列式存储的文件格式
// format(source: String) 指定源数据的格式
// load(path: String) 加载数据
// data : dataFrame
val data = spark.read.format("libsvm").load(path)
// randomSplit(weight: Array[Double],seed : Long)
// 按照 Double 类型的数组提供的权重值来随机切分数据,seed 可以理解为添加的杂志,增加随机性
val Array(trainingData, testData) =
data.randomSplit(Array(0.7, 0.3), seed = 1234L)
// LogisticRegression 是一个类
//.setThreshold(value : Double) 二分类中,设置阀值,概率大于该值的预测为1,概率小于该值预测为0。默认值:0.5.如果此值过大,那么很多标签都会被预测为0,如果此值过小,很多标签被预测为1
// setMaxIter(value: Int) 设置最大迭代次数,默认是100
// setRegParam(value : Double) 设置正则化参数,默认是 0.0
// setElasticNetParam(value: Double) value = 0.0 使用 L2 正则化,如果value = 1.0 使用 L1 正则化,如果 0.0 < value < 1.0 使用 L1 和 L2 组合的正则化。注意如果是 fit 优化只支持 L2 正则化
// 正则化主要是对权重比较大的特征进行惩罚,避免过度依赖某个特征造成过拟合
val lr = new LogisticRegression()
.setThreshold(0.6)
.setMaxIter(10)
.setRegParam(0.3)
.setElasticNetParam(0.8)
// fit(dataset: DataSet) 使用这个构建模型,输入数据是训练数据
val lrMode = lr.fit(trainingData)
// transform(dataSet: DataSet) : DataFrame 将测试数据输入开始预测
val predictions = lrMode.transform(testData)
predictions.show()
// BinaryClassificationEvaluator 这个类是用来评估二分类算法构建的模型的预测效果,有两个期望输入列:label 标签列和 rawPrediction
// setLabelCol 设置标签列的列名
val evaluator = new BinaryClassificationEvaluator()
.setLabelCol("label")
// evaluate(dataSet: DataSet) : Double 评估模型的预测结果,返回一个度量值
// def isLargerBetter: Boolean true:评估返回的指标应最大化,false:评估返回的值应最小化
val accuracy = evaluator.evaluate(predictions)
// RegressionMertrics 这个类是用来评估回归模型
// new RegressionMetrics(predictionAndObservations: RDD[(Double, Double)])
/*
val dataFrame1 = predictions.select("prediction","label")
dataFrame1 : org.apache.spark.sql.DataFrame
val rdd1 = dataFram1.rdd
rdd1 : org.apache.spark.rdd.RDD[org.apache.spark.sql.Row]
rdd1.rdd.map(x =>(x(0).asInstanceOf[Double],x(1).asInstanceOf[Double]))
return org.apache.spark.rdd.RDD[(Double, Double)]
x :org.apache.spark.sql.Row = [0.0,0.0]
x(0) : Any = 0.0
x(1) : Any = 0.0
x(0).asInstanceOf[Double] 将传入的对象转换成 Double 类型,这里就是将 Any 转换成 Double 类型
*/
val rm2 = new RegressionMetrics(
predictions
.select("prediction", "label")
.rdd
.map(x => (x(0).asInstanceOf[Double], x(1).asInstanceOf[Double])))
/*
def meanSquaredError: Double
def meanAbsoluteError: Double
def rootMeanSquaredError: Double
*/
println("MSE: ", rm2.meanSquaredError)
println("MAE: ", rm2.meanAbsoluteError)
println("RMSE Squared: ", rm2.rootMeanSquaredError)
val binaryClassificationEvaluator = new BinaryClassificationEvaluator()
val multiclassClassificationEvaluator: MulticlassClassificationEvaluator =
new MulticlassClassificationEvaluator()
printlnMetricMulti("f1", predictions, multiclassClassificationEvaluator)
printlnMetricMulti("weightedPrecision",
predictions,
multiclassClassificationEvaluator)
printlnMetricMulti("weightedRecall",
predictions,
multiclassClassificationEvaluator)
printlnMetricMulti("accuracy",
predictions,
multiclassClassificationEvaluator)
printlnMetricbinary("areaUnderROC",
binaryClassificationEvaluator,
predictions)
printlnMetricbinary("areaUnderPR",
binaryClassificationEvaluator,
predictions)
// A error of "value $ is not StringContext member" is reported if you don't add following line
import spark.implicits._
// 计算 TP,分类正确且分类为1的样本数
println(
predictions
.filter($"label" === $"prediction")
.filter($"label" === 1)
.count)
// 计算 TN,分类正确且分类为0的样本数
println(
predictions
.filter($"label" === $"prediction")
.filter($"prediction" === 0)
.count)
// 计算 FN,分类错误且分类为0的样本数
println(
predictions
.filter($"label" !== $"prediction")
.filter($"prediction" === 0)
.count)
// 计算 FP,分类错误且分类为1的样本数
println(
predictions
.filter($"label" !== $"prediction")
.filter($"prediction" === 1)
.count)
/*
准确率: TP(TP+FP) = 17/(17+0) = 1
召回率: TP(TP+FN) = 17/(17+1) = 0.944444
*/
}
// 计算准确率、召回率、正确率、F1
def printlnMetricMulti(
metricsName: String,
predictions: DataFrame,
multiclassClassificationEvaluatdor: MulticlassClassificationEvaluator)
: Unit = {
/*
val multiclassClassificationEvaluatdor = new MulticlassClassificationEvaluator()
setMetricName(metricName : String) : BinaryClassificationEvaluator.this.type 设置评估指标的名字
evaluate(predictions) 这个同上返回一个 Double的值,该指标具体的值
*/
println(
metricsName + " = " + multiclassClassificationEvaluatdor
.setMetricName(metricsName)
.evaluate(predictions))
}
// 计算 AUC(area under ROC ROC 曲线下的区域的面积),area under PR PR曲线的面积
def printlnMetricbinary(
metricsName: String,
binaryClassificationEvaluator: BinaryClassificationEvaluator,
predictions: DataFrame): Unit = {
println(
metricsName + " = " + binaryClassificationEvaluator
.setMetricName(metricsName)
.evaluate(predictions))
}
}
/*
代码集群方式提交
#!/bin/bash
cd /data/project/spark/spark_workstation
/data/sbt/bin/sbt compile && /data/sbt/bin/sbt package && \
/data/spark/bin/spark-submit --master yarn \
--deploy-mode cluster \
--verbose \
--num-executors 2 \
--executor-memory '1024m' \
--executor-cores 1 \
--class spark.mllib.modelAssess ./target/scala-2.11/mergedata_2.11-2.2.1.jar \
hdfs://master:9000/sparkMLlib/sample_libsvm_data.txt
*/
将数据的清洗、转换等数据的预处理工作,以及构建模型和评估模型这些任务当做 spark Pipeline的 stage,这样既可以保证各任务之间有序执行,也保证的处理数据的数据的一致性
// 创建 Pipeline,将各个 Stage 依次组装在一起
val pipeline = new Pipeline().setStages(Array(tokenizer,hashingTF,lr))
// 在训练集上拟合这个 Pipeline
val model = pipeline.fit(training)
// 在测试集上做预测
model.transform(test).select("label","prediction")
调优:使用给定的数据为给定的任务寻找最适合的模型或参数,调优可以是对单个阶段进行调试,也可以一次性对整个Pipeline 进行调优
MLlib 支持使用类型CorssValidator 和 TrainValidationSplit 这样的工具进行模型选择,这类工具有一下组件
模型选择工具工作原理如下:
交叉验证的缺点:虽然利用 CrossValidator 来训练模型可以提升泛华能力,但其代价比较高。如果 K =3 regParam = (0.1,0.01)、numiters = (10,20) 这样就需要对模型训练 3*2*2 = 12 次。然而对比启发式的手动调优,这是选择参数的行之有效的方法
model.write.overwrite().save("/tmp/spark-logistic-regreesion-model")
pipeline.write.overwrite().save("/tmp/spark-logistic-regression-model1")
val sameMode = PiplelineModel.load("/tmp/spark-logistic-regreesion-model")