如何在没有DataFrames / SparkContext的情况下评估spark.ml模型?

时间:2016-03-15 02:35:49

标签: apache-spark apache-spark-mllib apache-spark-ml

使用Spark MLLib,我构建了一个模型(如RandomForest),然后通过加载模型并在其上使用predict传递一个模型,可以在Spark外部对它进行评估。特征向量。

似乎与Spark ML一样,predict现在称为transform,仅对DataFrame起作用。

有没有办法在Spark之外构建DataFrame,因为看起来需要一个SparkContext来构建一个DataFrame?

我错过了什么吗?

3 个答案:

答案 0 :(得分:2)

Re:有没有办法在Spark之外构建一个DataFrame?

这是不可能的。 DataFrames位于SQLContext中,它位于SparkContext中。也许你可以用以某种方式来解决它,但整个故事是DataFrames和SparkContext之间的连接是设计的。

答案 1 :(得分:1)

这是我在spark上下文之外使用spark模型的解决方案(使用PMML):

  1. 您可以使用如下管道创建模型:
  2. SparkConf sparkConf = new SparkConf();

    SparkSession session = SparkSession.builder().enableHiveSupport().config(sparkConf).getOrCreate();   
    String tableName = "schema.table";
    Properties dbProperties = new Properties();
    dbProperties.setProperty("user",vKey);
    dbProperties.setProperty("password",password);
    dbProperties.setProperty("AuthMech","3");
    dbProperties.setProperty("source","jdbc");
    dbProperties.setProperty("driver","com.cloudera.impala.jdbc41.Driver");
    String tableName = "schema.table";
    String simpleUrl = "jdbc:impala://host:21050/schema"
    Dataset<Row> data = session.read().jdbc(simpleUrl ,tableName,dbProperties);
    String[] inputCols = {"column1"};
    StringIndexer indexer = new StringIndexer().setInputCol("column1").setOutputCol("indexed_column1");
    StringIndexerModel alphabet  = indexer.fit(data);
    data = alphabet.transform(data);
    VectorAssembler assembler = new VectorAssembler().setInputCols(inputCols).setOutputCol("features");
    Predictor p = new GBTRegressor();
    p.set("maxIter",20);
    p.set("maxDepth",2);
    p.set("maxBins",204);
    p.setLabelCol("faktor");
    PipelineStage[] stages = {indexer,assembler, p};
    Pipeline pipeline = new Pipeline();
    pipeline.setStages(stages);
    PipelineModel pmodel = pipeline.fit(data);
    PMML pmml = ConverterUtil.toPMML(data.schema(),pmodel);
    FileOutputStream fos = new FileOutputStream("model.pmml");
    JAXBUtil.marshalPMML(pmml,new StreamResult(fos));
    
    1. 使用PPML进行预测(本地,没有spark上下文,可以应用于参数Map而不是DataFrame):

      PMML pmml = org.jpmml.model.PMMLUtil.unmarshal(new FileInputStream(pmmlFile));
      ModelEvaluatorFactory modelEvaluatorFactory = ModelEvaluatorFactory.newInstance();
      MiningModelEvaluator evaluator = (MiningModelEvaluator) modelEvaluatorFactory.newModelEvaluator(pmml);
      inputFieldMap = new HashMap<String, Field>();     
      Map<FieldName,String> args = new HashMap<FieldName, String>();
      Field curField = evaluator.getInputFields().get(0);
      args.put(curField.getName(), "1.0");
      Map<FieldName, ?> result  = evaluator.evaluate(args);
      

答案 2 :(得分:0)

在此问题上也花费了几天。这并不简单。我的第三个建议涉及我为此目的专门编写的代码。

选项1

正如其他评论者所说,predict(Vector)现在可用。但是,您需要知道如何构造向量。如果不这样做,请参阅选项3。

选项2

如果目标是避免设置Spark服务器(独立或集群模式),则可以在本地模式下启动Spark。整个过程将在单个JVM中运行。

val spark = SparkSession.builder().config("spark.master", "local[*]").getOrCreate()
// create dataframe from file, or make it up from some data in memory
// use model.transform() to get predictions

但是,这给您的预测模块带来了不必要的依赖性,并且在运行时消耗了JVM中的资源。另外,如果预测等待时间很关键,例如,一旦收到请求,就要在毫秒内做出预测,那么此选项太慢了。

选项3

MLlib FeatureHasher的输出可用作学习者的输入。该类适用于一种热编码,也适合于固定要素尺寸的大小。即使所有特征都是数字,您也可以使用它。如果在训练中使用它,那么在预测时所需的就是那里的哈希逻辑。其implemented作为火花变压器,因此在火花环境之外不容易重复使用。因此,我已经完成了将哈希函数提取到lib的工作。您可以像往常一样在训练期间应用FeatureHasher和您的学习者。然后是在预测时使用瘦身哈希器的方法:

// Schema and hash size must stay consistent across training and prediction
val hasher = new FeatureHasherLite(mySchema, myHashSize)

// create sample data-point and hash it
val feature = Map("feature1" -> "value1", "feature2" -> 2.0, "feature3" -> 3, "feature4" -> false)
val featureVector = hasher.hash(feature)

// Make prediction
val prediction = model.predict(featureVector)

您可以在tilayealemu/sparkmllite的github中查看详细信息。如果您想复制我的代码,请查看FeatureHasherLite.scala。还有示例代码和单元测试。如果您需要帮助,请随时提出问题。