如何在 Spark 机器学习中应用 scikit-learn

(andehr03)
(kobeshow)
第三方登录:几周前,我们的Florian Douetteau (FD)对Olivier Grisel(OG)进行了一次访谈,正好我得到这个机会去旁听。Olivier是scikit-learn机器学习库的主要贡献者,因此他们两个详细地讨论了Olivier的工作和其它技术的发展。这是采访的第一部分。Olivier Grisel 和 scikit-learnFD:Olivier,你作为scikit-learn的主要贡献者已经有一段时间了。你可以告诉我们一些关于你的贡献么?OG:大概是2010年,我就开始做scikit-learn这个项目。我是利用业余时间去做这个项目的。在2013年10月,我加入了Inria,一所面向计算机科学和自动化研究的法国研究院。我们有个团队,名叫Parietal,主要研究使用MRI数据对大脑进行建模。在这个项目中,我主要负责让scikit-learn发展地更长远,主要是指性能和可扩展性方面。FD:scikit-learn已经发展了这么多年,而且知道开发过程中的许多阻碍。你能告诉我们一些关于将来的事么?OG:当然可以。在过去的几年中,我们已经知道了一个重大的进展。现在,我们有很多新的用户和贡献者。根据我们的网站统计,我们每个月有0000个独立访客,其中有1 / 3是回访用户,而且我们也有越来越多的贡献者。例如,在这些天,几乎有300个pull请求需要我们去处理。scikit-learn大多数的新发展都来自用户社区自身的贡献。他们不断给scikit-learn库进行修改和补充,并为scikit-learn更好的后续版本提交这些工作。然后我们会对这些修改进行测试,并将其添加到每个新的版本中。例如,在最近的一个测试版本里,我们的一个贡献者开发了LDA估测器。这个算法在某种程度上可以替换scikit-learn已经存在的MMF,而且LDA在可扩展性方面表现的更强。我开发的是一个更加长期的项目,这个项目涉及了大量的问题(因此它并不属于下一个版本的一部分)。我们正在努力使更多的scikit-learn算法能够以数据流模式,或核外模式,来管理数据,而不是在内存中控制整个数据集。我们希望它们逐渐地加载数据集,就像它们训练模型那样。scikit-learn
MLlibFD:目前,在机器学习领域,我们听到了大量关于Spark的传闻。你有机会去尝试一下么?如何把它与scikit-learn进行比较呢?OG:通过制作的两个Spark教程,我了解了一下Spark(教程1,教程2)。Spark和Python或scikit-learn之间的主要区别是,Spark默认是一个系统,以分布式的方式管理那些其它数据处理方法无法在内存中处理的数据。这也是MLlib一开始的设计方向(ed:Spark分布式机器学习框架)。他们选择仅实现可扩展性的算法,这些算法可以在它们有能力处理的那些数据上和大量集群中运行。通过只选择有这种特性的算法,他们目前已经解决了这个双重可扩展性问题。scikit-learn最初的目的是处理内存中的数据,所以我们不存在偏见。我们有一些非常有效的算法,它们只在小数据集上有效。但事实上,我们有很多算法都是以批处理模式实现的。目前,我正在对它们进行重构,主要是为了让其具有更好的可扩展性。scikit-learn并不是创建跨集群的功能。我们不想改变所有的功能,来处理存储在集群中的资源,但我们想把它作为一种可能性,确保scikit-learn模型可以嵌入到一个类似Spark的框架里,这样它们就可以分布在集群中。例如,当你在训练一个随机森林时,如果你认为你的数据小到可以在整个集群中进行复制,那么你可以很容易地训练每棵树。对于中等规模的数据集,我们也想要加快超参数搜索和交叉验证的速度,这自然就是并行。在解决集群的分布式计算之前(正如Spark关注的),我对于研究有效的核外处理方法(像Dato正在做的)也是很有兴趣的。目前我还没有真正地研究过细节,但似乎只要你能够更好地进行核外处理并重视算法效率,你就可以减少资源的浪费。这也可能成为scikit-learn未来发展的驱动力。FD:以分布式方式存储大量数据会导致性能和结果的偏差么?我正在思考使用Spark运行随机森林的例子。OG:MLlib随机森林算法在选择特征进行划分时,它是直接在每棵树的训练层面进行并行的。它并没有考虑所有可能的分裂。它建立的是一个直方图,并在划分的数据集上进行并行运算。然后,使用总的信息构建划分。这跟估计算法类似。尽管这种方法是近似估算,但在实际应用中,当你使用样本进行建模时,几乎不会出现问题。因为和非估计算法的结果相比非常接近,只是实现的效率差了点。未来的方向是特征生成?FD:当你去查看一个数据项目,很多时间–如果不是大部分时间–是用在数据预处理和特征生成。在过去的几个月里,scikit-learn在朝着特征工程方向发展。这是你将继续维持的方向吗?你会朝一个集成的管道工作吗?这似乎像是一条无止尽的路。有没有一些平行的项目专攻特定的数据类型和格式,同时又遵循scikit-learn的习惯和理念?OG:在创建scikit-learn预测模型时,特征始终是一个关键点。因为pandas数据框的最新版本,我们越来越善于整合工具箱去操纵任何格式的数据,并把它转为其它格式或是任何其他的表示。我赞同你的观点,特征工程对于一个具体的应用程序而言,永远是一个特殊环节。我们希望保留一个通用库。如果我们要专攻某个特定的领域并开发特征,它将成为一个独立的特定库的一部分。例如,在天体物理学中有一个叫AstroML的专用库。此前,我在INRIA的团队处理的是影像数据。我们已经开发了一个特定的库,叫做nilearn,它是scikit-learn的一个分支项目。事实上,划分不同项目的范围是很有好处的。它可以围绕社区特定的实践活动进行更好地交流。FD:在特征工程这个主题上,你相信Spark和MLlib会改变数据科学家的工作方式么?OG:最近的数据框API是Spark的一个优点。它给了数据科学家一个非常直观,灵活,并富有表现力的工具,用于测试他们不同的数据表示。从更高层面来讲,最新版本的spark.ml包,允许在以数据组合为特征的“链”中创建管道和预测模型。在链的不同阶段可以交叉验证参数的相互作用。也正是这类API的优点,使它更易于测试。其实在scikit-learn中也可以安装插件,使用数据框作为输入并且添加用户自定义的scikit-learn转换脚本。事实上,使这个过程变得更加简单也正是我们应该努力的实践方向。搜寻这些项目FD:非常感谢您这次精彩的谈话!你觉得还有其他任何需要补充的吗?OG:我认为Python生态圈越来越意识到当前的技术形势,特别是在谈及到处理大量数据时。Java和Scala领先于我们,尤其是Hadoop和Spark。开发人员对于这一点都非常清楚,他们正在寻找答案。如今有很多有趣的项目,如Blaze,Dask,或XRay。他们正在开发相关的APIs,努力使其像Pandas一样出色,并且能做核外计算,最终形成分布式的。Wes McKinney给Cloudera做的Ibis项目也很有趣。它使用的是Python,但用Impala作为后台,用其替代PySpark。其实,我并不相信在当今的生产中能够使用它,但我相信这个主题的发展将会很有趣。敬请期待Olivier访谈的第二部分,在那里他给数据科学的入门人士和想知道应该培养什么技术的学者提出了一些建议。原文链接:[Interview] Olivier Grisel on scikitlearn and the future of Machine Learning technologies (part 1)(编译/刘帝伟 审校/朱正贵、赵屹华 责编/周建丁)译者简介:刘帝伟,中南大学软件学院在读研究生,关注机器学习、数据挖掘及生物信息领域。本文为CSDN原创,点击“阅读原文”可查看完整文章并参与讨论。如果您喜欢这篇文章,请点击右上角“…”将本文分享给你的朋友。CSDN(CSDNnews) 
 文章为作者独立观点,不代表大不六文章网立场
CSDNnewsCSDN精彩内容每日推荐。我们关注IT产品研发背后的那些人、技术和故事。热门文章最新文章CSDNnewsCSDN精彩内容每日推荐。我们关注IT产品研发背后的那些人、技术和故事。&&&&违法和不良信息举报电话:183-
举报邮箱:
Copyright(C)2016 大不六文章网
京公网安备78developerWorks 社区
本文将通过一个分类预测的机器学习问题向读者展示如何使用 Spark 新的 ML Pipeline 库构建机器学习的工作流。通过本文的阅读,读者将会了解到 ML Pipeline 与 MLlib 相比在设计上的独到和使用上的不同之处,并且会深入理解 ML Pipeline 的基本概念和工作方式,为进一步学习和深入研究打下良好的基础。
, 软件工程师,
王龙,资深软件工程师,目前就职于IBM全球商业解决方案中心,主要从事基于数据挖掘技术的反欺诈和滥用系统的开发。个人研究方向还包括Hadoop,Spark等大数据存储和计算技术
引言使用机器学习 (Machine
Learning) 技术和方法来解决实际问题,已经被成功应用到多个领域,我们经常能够看到的实例有个性推荐系统,金融反欺诈,自然语言处理和机器翻译,模式识别,智能控制等。一个典型的机器学习机器学习过程通常会包含:源数据 ETL,数据预处理,指标提取,模型训练与交叉验证,新数据预测等。我们可以看到这是一个包含多个步骤的流水线式工作,也就是说数据从收集开始,要经历多个步骤,才能得到我们需要的输出。在已经向大家介绍了 Spark MLlib 机器学习库,
虽然 MLlib 已经足够简单易用,但是如果目标数据集结构复杂需要多次处理,或者是对新数据进行预测的时候需要结合多个已经训练好的单个模型进行综合预测
(集成学习的思想),那么使用 MLlib 将会让程序结构复杂,难于理解和实现。值得庆幸的是,在 Spark 的生态系统里,一个可以用于构建复杂机器学习工作流应用的新库已经出现了,它就是 Spark
1.2 版本之后引入的 ML Pipeline,经过几个版本的发展,截止目前的 1.5.1 版本已经变得足够稳定易用了。本文将向读者详细地介绍 Spark ML
Pipeline 的设计思想和基本概念,以及如何使用 ML
Pipeline 提供的 API 库编写一个解决分类预测问题的 Pipeline 式应用程序。相信通过本文的学习,读者可以较为深入的理解 ML
Pipeline,进而将它推广和应用到更多复杂问题的解决方案上去。关于 ML PipelineSpark ML Pipeline 的出现,是受到了
项目的启发,并且总结了 MLlib 在处理复杂机器学习问题上的弊端,旨在向用户提供基于 DataFrame 之上的更加高层次的 API 库,以更加方便的构建复杂的机器学习工作流式应用。一个 Pipeline 在结构上会包含一个或多个 PipelineStage,每一个 PipelineStage 都会完成一个任务,如数据集处理转化,模型训练,参数设置或数据预测等,这样的 PipelineStage 在 ML 里按照处理问题类型的不同都有相应的定义和实现。接下来,我们先来了解几个重要概念。 DataFrame关于 DataFrame 其实我们已经在介绍过了,它较之 RDD,包含了 schema 信息,更类似传统数据库中的二维表格。它被 ML Pipeline 用来存储源数据。DataFrame 可以被用来保存各种类型的数据,如我们可以把特征向量存储在 DataFrame 的一列中,这样用起来是非常方便的。 TransformerTransformer 中文可以被翻译成转换器,是一个 PipelineStage,实现上也是继承自 PipelineStage 类,主要是用来把
一个 DataFrame 转换成另一个 DataFrame,比如一个模型就是一个 Transformer,因为它可以把
一个不包含预测标签的测试数据集 DataFrame 打上标签转化成另一个包含预测标签的 DataFrame,显然这样的结果集可以被用来做分析结果的可视化。 EstimatorEstimator 中文可以被翻译成评估器或适配器,在 Pipeline 里通常是被用来操作 DataFrame 数据并生产一个 Transformer,如一个随机森林算法就是一个 Estimator,因为它可以通过训练特征数据而得到一个随机森林模型。实现上 Estimator 也是继承自 PipelineStage 类。 ParameterParameter 被用来设置 Transformer 或者 Estimator 的参数。
要构建一个 Pipeline,首先我们需要定义 Pipeline 中的各个 PipelineStage,如指标提取和转换模型训练等。有了这些处理特定问题的 Transformer 和 Estimator,我们就可以按照具体的处理逻辑来有序的组织 PipelineStages
并创建一个 Pipeline,如 val pipeline = new
Pipeline().setStages(Array(stage1,stage2,stage3,…))。然后就可以把训练数据集作为入参并调用 Pipelin 实例的 fit 方法来开始以流的方式来处理源训练数据,这个调用会返回一个 PipelineModel 类实例,进而被用来预测测试数据的标签,它是一个 Transformer。随机森林及 ML 的实现随机森林构建于决策树之上,顾名思义,就是随机的构建一个包含多个决策树的森林。随机森林里的决策树之间是独立的,在随机森林模型构建好以后,对于新来的测试样本数据,随机森林模型会让其中的每个决策树分别做一次预测,然后统计出现此处最多的预测标签,并将它作为最终的预测标签。随机森林算法运用的就是集成学习的思想,在实践中,随机森林往往都有很好表现,并且多次预测结果稳定并且精度非常高,也不容易出现过拟合的问题。也是笔者最喜欢并且最常用的一种机器学习算法。本文并不会重点介绍随机森林的基本理论,因为网上这样的文章已经很多了,本文将把重点放在对 Spark ML
中随机森林的实现以及可调参数的介绍。关于随机森林算法的详细介绍大家可以参考维基百科上的。Spark ML 中随机森林实现是在 RandomForestClassifier 类中,位于 org.apache.spark.ml.
classification 包中,该实现中支持设置的主要参数如下: featuresCol训练数据集 DataFrame 中存储特征数据的列名。 labelCol标签列的名称。 impurity树节点选择的不纯度的衡量指标,取值可以是”entroy”或“gini”, 默认是”gini”。 maxBins离散连续性变量时最大的分箱数,默认是 32。理论上箱数越大粒度就越细,但是针对特定的数据集总有一个合理的箱数。 maxDepth树的最大深度,默认值是 5。 numTrees随机森林需要训练的树的个数,默认值是 20。 predictionCol算法预测结果的存储列的名称, 默认是”prediction”。 rawPredictionCol原始的算法预测结果的存储列的名称, 默认是”rawPrediction” probabilityCol类别预测结果的条件概率值存储列的名称, 默认值是”probability”
在后文中大家可以看到如何在程序中设置这些参数。可以调用 RandomForestClassifier.setXXX 方法或者在 ParamMap 里设定参数,然后再调用 RandomForestClassifier.fit 方法时传入 ParamMap 实例,如:RandomForestClassifier 的 fit 方法从源头上来讲,是来自 Predictor 类 (Estimator 的子类),Predictor 类的 fit 方法设计和实现上实际上是采用了模板方法的设计模式,具体会调用实现类的 train 方法图 1. Predictor 类的 fit 方法实现预览
所以对于 RandomForestClassifier 类我们最需要关注的就是 train 方法,其中包含具体从源数据 DataFrame 训练一个随机森林模型的过程。train 方法在提取出 DataFrame 数据集中的 label 和 features 数据之后,进一步调用 RandomForest.run 方法去真正的开始训练随机森林模型,训练结束后会返回一个 RandomForestClassificationModel 类实例,这是一个 Transformer,会被用来预测测试数据集。图 2. RandomForestClassifier 类的 train 方法实现预览对于 RandomForest 类的 run 方法的具体实现逻辑,已经在 developerWorks 的 一文中有详细介绍,为了避免内容冲突,本文的内容将重点放在 ML
Pipeline 的实现层次关系上,在这里不做赘述。目标数据集预览本文所使用的测试数据集来自 UCI 的
,这是一个从纸币鉴别过程中的图片里提取的数据集,总共包含五个列,前 4 列是指标值 (连续型),最后一列是真假标识。图 3. 测试数据集格式四列依次是小波变换图像的方差,小波变换图像的偏态,小波变换图像的峰度,图像熵,类别标签。其实读者并不需要知道什么是小波变换及其相关改变,只需要知道这是四个特征指标的值,我们将根据这些指标训练模型使用模型预测类别。对于该数据集的更多信息,读者可以参考 UCI 官网的描述。案例分析与编码实现前面提到,本文的目的是使用 Spark ML Pipeline 构建一个对目标数据集进行分类预测的机器学习工作流,案例背景已经相当清晰,在了解了数据集本身和 ML
Pipeline 的相关知识后,接下来就是编程实现了。关于实现基本思路和关键的 11 个步骤笔者已经在代码中做了详细解释,为了方便读者理解,这里特别的把该实例的 Pipeline 里包含的 4 个 Stage 重点介绍下。这四个 Stage 分别对应代码注释里的步骤 2-5,作用如下:第一个,使用 StringIndexer 去把源数据里的字符 Label,按照 Label 出现的频次对其进行序列编码, 如,0,1,2,…。在本例的数据中,可能这个步骤的作用不甚明显,因为我们的数据格式良好,Label 本身也只有两种,并且已经是类序列编码的”0”和”1”格式。但是对于多分类问题或者是 Label 本身是字符串的编码方式,如”High”,”Low”,”Medium”等,那么这个步骤就很有用,转换后的格式,才能被 Spark 更好的处理。第二个,使用 VectorAssembler 从源数据中提取特征指标数据,这是一个比较典型且通用的步骤,因为我们的原始数据集里,经常会包含一些非指标数据,如 ID,Description 等。第三个,创建一个随机森林分类器 RandomForestClassifier 实例,并设定相关参数,主要是告诉随机森林算法输入 DataFrame 数据里哪个列是特征向量,哪个是类别标识,并告诉随机森林分类器训练 5 棵独立的子树。第四个,我们使用 IndexToString
Transformer 去把之前的序列编码后的 Label 转化成原始的 Label,恢复之前的可读性比较高的 Label,这样不论是存储还是显示模型的测试结果,可读性都会比较高。这几个 Stage 都会被用来构建 Pipeline 实例,并且会按照顺序执行,最终我们根据得到的 PipelineModel 实例,进一步调用其 transform 方法,去用训练好的模型预测测试数据集的分类。清单 1. 示例程序源代码import org.apache.spark.ml.Pipeline
import org.apache.spark.ml.classification._
import org.apache.spark.ml.evaluation.MulticlassClassificationEvaluator
import org.apache.spark.ml.feature.{IndexToString, StringIndexer, VectorAssembler}
import org.apache.spark.ml.param.ParamMap
import org.apache.spark.sql.SQLContext
import org.apache.spark.{SparkConf, SparkContext}
object ClassificationPipeline {
def main(args: Array[String]) {
if (args.length & 1){
println("Usage:ClassificationPipeline inputDataFile")
sys.exit(1)
val conf = new SparkConf().setAppName("Classification with ML Pipeline")
val sc = new SparkContext(conf)
val sqlCtx = new SQLContext(sc)
/** Step 1
* Read the source data file and convert it to be a dataframe with columns named.
* 3.1,-2.99,0
* 4.4,-2.1,0
* 3.866,-2.2,0.10645,0
* 3.8,-4.4,0
* 0.32,4.8,0
val parsedRDD = sc.textFile(args(0)).map(_.split(",")).map(eachRow =& {
val a = eachRow.map(x =& x.toDouble)
(a(0),a(1),a(2),a(3),a(4))
val df = sqlCtx.createDataFrame(parsedRDD).toDF(
"f0","f1","f2","f3","label").cache()
* StringIndexer encodes a string column of labels
* to a column of label indices. The indices are in [0, numLabels),
* ordered by label frequencies.
* This can help detect label in raw data and give it an index automatically.
* So that it can be easily processed by existing spark machine learning algorithms.
val labelIndexer = new StringIndexer()
.setInputCol("label")
.setOutputCol("indexedLabel")
* Define a VectorAssembler transformer to transform source features data to be a vector
* This is helpful when raw input data contains non-feature columns, and it is common for
* such a input data file to contain columns such as "ID", "Date", etc.
val vectorAssembler = new VectorAssembler()
.setInputCols(Array("f0","f1","f2","f3"))
.setOutputCol("featureVector")
* Create RandomForestClassifier instance and set the input parameters.
* Here we will use 5 trees Random Forest to train on input data.
val rfClassifier = new RandomForestClassifier()
.setLabelCol("indexedLabel")
.setFeaturesCol("featureVector")
.setNumTrees(5)
* Convert indexed class labels back to original one so that it can be easily understood when we
* need to display or save the prediction result to a file.
val labelConverter = new IndexToString()
.setInputCol("prediction")
.setOutputCol("predictedLabel")
.setLabels(labelIndexer.labels)
//Randomly split the input data by 8:2, while 80% is for training, the rest is for testing.
val Array(trainingData, testData) = df.randomSplit(Array(0.8, 0.2))
* Create a ML pipeline which is constructed by for 4 PipelineStage objects.
* and then call fit method to perform defined operations on training data.
val pipeline = new Pipeline().setStages(Array(labelIndexer,vectorAssembler,rfClassifier,labelConverter))
val model = pipeline.fit(trainingData)
*Perform predictions about testing data. This transform method will return a result DataFrame
*with new prediction column appended towards previous DataFrame.
val predictionResultDF = model.transform(testData)
* Select features,label,and predicted label from the DataFrame to display.
* We only show 20 rows, it is just for reference.
predictionResultDF.select("f0","f1","f2","f3","label","predictedLabel").show(20)
* The evaluator code is used to compute the prediction accuracy, this is
* usually a valuable feature to estimate prediction accuracy the trained model.
val evaluator = new MulticlassClassificationEvaluator()
.setLabelCol("label")
.setPredictionCol("prediction")
.setMetricName("precision")
val predictionAccuracy = evaluator.evaluate(predictionResultDF)
println("Testing Error = " + (1.0 - predictionAccuracy))
* Step 11(Optional)
* You can choose to print or save the the model structure.
val randomForestModel = model.stages(2).asInstanceOf[RandomForestClassificationModel]
println("Trained Random Forest Model is:\n" + randomForestModel.toDebugString)
}运行示例程序在运行程序之前,读者需要把目标数据集上传至你的 HDFS 上,并把测试程序打成 jar 包。清单 2. 示例程序运行命令及参数示例./spark-submit --class com.ibm.spark.exercise.ml.ClassificationPipeline
\--master spark://&spark_master&:&port&\--num-executors 6 \--driver-memory 3g \--executor-memory 1g \--executor-cores 1 /home/fams/spark_exercise-1.0.jar \ hdfs://&hdfs_name_node&:&port&/user/fams/mllib/data_banknote_authentication.txt当然如果你想采用“yarn-cluster”或者”yarn-client”的方式运行,运行命令会有稍许不同,并且根据你的集群状况的不同,可能命令也会发生稍许变化。图 4. 示例程序运行结果预览 (部分)从运行结果的预测错误来看,预测正确率基本可以达到近 98%,当然你可以按 9:1 去划分训练和测试数据集,这样可以得到更好的精确度。由此看来,随机森林算法的预测精度确实非常的好,当然这也取决于该组数据的模式比较明显,特征数据质量比较好。注意事项 本文的目标数据集结构其实并不复杂,之所以用 ML Pipeline 的方式实现训练和预测过程是为了向大家展示 ML Pipeline 的用法,这样的简单数据集也更有利于读者掌握 ML
Pipeline 的处理过程。 ML Pipeline 提供了大量做特征数据提取和转换的工具,具体参考。
使用 Spark 解决机器学习问题,我们通常需要先了解相关算法的原理,然后学习 Spark 相关实现的可调参数,测试过程中,可以针对数据集特点多尝试几种算法,并多做模型的交叉验证。
本文所使用的数据集数据量很小,所以可能反映不了 Spark 处理大数据的优势,读者如果有更大量的数据集,即可对本文程序做少许修改便可以使用在新的数据集上,以测试并了解更多的实现细节。总结本文向读者较为详细的介绍了 ML Pipeline 的基本概念和编程实现步骤,大家可以看到,较之 MLlib,ML
Pipeline 在结构和逻辑层次上确实是更加清晰了。但是我认为 MLlib 对于处理结构相对简单的数据集其实依然具有优势,可能刚开始更容易被理解接受。另外从 Spark 的学习曲线上来讲,刚开始大家接触的都是 RDD,对 DataFrame 不甚了解,所以对于初学者对 MLlib 的方式其实更容易接受。所以,应该说 MLlib 和 ML
Pipeline 都有各自的优势吧。当然,这更多是我个人的理解。希望这篇文章可以对大家学习 ML
Pipeline 有帮助,在阅读过程中,有任何不懂或者发现任何问题,请留下您的评论,我会第一时间回答,这样也是一个交流学习的过程,非常感谢。
参考资料 参考 ,了解基本理论和方法。参考 ,了解相关 API 的用法。:查找丰富的操作信息、工具和项目更新,帮助您掌握开源技术并将其用于 IBM 产品。
加入 ,查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。
developerWorks: 登录
标有星(*)号的字段是必填字段。
保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件。
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
选择您的昵称
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。
您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
标有星(*)号的字段是必填字段。
(昵称长度在 3 至 31 个字符之间)
单击提交则表示您同意developerWorks 的条款和条件。 .
所有提交的信息确保安全。
文章、教程、演示,帮助您构建、部署和管理云应用。
立即加入来自 IBM 的专业 IT 社交网络。
免费下载、试用软件产品,构建应用并提升技能。
static.content.url=/developerworks/js/artrating/SITE_ID=10Zone=Open source, Big data and analyticsArticleID=1019058ArticleTitle=Spark 实战,第 5 部分: 使用 ML Pipeline 构建机器学习工作流publish-date=}

我要回帖

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信