我正在使用Spark ML来运行一些ML实验,并且在一个20MB(Poker dataset)的小数据集和一个带参数网格的随机森林中,需要1小时30分钟才能完成。与scikit-learn类似,它需要的费用要少得多。
在环境方面,我正在测试2个从站,每个15GB内存,24个内核。我认为不应该花那么长时间,我想知道问题是否在我的代码中,因为我对Spark很新。
这是:
df = pd.read_csv(http://archive.ics.uci.edu/ml/machine-learning-databases/poker/poker-hand-testing.data)
dataframe = sqlContext.createDataFrame(df)
train, test = dataframe.randomSplit([0.7, 0.3])
columnTypes = dataframe.dtypes
for ct in columnTypes:
if ct[1] == 'string' and ct[0] != 'label':
categoricalCols += [ct[0]]
elif ct[0] != 'label':
numericCols += [ct[0]]
stages = []
for categoricalCol in categoricalCols:
stringIndexer = StringIndexer(inputCol=categoricalCol, outputCol=categoricalCol+"Index")
stages += [stringIndexer]
assemblerInputs = map(lambda c: c + "Index", categoricalCols) + numericCols
assembler = VectorAssembler(inputCols=assemblerInputs, outputCol="features")
stages += [assembler]
labelIndexer = StringIndexer(inputCol='label', outputCol='indexedLabel', handleInvalid='skip')
stages += [labelIndexer]
estimator = RandomForestClassifier(labelCol="indexedLabel", featuresCol="features")
stages += [estimator]
parameters = {"maxDepth" : [3, 5, 10, 15], "maxBins" : [6, 12, 24, 32], "numTrees" : [3, 5, 10]}
paramGrid = ParamGridBuilder()
for key, value in parameters.iteritems():
paramGrid.addGrid(estimator.getParam(key), value)
estimatorParamMaps = (paramGrid.build())
pipeline = Pipeline(stages=stages)
crossValidator = CrossValidator(estimator=pipeline, estimatorParamMaps=estimatorParamMaps, evaluator=MulticlassClassificationEvaluator(labelCol='indexedLabel', predictionCol='prediction', metricName='f1'), numFolds=3)
pipelineModel = crossValidator.fit(train)
predictions = pipelineModel.transform(test)
evaluator = pipeline.getEvaluator().evaluate(predictions)
在此先感谢,我们非常感谢任何意见/建议:)
答案 0 :(得分:4)
以下内容可能无法完全解决您的问题,但它应该为您提供一些启动指针。
您面临的第一个问题是数据量和资源之间的不成比例。
这意味着由于您正在并行化本地集合(pandas dataframe),因此Spark将使用默认的并行性配置。哪个最有可能导致48
分区的每个分区小于0.5mb
。 (Spark不适用于小文件或小分区)
第二个问题与Spark中Tree模型使用的昂贵的优化/近似技术有关。
Spark树模型使用一些技巧来优化存储连续变量。对于小数据,只需获得精确的分割就更便宜了。 在这种情况下,它主要使用近似分位数。
通常,在单个机器框架场景中,如scikit
,树模型将连续要素的唯一要素值用作最佳拟合计算的分割候选。而在Apache Spark中,树模型使用每个要素的分位数作为拆分候选。
另外要补充一点,你不应该忘记交叉验证是一项沉重而漫长的任务,因为它与你的3个超参数的组合成倍,折叠的次数乘以花费的时间。训练每个模型(GridSearch方法)。您可能希望在每个示例中缓存您的数据以便开始,但它仍然不会花费您太多时间。我认为火花对于这一数据来说是一种过度杀伤力。您可能希望使用scikit learn,并使用spark-sklearn分发本地模型培训。
Spark将根据数据分布和大的假设分别和顺序地学习每个模型。
你当然可以使用基于柱状数据的文件格式来优化性能,例如镶木地板和调整火花本身等等。它太广泛了,不能在这里谈论它。
您可以在以下博文中了解有关使用spark-mllib的树模型可伸缩性的更多信息: