使用RandomForest的Spark ML管道在20MB数据集上花费的时间太长

Lar*_*ite 8 apache-spark pyspark apache-spark-ml apache-spark-mllib

我正在使用Spark ML运行一些ML实验,并且在一个20MB的小型数据集(扑克数据集)和一个带参数网格的随机森林中,需要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)
Run Code Online (Sandbox Code Playgroud)

在此先感谢您的任何评论/建议:)

eli*_*sah 7

以下内容可能无法完全解决您的问题,但应该为您提供一些入门指南。

您面临的第一个问题是数据量和资源之间的不均衡

这意味着,由于您要并行化本地集合(pandas数据帧),因此Spark将使用默认的并行性配置。这最有可能导致48分区少于0.5mb每个分区。(对于小文件或小分区,Spark效果不佳)

第二个问题与Spark中Tree模型使用的昂贵的优化/逼近技术有关。

火花树模型使用一些技巧来优化存储连续变量。对于小数据,仅获取精确的分割会更便宜。在这种情况下,它主要使用近似分位数。

通常,在单个机器框架场景中,例如scikit,树模型使用连续功能的唯一特征值作为最佳拟合计算的候选分割。而在Apache Spark中,树模型将每个功能的分位数用作拆分候选。

另外还要补充一点,您也不要忘记交叉验证是一项繁重而艰巨的任务,因为它与3个超参数的组合乘以倍数乘以训练每个模型所花费的时间成正比(GridSearch方法)。您可能希望每个示例都缓存您的数据,但是仍然不会花费很多时间。我认为,火花对于这种数量的数据来说是一个过大的杀伤力。您可能要改用scikit学习,也可能要使用spark-sklearn进行分布式本地模型训练。

Spark将以数据分散且庞大的假设来依次学习每种模型。

当然,您可以使用基于柱状数据的文件格式(例如镶木地板和调整火花本身)来优化性能。这里讨论的范围太广了。

您可以在以下博文中阅读有关spark-mllib的树模型可伸缩性的更多信息: