Scala spark数据帧将行值转换为列名

Scala spark数据帧将行值转换为列名,scala,dataframe,apache-spark,apache-spark-sql,spark-streaming,Scala,Dataframe,Apache Spark,Apache Spark Sql,Spark Streaming,使用spark dataframe,我需要按用户id将行值转换为列和分区,并创建一个csv文件 val someDF=Seq( (“用户1”、“数学”、“代数-1”、“90”), (“用户1”、“物理”、“重力”、“70”), (“用户3”、“生物”、“健康”、“50”), (“用户2”、“生物”、“健康”、“100”), (“用户1”、“数学”、“代数-1”、“40”), (“用户2”,“物理”,“重力-2”,“20”) ).toDF(“用户id”、“课程id”、“课程名称”、“分数”) s

使用spark dataframe,我需要按用户id将行值转换为列和分区,并创建一个csv文件


val someDF=Seq(
(“用户1”、“数学”、“代数-1”、“90”),
(“用户1”、“物理”、“重力”、“70”),
(“用户3”、“生物”、“健康”、“50”),
(“用户2”、“生物”、“健康”、“100”),
(“用户1”、“数学”、“代数-1”、“40”),
(“用户2”,“物理”,“重力-2”,“20”)
).toDF(“用户id”、“课程id”、“课程名称”、“分数”)
someDF.show(假)
+-------+---------+-----------+-----+
|用户|课程|课程|名称|分数|
+-------+---------+-----------+-----+
|用户1 |数学|代数-1 | 90|
|用户1 |物理|重力| 70|
|用户3 |生物|健康| 50|
|用户2 |生物|健康| 100|
|用户1 |数学|代数-1 | 40|
|用户2 |物理|重力-2 | 20|
+-------+---------+-----------+-----+
val result=someDF.groupBy(“用户id”、“课程id”).pivot(“课程名称”).agg(第一(“分数”))
结果显示(假)
+-------+---------+---------+-------+---------+------+
|用户id |课程id |代数-1 |重力|重力-2 |健康|
+-------+---------+---------+-------+---------+------+
|用户3 |生物学|空|空|空| 50|
|user1 | math | 90 | null | null | null|
|用户2 |生物学|空|空|空| 100|
|用户2 |物理|空|空| 20 |空|
|用户1 |物理|空| 70 |空|空|
+-------+---------+---------+-------+---------+------+
通过上面的代码,我能够将行值(lesson_name)转换为列名。 但是我需要将输出保存在csv中的
课程中

在csv中预期输出的格式应如下所示。

biology.csv//预期输出
+-------+---------+------+
|用户id |课程id |健康|
+-------+---------+------+
|用户3 |生物学| 50|
|用户2 |生物学| 100|
+-------+---------+-------
physics.csv//预期输出
+-------+---------+---------+-------
|用户id |球场id |重力-2 |重力|
+-------+---------+---------+-------+
|用户2 |物理| 50 |空|
|用户1 |物理| 100 | 70 |
+-------+---------+---------+-------+
**注意:csv中的每门课程应仅包含其特定的课程名称,不应包含任何不相关的课程名称

实际上,在csv中,我可以在下面格式化**

result.write
.partitionBy(“课程id”)
.mode(“覆盖”)
.format(“com.databricks.spark.csv”)
.选项(“标题”、“正确”)
.save(somepath)
例如:

biology.csv//输出错误,因为它包含不相关的课程(代数-1、重力-2、代数-1)
+-------+---------+---------+-------+---------+------+
|用户id |课程id |代数-1 |重力|重力-2 |健康|
+-------+---------+---------+-------+---------+------+
|用户3 |生物学|空|空|空| 50|
|用户2 |生物学|空|空|空| 100|
+-------+---------+---------+-------+---------+------+

任何人都可以帮助解决此问题?

只需按课程进行筛选,然后再转向:

val result = someDF.filter($"course_id" === "physics").groupBy("user_id", "course_id").pivot("lesson_name").agg(first("score"))

+-------+---------+-------+---------+
|user_id|course_id|gravity|gravity-2|
+-------+---------+-------+---------+
|user2  |physics  |null   |20       |
|user1  |physics  |70     |null     |
+-------+---------+-------+---------+

我假设您的意思是希望按课程id将数据保存到单独的目录中。您可以使用这种方法

