如何将csv字符串转换为Spark-ML兼容的数据集<row>格式?

时间:2018-04-03 16:55:09

标签: java apache-spark apache-spark-sql apache-spark-ml apache-spark-dataset

我有Dataset<Row> df,其中包含string类型的两列(&#34;键&#34;和#34;值&#34;)。 df.printSchema();给我以下输出:

root
 |-- key: string (nullable = true)
 |-- value: string (nullable = true)

值列的内容实际上是csv格式化的行(来自kafka主题),该行的最后一个条目表示类标签,所有先前的条目都是功能(第一行不包含在数据集中) ):

feature0,feature1,label
0.6720004294237854,-0.4033586564886893,0
0.6659082469383558,0.07688976580256132,0
0.8086502311695247,0.564354801275521,1

由于我想在这个数据上训练一个分类器,我需要将这个表示转换为一个类型密集向量的行,包含所有的特征值和一个double类型的列,包含标签值:

root
 |-- indexedFeatures: vector (nullable = false)
 |-- indexedLabel: double (nullable = false)

如何使用java 1.8和Spark 2.2.0进行此操作?

编辑:我走得更远,但在尝试使用灵活数量的特征尺寸时,我再次陷入困境。我创建了一个follow-up question.

2 个答案:

答案 0 :(得分:1)

你有不同的方法来实现这一目标。

根据您的CSV文件创建架构。

public class CSVData implements Serializable {
  String col1;
  String col2;
  long col3;
  String col4;
  //getters and setters  
}

然后将文件转换为RDD。

JavaSparkContext sc;
JavaRDD<String> data = sc.textFile("path-to-csv-file");
JavaSQLContext sqlContext = new JavaSQLContext(sc);

JavaRDD<Record> csv_rdd = sc.textFile(data).map(
  new Function<String, Record>() {
      public Record call(String line) throws Exception {
         String[] fields = line.split(",");
         Record sd = new Record(fields[0], fields[1], fields[2].trim(), fields[3]);
         return sd;
      }
});

或者

创建Spark会话以将文件读取为数据集。

SparkSession spark = SparkSession
                .builder()
                .appName("SparkSample")
                .master("local[*]")
                .getOrCreate();
//Read file
Dataset<Row> ds = spark.read().text("path-to-csv-file");
 or
Dataset<Row> ds = spark.read().csv("path-to-csv-file");
ds.show();

答案 1 :(得分:1)

VectorAssemblerjavadocs)可以将数据集转换为所需的格式。

首先,输入分为三列:

Dataset<FeaturesAndLabelData> featuresAndLabelData = inputDf.select("value").as(Encoders.STRING())
  .flatMap(s -> {
    String[] splitted = s.split(",");
    if (splitted.length == 3) {
      return Collections.singleton(new FeaturesAndLabelData(
        Double.parseDouble(splitted[0]),
        Double.parseDouble(splitted[1]), 
        Integer.parseInt(splitted[2]))).iterator();
    } else {
      // apply some error handling...
      return Collections.emptyIterator();
    }
  }, Encoders.bean(FeaturesAndLabelData.class));

然后由VectorAssembler转换结果:

VectorAssembler assembler = new VectorAssembler()
  .setInputCols(new String[] { "feature1", "feature2" })
  .setOutputCol("indexedFeatures");
Dataset<Row> result = assembler.transform(featuresAndLabelData)
  .withColumn("indexedLabel", functions.col("label").cast("double"))
  .select("indexedFeatures", "indexedLabel");

结果数据框具有所需的格式:

+----------------------------------------+------------+
|indexedFeatures                         |indexedLabel|
+----------------------------------------+------------+
|[0.6720004294237854,-0.4033586564886893]|0.0         |
|[0.6659082469383558,0.07688976580256132]|0.0         |
|[0.8086502311695247,0.564354801275521]  |1.0         |
+----------------------------------------+------------+

root
 |-- indexedFeatures: vector (nullable = true)
 |-- indexedLabel: double (nullable = true)

FeaturesAndLabelData是一个简单的Java bean,用于确保列名正确:

public class FeaturesAndLabelData {
  private double feature1;
  private double feature2;
  private int label;

  //getters and setters...
}