[提前声明]
文章由作者:张耀峰 结合自己生产中的使用经验整理,最终形成简单易懂的文章
写作不易,转载请注明,谢谢!
代码案例地址: ?https://github.com/Mydreamandreality/sparkResearch
运行你的第一个机器学习程序
让我们一起开发第一个机器学习程序
我们要做的案例也很简单,自动识别垃圾邮件
在开始编码前,我们先把一些可能遇到的坑埋掉↓
系统依赖
如果运行中MLlib警告找不到gfortran
库需要先安装该库
MLlib使用了线性代数包Breeze
,它依赖于netlib-java
和jblas
,netlib-java 和 jblas 需要依赖native Fortran routines,所以需要安装gfortran runtime library
如果你是用python开发spark,就需要NumPy version 1.4
或以上版本.numpy是python机器学习的基础库
Centos安装 使用命令:sudo yum install libgfortran.x86_64
编码思路
- 我们可能需要如下几个步骤:
- 首先用字符串RDD表示我们的消息
- 运行MLlib中的一个
特征提取算法
把数据转换为数值特征,该操作会返回一个向量的RDD - 对向量的RDD调用
分类算法(逻辑回归)
,返回一个模型对象,用该对象对新的数据进行分类 - 使用MLlib的评估函数在测试数据集上评估模型
Java代码案例:
package v1;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.mllib.classification.LogisticRegressionModel;
import org.apache.spark.mllib.classification.LogisticRegressionWithSGD;
import org.apache.spark.mllib.linalg.Vector;
import org.apache.spark.mllib.regression.LabeledPoint;
import org.apache.spark.sql.SparkSession;
import org.apache.spark.mllib.feature.HashingTF;
import java.util.Arrays;
import java.util.regex.Pattern;
/**
* Created by 張燿峰
* 机器学习入门案例
* 过滤垃圾邮件
*
* @author 孤
* @date 2019/5/7
* @Varsion 1.0
*/
public class SpamEmail {
private static final Pattern SPACE = Pattern.compile(" ");
public static void main(String[] args) {
SparkSession sparkSession = SparkSession.builder().appName("spam-email").master("local[2]").getOrCreate();
JavaSparkContext javaSparkContext = JavaSparkContext.fromSparkContext(sparkSession.sparkContext());
//垃圾邮件数据
JavaRDD<String> spamEmail = javaSparkContext.textFile("spam.json");
//优质邮件数据
JavaRDD<String> normalEmail = javaSparkContext.textFile("normal.json");
//创建hashingTF实例把邮件文本映射为包含10000个特征的向量
final HashingTF hashingTF = new HashingTF(10000);
JavaRDD<LabeledPoint> spamExamples = spamEmail.map(new Function<String, LabeledPoint>() {
@Override
public LabeledPoint call(String v1) throws Exception {
return new LabeledPoint(0, hashingTF.transform(Arrays.asList(SPACE.split(v1))));
}
});
JavaRDD<LabeledPoint> normaExamples = normalEmail.map(new Function<String, LabeledPoint>() {
@Override
public LabeledPoint call(String v1) throws Exception {
return new LabeledPoint(1, hashingTF.transform(Arrays.asList(SPACE.split(v1))));
}
});
//训练数据
JavaRDD<LabeledPoint> trainData = spamExamples.union(normaExamples);
trainData.cache(); //逻辑回归需要迭代,先缓存
//随机梯度下降法 SGD 逻辑回归
LogisticRegressionModel model = new LogisticRegressionWithSGD().run(trainData.rdd());
Vector spamModel = hashingTF.transform(Arrays.asList(SPACE.split("垃 圾 钱 恶 心 色 情 赌 博 毒 品 败 类 犯罪")));
Vector normaModel = hashingTF.transform(Arrays.asList(SPACE.split("work 工作 你好 我们 请问 时间 领导")));
System.out.println("预测负面的例子: " + model.predict(spamModel));
System.out.println("预测积极的例子: " + model.predict(normaModel));
}
}
这个程序使用了MLlib中的两个函数HashingTF
和LogisticRegressionWithSGD
.前者从文本数据构建词频特征向量
,后者使用随机梯度下降法
(Stochastic Gradient Descent),简称 SGD实现逻辑回归,假设我们从两个文件 spam.json和normal.json开始,两个文件分别包含垃圾邮件和非垃圾邮件的例子,每行一个,接下来我们就根据词频把每个文件中的文本转化为特征向量.然后训练出一个可以把两类消息分开的逻辑回归模型
Python代码案例
from pyspark.mllib.regression import LabeledPoint
from pyspark.mllib.feature import HashingTF
from pyspark.mllib.classification import
LogisticRegressionWithSGD
spam = sc.textFile("spam.txt")
normal = sc.textFile("normal.txt")
tf = HashingTF(numFeatures = 10000)
spamFeatures = spam.map(lambda email: tf.transform(email.split(" ")))
normalFeatures = normal.map(lambda email: tf.transform(email.split(" ")))
positiveExamples = spamFeatures.map(lambda features: LabeledPoint(1, features))
negativeExamples = normalFeatures.map(lambda features: LabeledPoint(0, features))
trainingData = positiveExamples.union(negativeExamples)
trainingData.cache() # 因为逻辑回归是迭代算法,所以缓存训练
# 使用SGD算法运行逻辑回归
model = LogisticRegressionWithSGD.train(trainingData)
# 一样的HashingTF特征来得到特征向量,然后对该向量应用得到的模型
posTest = tf.transform("work 工作 你好 我们 请问 时间 领导".split(""))
negTest = tf.transform("垃 圾 钱 恶 心 色 情 赌 博 毒 品 败 类 犯罪".split(" "))
print "Prediction for positive test example: %g" % model.predict(posTest)
print "Prediction for negative test example: %g" % model.predict(negTest)
总结
参考资料:spark文档
- 机器学习算法尝试根据训练数据(training data)使得表示算法行为的数学目标最大化,并以此来进行预测或作出决定
- 机器学习问题分为几种,包括分类、回归、聚类,每种都有不一样的目标。拿分类(classification)作为一个简单的例子:分类是基于已经被标记的其他数据点(比如一些已经分别被标记为垃圾邮件或非垃圾邮件的邮件)作为例子来识别一个数据点属于几个类别中的哪一种(比如判断一封邮件是不是垃圾邮件,所有的学习算法都需要定义每个数据点的特征(feature)集,也就是传给学习函数的值
大多数算法都只是专为数值特征(具体来说,就是一个代表各个特征值的数字向量)定义的,因此提取特征并转化为特征向量是机器学习过程中很重要的一步 - 例如,某个分类算法可能会在特征向量的空间中定义出一个平面,使得这个平面能“最好”地分隔垃圾邮件和非垃圾邮件。这里需要为“最好”给出定义(比如大多数数据点都被这个平面正确分类)。算法会在运行结束时返回一个代表学习决定的模型 (比如这个选中的平面),而这个模型就可以用来对新的点进行预测(例如根据新邮件的特征向量在平面的哪一边来决定它是不是垃圾邮件)
机器学习本身是一个很大的话题,难就难在迈出你的第一步
现在,你已经成功的跨出了第一步,继续努力吧!