Scala 一组接一组

Scala 一组接一组,scala,apache-spark,spark-dataframe,Scala,Apache Spark,Spark Dataframe,我有一个数据框,有4列co1,col2,col3和col4。我需要: 基于键col1和col2 然后将其他列分组,如col3和col4,并显示col3和col4的计数 输入 输出 col1 col2 col_name col_value cnt 1 1 col3 2 2 1 1 col3 3 1 1 1 col4 4 2 1 1 col4 5

我有一个数据框,有4列
co1
col2
col3
col4
。我需要:

  • 基于键
    col1
    col2
  • 然后将其他列分组,如
    col3
    col4
    ,并显示
    col3
    col4
    的计数
输入

输出

col1 col2 col_name col_value  cnt
1     1    col3      2         2
1     1    col3      3         1
1     1    col4      4         2
1     1    col4      5         1

这可能吗?

这是
melt
类操作的情况。您可以使用as-to提供的实现


我们可以使用groupBy和union来实现这一点

val x = Seq((1, 1,2,4),(1, 1,2,4),(1, 1,3,5)).toDF("col1", "col2", "col3", "col4")

val  y = x.groupBy("col1", "col2","col3").
          agg(count(col("col3")).alias("cnt")).
          withColumn("col_name", lit("col3")).
          select(col("col1"), col("col2"), col("col_name"), col("col3").alias("col_value"), col("cnt"))

val z = x.groupBy("col1", "col2","col4").
          agg(count(col("col4")).alias("cnt")).
          withColumn("col_name", lit("col4")).
          select(col("col1"), col("col2"), col("col_name"), col("col4").alias("col_value"), col("cnt"))

y.union(z).show()

这里有一种方法适用于任意数量的键列和值列(请注意,示例数据集已扩展以用于演示):

val df = Seq(
  (1, 1, 2, 4), (1, 1, 2, 4), (1, 1, 3, 5)
).toDF("col1", "col2", "col3", "col4")


df.melt(
  Seq("col1", "col2"), Seq("col3", "col4"), "col_name", "col_value"
).groupBy("col1", "col2", "col_name", "col_value").count.show
// +----+----+--------+---------+-----+
// |col1|col2|col_name|col_value|count|
// +----+----+--------+---------+-----+
// |   1|   1|    col3|        3|    1|
// |   1|   1|    col4|        5|    1|
// |   1|   1|    col4|        4|    2|
// |   1|   1|    col3|        2|    2|
// +----+----+--------+---------+-----+
val x = Seq((1, 1,2,4),(1, 1,2,4),(1, 1,3,5)).toDF("col1", "col2", "col3", "col4")

val  y = x.groupBy("col1", "col2","col3").
          agg(count(col("col3")).alias("cnt")).
          withColumn("col_name", lit("col3")).
          select(col("col1"), col("col2"), col("col_name"), col("col3").alias("col_value"), col("cnt"))

val z = x.groupBy("col1", "col2","col4").
          agg(count(col("col4")).alias("cnt")).
          withColumn("col_name", lit("col4")).
          select(col("col1"), col("col2"), col("col_name"), col("col4").alias("col_value"), col("cnt"))

y.union(z).show()
val df = Seq(
  (1, 1, 2, 4, 6),
  (1, 1, 2, 4, 7),
  (1, 1, 3, 5, 7)
).toDF("col1", "col2", "col3", "col4", "col5")

import org.apache.spark.sql.functions._

val keyCols = Seq("col1", "col2")
val valCols = Seq("col3", "col4", "col5")

val dfList = valCols.map( c => {
  val grpCols = keyCols :+ c

  df.groupBy(grpCols.head, grpCols.tail: _*).agg(count(col(c)).as("cnt")).
    select(keyCols.map(col) :+ lit(c).as("col_name") :+ col(c).as("col_value") :+ col("cnt"): _*)
} )

dfList.reduce(_ union _).show
// +----+----+--------+---------+---+
// |col1|col2|col_name|col_value|cnt|
// +----+----+--------+---------+---+
// |   1|   1|    col3|        3|  1|
// |   1|   1|    col3|        2|  2|
// |   1|   1|    col4|        4|  2|
// |   1|   1|    col4|        5|  1|
// |   1|   1|    col5|        6|  1|
// |   1|   1|    col5|        7|  2|
// +----+----+--------+---------+---+