Python Spark 机器学习(一)

Python Spark 机器学习(一)

主要是MLlib包(基于RDD)和ml包(基于DataFrame)的使用

Python Spark MLlib 决策树二元分类

通过Kaggle上一个题目来实践: StumbleUpon Evergreen Classification Challenge

该题目内容是判断一个网页内容是暂时性的(ephemeral)还是长青的(evergreen),具体内容可以在Kaggle网站上查看

在这里插入图片描述

查看并下载数据(需注册)

在data页面查看train数据的大致情况,有27列,其中26列特征列,1列标签列。查看数据描述,其中0-2字段是网址、网址ID、样板文字,跟网页是否长青关系不大,我们可以直接忽略。

在这里插入图片描述

后面的字段都是特征字段,第三个是string,后面的都是数值型(太多,就不一一展示,可以在网页上查看)。这些大致判断是跟结果有关的(至于到底有多大相关,如果是数值型可以求相关系数表,如果是字符型可以做方差分析)。
在这里插入图片描述

test数据有26列,全是特征列,没有标签列(废话)。

下载train和test数据,解压。

上传文件到HDFS

# 启动hdfs
start-dfs.sh
# 先创建两个文件用来存储输入和输出文件(可自行指定)
hadoop fs -mkdir /user/hduser/input
hadoop fs -mkdir /user/hduser/output
# 上传下载的两个文件到hdfs
hadoop fs -copyFromLocal *.tsv /user/hduser/input

在这里插入图片描述

数据预处理

用jupyter notebook打开pyspark(参考以往的博文)

# 先开启节点
/usr/local/spark/sbin/start-all.sh
# 再启动spark(其他启动方法也行)
pyspark --master spark://master:7077

在这里插入图片描述

new一个新的notebook

# 配置文件读取路径
global Path
if sc.master[0:5]=='local':
    '''如果是现在本地运行则读取本地文件'''
    Path = 'file:/home/hduser/'
else:
    '''否则读取hdfs文件'''
    Path = 'hdfs://master:9000/user/hduser/input/'

在这里插入图片描述

# 读取文本并查看数据
rawDataWithHeader = sc.textFile(Path + 'train.tsv')
rawDataWithHeader.take(2)

在这里插入图片描述

# 从上面输出可以看到,表头也被包含在数据中,我们不需要,可以去掉。还有数据以'\'分割,并被""包围,我们要去除这些,得到纯数据
# 将表头取出来
header = rawDataWithHeader.first()
# 将表头匹配删除
rawData = rawDataWithHeader.filter(lambda r: r != header)
# 将双引号去掉
rData = rawData.map(lambda r: r.replace("\"", ""))
# 根据\t分割数据,得到纯数据
lines = rData.map(lambda r: r.split("\t"))
print("共计:" + str(lines.count()) + "行")

在这里插入图片描述

提取特征字段

# 先查看第一项数据
lines.first()[3:]

在这里插入图片描述

# 由于第四个字段是string,我们要将其转换为数值型,首先为其建立一个字典,每一个键值(即特征值)对应一个数字。
categoriesMap = lines.map(lambda fields: fields[3]).distinct().zipWithIndex().collectAsMap()
categoriesMap
# 我们看到每一个值都对应了一个数字
# 可能会有报错 Exception: Randomness of hash of string should be disabled via PYTHONHASHSEED
# 此时保存退出,更改spark配置文件spark-defaults.conf,在最后加入一行 spark.executorEnv.PYTHONHASHSEED=0
# 问题解决

在这里插入图片描述

# 编写函数提取特征字段
import numpy as np
def extract_feture(field, categoriesMap, featureEnd):
    '''
    field: 每一项数据
    categories: 分类字典
    featureEnd: 特征字段的结尾
    '''
    # 提取分类特征字段 (跟pandas和sklearn的dummy功能差不多)就是OneHotEncoding
    categoryIdx = categoriesMap[field[3]] # 获取该特征值在字典中的数值
    categoryFeatures = np.zeros(len(categoriesMap)) # 创建分类特征字段
    categoryFeatures[categoryIdx] = 1 # 令对应的值为1
    # 提取数值字段
    numericalFeatures = [convert_float(field) for field in field[4:featureEnd]]
    # 将两类字段合并返回
    return np.concatenate((categoryFeatures, numericalFeatures))

def convert_float(x):
    '''将缺失值以0代替'''
    return (0 if x=='?' else float(x))

def extract_label(field):
    label = field[-1]
    return float(label)

在这里插入图片描述

在这里插入图片描述

# 训练模型的数据必须以LabeledPoint格式提供,先建立LabeledPoint数据
from pyspark.mllib.regression import LabeledPoint
labelPointRDD = lines.map(lambda r:
                         LabeledPoint(
                                extract_label(r),
                                extract_features(r, categoriesMap, len(r)-1)))
# 一行一行创建LabelPoint

在这里插入图片描述

# 划分数据集为三部分,训练数据、验证数据、和测试数据
(trainData, validationData, testData) = labelPointRDD.randomSplit([8, 1, 1])
print("将数据分trainData:" + str(trainData.count())+ " validationData:" + str(validationData.count()) + " testData:" + str(testData.count()))