scala>val someDF=Seq(
(“用户1”、“数学”、“代数-1”、“90”),
(“用户1”、“物理”、“重力”、“70”),
(“用户3”、“生物”、“健康”、“50”),
(“用户2”、“生物”、“健康”、“100”),
(“用户1”、“数学”、“代数-1”、“40”),
(“用户2”,“物理”,“重力-2”,“20”)
).toDF(“用户id”、“课程id”、“课程名称”、“分数”)
scala>val result=someDF.groupBy(“用户id”、“课程id”).pivot(“课程名称”).agg(第一(“分数”))
scala>val eventNames=result.select($“课程id”).distinct().collect()
var eventlist=eventNames.map(x=>x(0).toString)
for(eventName当(col(c).isNull,0)时。否则(1).as(c)):*)
.groupBy().max(course.columns.map(c=>c):\ux*)
.首先
val colKeep=row.getValuesMap[Int](row.schema.fieldNames)
.map{c=>if(c._2==1)Some(c._1)else None}
.flatte.toArray
var final_df=course.select(row.schema.fieldNames.intersect(colKeep)
.map(c=>col(c.drop(4).dropRight(1)):*)
最终设计图显示()
final_df.coalesce(1).write.mode(“overwrite”).format(“csv”).save(s“${eventName}”)
}
+-------+---------+------+
|用户id |课程id |健康|
+-------+---------+------+
|用户3 |生物学| 50|
|用户2 |生物学| 100|
+-------+---------+------+
+-------+---------+-------+---------+
|用户id |球场id |重力|重力-2|
+-------+---------+-------+---------+
|用户2 |物理|空| 20|
|用户1 |物理| 70 |空|
+-------+---------+-------+---------+
+-------+---------+---------+
|用户id |课程id |代数-1|
+-------+---------+---------+
|用户1 |数学| 90|
+-------+---------+---------+

如果它解决了你的问题,请接受答案。HAppy Hadoop

你为什么要硬编码“物理”?如果我有1000个课程id怎么办?我们如何处理这种情况?我想创建一个课程智能csv文件?假设在这种情况下我有1000门课,每门课有5节课,那么你怎么处理@Andrew如果我有另一列(batchid)和courseid,该怎么办?假设我想同时保存courseid和batchid<代码>val someDF=Seq((“用户1”,“数学”,“代数-1”,“90”,“b1”),(“用户1”,“物理”,“重力”,“70”,“b1”),(“用户3”,“生物”,“健康”,“50”,“b2”),(“用户2”,“生物”,“健康”,“100”,“b2”),(“用户1”,“数学”,“代数-1”,“40”,“b1”),(“用户2”,“物理”,“重力-2”,“20”,“b3”))。toDF(“用户id”,“课程id”,“课程名称”,“分数”,“批次id”)
我想在batchid和courseid上创建一个csv文件,输出应该是这样的|
scala> val someDF = Seq(
("user1", "math","algebra-1","90"),
("user1", "physics","gravity","70"),
("user3", "biology","health","50"),
("user2", "biology","health","100"),
("user1", "math","algebra-1","40"),
("user2", "physics","gravity-2","20")
).toDF("user_id", "course_id","lesson_name","score")


scala> val result = someDF.groupBy("user_id", "course_id").pivot("lesson_name").agg(first("score"))

scala>     val eventNames = result.select($"course_id").distinct().collect() 
var eventlist =eventNames.map(x => x(0).toString)



for (eventName <- eventlist) {
val course = result.where($"course_id" === lit(eventName))
//remove null column

val row = course
.select(course.columns.map(c => when(col(c).isNull, 0).otherwise(1).as(c)): _*)
.groupBy().max(course.columns.map(c => c): _*)
.first

val colKeep = row.getValuesMap[Int](row.schema.fieldNames)
.map{c => if (c._2 == 1) Some(c._1) else None }
.flatten.toArray


var final_df = course.select(row.schema.fieldNames.intersect(colKeep)
.map(c => col(c.drop(4).dropRight(1))): _*)


final_df.show()

final_df.coalesce(1).write.mode("overwrite").format("csv").save(s"${eventName}")
}


+-------+---------+------+
|user_id|course_id|health|
+-------+---------+------+
|  user3|  biology|    50|
|  user2|  biology|   100|
+-------+---------+------+

+-------+---------+-------+---------+
|user_id|course_id|gravity|gravity-2|
+-------+---------+-------+---------+
|  user2|  physics|   null|       20|
|  user1|  physics|     70|     null|
+-------+---------+-------+---------+

+-------+---------+---------+
|user_id|course_id|algebra-1|
+-------+---------+---------+
|  user1|     math|       90|
+-------+---------+---------+