根据同一行中的其他列动态选择列内容

时间:2016-12-21 08:01:48

标签: scala apache-spark

我正在使用Spark 1.6.1。让我们说我的数据框架如下:

+------------+-----+----+
|categoryName|catA |catB|
+------------+-----+----+
|     catA   |0.25 |0.75|
|     catB   |0.5  |0.5 |
+------------+-----+----+

categoryName具有字符串类型,cat*为Double。我想添加一个列,该列将包含名称位于categoryName列中的列的值:

+------------+-----+----+-------+
|categoryName|catA |catB| score |
+------------+-----+----+-------+
|     catA   |0.25 |0.75| 0.25  | ('score' has value from column name 'catA')
|     catB   |0.5  |0.7 |  0.7  | ('score' value from column name 'catB')
+------------+-----+----+-------+

我需要这样的提取到稍后的计算。有什么想法吗?

重要提示:我不知道类别列的名称。解决方案需要是动态的。

2 个答案:

答案 0 :(得分:3)

Spark 2.0 : 您可以通过创建一个包含categroyName - >地图的临时列来执行此操作(对于任意数量的类别列)。 categoryValue,然后从中进行选择:

// sequence of any number of category columns
val catCols = input.columns.filterNot(_ == "categoryName")

// create a map of category -> value, and then select from that map using categoryName:
input
  .withColumn("asMap", map(catCols.flatMap(c => Seq(lit(c), col(c))): _*))
  .withColumn("score", $"asMap".apply($"categoryName"))
  .drop("asMap")

Spark 1.6 :类似的想法,但使用数组和UDF从中进行选择:

// sequence of any number of category columns
val catCols = input.columns.filterNot(_ == "categoryName")

// UDF to select from array by index of colName in catCols
val getByColName = udf[Double, String, mutable.WrappedArray[Double]] {
  case (colName, colValues) =>
    val index = catCols.zipWithIndex.find(_._1 == colName).map(_._2)
    index.map(colValues.apply).getOrElse(0.0)
}

// create an array of category values and select from it using UDF:
input
  .withColumn("asArray", array(catCols.map(col): _*))
  .withColumn("score", getByColName($"categoryName", $"asArray"))
  .drop("asArray")

答案 1 :(得分:1)

您有几种选择:

  1. 如果您使用scala,则可以使用数据集API,在这种情况下,您只需创建一个执行计算的地图。
  2. 您可以从数据框移至RDD并使用地图
  3. 您可以创建一个UDF,它接收所有相关列作为输入并在
  4. 中进行计算
  5. 您可以使用一堆when / otherwise子句进行搜索(例如,当(col1 == CatA,col(CatA))。否则(col(CatB)))