在这里插入图片描述

# 为了加快后续程序的运行效率,将数据存储在内存中
trainData.persist()
validationData.persist()
testData.persist()

在这里插入图片描述

建立并训练模型

from pyspark.mllib.tree import DecisionTree
model = DecisionTree.trainClassifier(trainData, numClasses=2, categoricalFeaturesInfo={}, impurity='entropy', maxDepth=5, maxBins=5)
# numClasses: 分类数目,这里是二元分类
# categoricalFeaturesInfo: 设置分类特征字段信息,这里不用了
# impurity:c: 分类评判方法,gini 基尼指数或者 entropy熵  想多了解可以去看专门的机器学习书
# maxDepth: 决策树最大深度
# maxBins: 决策树每一个节点最大分支数

在这里插入图片描述

使用模型进行预测

# 定义PredictData函数
def PredictData(sc, model, categoriesMap):
    rawDataWithHeader = sc.textFile(Path + 'test.tsv')
    header = rawDataWithHeader.first()
    rawData = rawDataWithHeader.filter(lambda r: r != header)
    rData = rawData.map(lambda r: r.replace("\"", ""))
    lines = rData.map(lambda r: r.split("\t"))
    print("共计:" + str(lines.count()) + "行")
    # 以上的数据预处理跟以前相同
    # 将网址跟特征字段打包
    dataRDD = lines.map(lambda r: (r[0], extract_features(r, categoriesMap, len(r))))
    DescDict = {
        0: "暂时性网页(ephemera)",
        1: "长青网页(evergreen)"
    }
    # 进行预测
    for data in dataRDD.take(10):
        predictResult = model.predict(data[1])
        print("网址:" + str(data[0]) + "\n" + "      ===>预测:" + str(predictResult) + "说明:" + DescDict[predictResult] + "\n")

在这里插入图片描述

# 预测结果
PredictData(sc, model, categoriesMap)
# 你可以点进网页查看是否正确

在这里插入图片描述

模型评估

# 编写模型评估函数
# 我们采用MLlib提供的BinaryClassificationMetrics计算AUC进行评估
from pyspark.mllib.evaluation import BinaryClassificationMetrics
def evaluateModel(model, validationData):
    # 先预测
    score = model.predict(validationData.map(lambda p: p.features))
    # 再将预测结果与原标签进行组合
    scoreAndLabels = score.zip(validationData.map(lambda p: p.label))
    # 建立二元分类
    metrics = BinaryClassificationMetrics(scoreAndLabels)
    # 计算AUC
    AUC = metrics.areaUnderROC
    return AUC

AUC = evaluateModel(model, validationData)
print("AUC: " + str(AUC))

在这里插入图片描述

超参数调整

# 先建立模型训练函数(将之前的几步组合起来),加一个时间记录
from time import time
def trainEvaluateModel(trainData, validationData, impurityParam, maxDepthParam, maxBinsParam):
    startTime = time()
    model = DecisionTree.trainClassifier(trainData, numClasses=2, categoricalFeaturesInfo={},
                                         impurity=impurityParam, maxDepth=maxDepthParam, maxBins=maxBinsParam)
    AUC = evaluateModel(model, validationData)
    duration = time() - startTime
    print("训练评估: 使用参数" + " impurity: " + str(impurityParam) + " maxDepth: " + str(maxDepthParam) + " maxBins: " + str(maxBinsParam) + 
         "==>所需时间: " + str(duration) + " AUC: " + str(AUC))
    return (AUC, duration, impurityParam, maxDepthParam, maxBinsParam, model)

在这里插入图片描述

# 建立评估参数函数
def evalParameter(trainData, validationData, impurityList, maxDepthList, maxBinsList):
    # 用一个for循环评估所有参数组合
    metrics = [trainEvaluateModel(trainData, validationData, impurity, maxDepth, maxBins)
               for impurity in impurityList
               for maxDepth in maxDepthList
               for maxBins in maxBinsList]
    # 找出AUC参数最大的参数组合
    Smetrics = sorted(metrics, key=lambda r: r[0], reverse=True)
    bestParameter = Smetrics[0]
    # 显示最佳参数
    print("调参后最佳参数组合:" + " impurity: " + str(bestParameter[2]) + " maxDepth: " + str(bestParameter[3]) +
          " maxBins: " + str(bestParameter[4]) + "\n, 结果AUC = " + str(bestParameter[0]))
    # 返回最佳模型
    return bestParameter[5]

bestModel = evalParameter(trainData, validationData, ["gini", "entropy"], [3, 5, 10, 15, 20, 25], [3, 5, 10, 50, 100, 200])

在这里插入图片描述

最后会根据AUC选出一个最佳参数组合

在这里插入图片描述

)

本文到这里就结束了,这只是最基本的Spark机器学习,而且只用了Mllib,没用更新的ml包,下一篇将使用ml包建立管道流机器学习。(还缺少数据探索性分析和特征选择几步,有兴趣可以自己做)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值