![](/img/trans.png)
[英]How to convert Array[Long] to Vector type in scala dataframe?
[英]How to loop through the Dataframe which is of type of Array and append the value to a final Dataframe using Scala
請為以下問題的解決方案提供幫助嗎?問題01:有沒有一種方法可以僅循環數組類型,因為在數組中循環字符串類型會引發錯誤。 我無法刪除String Type(VIN),因為我需要在最終df上使用此數據。
df.printSchema
返回:
root
|-- APP: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- E: long (nullable = true)
| | |-- V: double (nullable = true)
|-- B1X: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- E: long (nullable = true)
| | |-- V: long (nullable = true)
|-- B2X: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- E: long (nullable = true)
| | |-- V: long (nullable = true)
|-- B3X: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- E: long (nullable = true)
| | |-- V: long (nullable = true)
|-- VIN: string (nullable = true)
運行以下forloop之后:
問題02:數據幀jsonDF2僅保留最后一個信號B3X的最后一個E,V值作為stime,can_value。 有沒有一種方法可以將所有值(我是指所有信號值{APP,B1X,B2X,B3X,VIN})附加到Dataframe jsonDF2中,使其脫離foreach循環。
val columns:Array[String] = df.columns
for(col_name <- columns){
| df = df.withColumn("element", explode(col(col_name)))
| .withColumn("stime", col("element.E"))
| .withColumn("can_value", col("element.V"))
| .withColumn("SIGNAL", lit(col_name))
| .drop(col("element"))
| .drop(col(col_name))
| }
您可以使用架構成員,然后使用過濾器和地圖將其過濾掉。 然后執行for循環操作。
import org.apache.spark.sql.types._
val schema = df.schema.filter{ case StructField(_, datatype, _, _) => datatype == ArrayType }
val columns = schema.map{ case StructField(columnName, _ , _, _) => columnName }
這是使用以下示例說明的一種方法:
import org.apache.spark.sql.types._
import org.apache.spark.sql.Row
import org.apache.spark.sql.functions._
import spark.implicits._
case class Elem(e: Long, v: Double)
val df = Seq(
(Seq(Elem(1, 1.0)), Seq(Elem(2, 2.0), Elem(3, 3.0)), Seq(Elem(4, 4.0)), Seq(Elem(5, 5.0)), "a"),
(Seq(Elem(6, 6.0)), Seq(Elem(7, 7.0), Elem(8, 8.0)), Seq(Elem(9, 9.0)), Seq(Elem(10, 10.0)), "b")
).toDF("APP", "B1X", "B2X", "B3X", "VIN")
問題1:有沒有辦法我只能循環數組類型?
您可以簡單地collect
ArrayType
所有頂級字段名稱,如下所示:
val arrCols = df.schema.fields.collect{
case StructField(name, dtype: ArrayType, _, _) => name
}
// arrCols: Array[String] = Array(APP, B1X, B2X, B3X)
問題2:是否可以添加所有信號值{APP,B1X,B2X,B3X,VIN}?
不知道我是否完全了解您的要求,而沒有提供示例輸出。 根據您的代碼片段,我假設您的目標是將結構類型元素的所有數組列展平為單獨的頂層列。 步驟如下:
步驟1 :將所有數組列分組為struct(colName, colValue)
的單個數組列; 然后使用foldLeft
轉換每一行,以生成struct(colName, Elem-E, Elem-V)
的組合數組:
case class ColElem(c: String, e: Long, v: Double)
val df2 = df.
select(array(arrCols.map(c => struct(lit(c).as("_1"), col(c).as("_2"))): _*)).
map{ case Row(rs: Seq[Row] @unchecked) => rs.foldLeft(Seq[ColElem]()){
(acc, r) => r match { case Row(c: String, s: Seq[Row] @unchecked) =>
acc ++ s.map(el => ColElem(c, el.getAs[Long](0), el.getAs[Double](1)))
}
}}.toDF("combined_array")
df2.show(false)
// +-----------------------------------------------------------------------------+
// |combined_array |
// +-----------------------------------------------------------------------------+
// |[[APP, 1, 1.0], [B1X, 2, 2.0], [B1X, 3, 3.0], [B2X, 4, 4.0], [B3X, 5, 5.0]] |
// |[[APP, 6, 6.0], [B1X, 7, 7.0], [B1X, 8, 8.0], [B2X, 9, 9.0], [B3X, 10, 10.0]]|
// +-----------------------------------------------------------------------------+
步驟2 :將結構類型元素的組合數組展平到頂級列中:
df2.
select(explode($"combined_array").as("flattened")).
select($"flattened.c".as("signal"), $"flattened.e".as("stime"), $"flattened.v".as("can_value")).
orderBy("signal", "stime").
show
// +------+-----+---------+
// |signal|stime|can_value|
// +------+-----+---------+
// | APP| 1| 1.0|
// | APP| 6| 6.0|
// | B1X| 2| 2.0|
// | B1X| 3| 3.0|
// | B1X| 7| 7.0|
// | B1X| 8| 8.0|
// | B2X| 4| 4.0|
// | B2X| 9| 9.0|
// | B3X| 5| 5.0|
// | B3X| 10| 10.0|
// +------+-----+---------+
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.