【问题标题】:How to convert a Dataframe into a List (Scala)?如何将数据框转换为列表(Scala)?
【发布时间】:2019-09-13 16:06:28
【问题描述】:

我想将包含 Double 值的 Dataframe 转换为 List,以便我可以使用它进行计算。您有什么建议,以便我可以采用正确的类型 List(即 Double)?

我的做法是这样的:

var newList = myDataFrame.collect().toList 

但它返回一个类型 List[org.apache.spark.sql.Row] 我不知道它到底是什么!

是否可以忘记该步骤,只需将我的 Dataframe 传递到函数中并从中进行计算? (例如,我想将其第二列的第三个元素与特定的 double 进行比较。是否可以直接从我的 Dataframe 中这样做?

我必须不惜一切代价了解如何每次都创建正确的类型列表!

编辑:

输入数据框:

+---+---+ 
|_c1|_c2|
+---+---+ 
|0  |0  | 
|8  |2  | 
|9  |1  | 
|2  |9  | 
|2  |4  | 
|4  |6  | 
|3  |5  | 
|5  |3  | 
|5  |9  | 
|0  |1  | 
|8  |9  | 
|1  |0  | 
|3  |4  |
|8  |7  | 
|4  |9  | 
|2  |5  | 
|1  |9  | 
|3  |6  |
+---+---+

转换后的结果:

List((0,0), (8,2), (9,1), (2,9), (2,4), (4,6), (3,5), (5,3), (5,9), (0,1), (8,9), (1,0), (3,4), (8,7), (4,9), (2,5), (1,9), (3,6))

但是 List 中的每个元素都必须是 Double 类型。

【问题讨论】:

  • 你能解释一下输入和预期结果吗?
  • 您好!再次检查!

标签: scala list apache-spark dataframe


【解决方案1】:

你可以将你需要的coulmn转换成Double并转换成RDD和collect

如果您有无法解析的数据,则可以在将其转换为双精度之前使用 udf 进行清理

val stringToDouble = udf((data: String) => {
  Try (data.toDouble) match {
    case Success(value) => value
    case Failure(exception) => Double.NaN
  }
})

 val df = Seq(
   ("0.000","0"),
   ("0.000008","24"),
   ("9.00000","1"),
   ("-2","xyz"),
   ("2adsfas","1.1.1")
 ).toDF("a", "b")
  .withColumn("a", stringToDouble($"a").cast(DoubleType))
  .withColumn("b", stringToDouble($"b").cast(DoubleType))

在此之后,您将获得输出为

+------+----+
|a     |b   |
+------+----+
|0.0   |0.0 |
|8.0E-6|24.0|
|9.0   |1.0 |
|-2.0  |NaN |
|NaN   |NaN |
+------+----+

获取Array[(Double, Double)]

val result = df.rdd.map(row => (row.getDouble(0), row.getDouble(1))).collect()

结果将是Array[(Double, Double)]

【讨论】:

  • 您好!我理解你的方法背后的逻辑,但我在实践方面失去了它,因为我对 scala 很陌生。我在这里理解的是,您使用标准数据创建了一个 DataFrame。在我的情况下,我必须创建的数据框来自数据集文件(csv),它不会每次都是标准的。那么如何将现有 DataFrame 的一列转换为 Double?
  • 另外,当我在我的数据帧上运行“convert to rdd”命令时(没有任何转换更改)我收到此错误org.apache.spark.SparkException: Job aborted due to stage failure: Task 0 in stage 333.0 failed 1 times, most recent failure: Lost task 0.0 in stage 333.0 (TID 333, localhost, executor driver): java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Double
  • 在这些情况下,您需要清理数据,需要删除空值或删除一些无法转换为 Double 的值等等。这取决于您的实施。你可以创建一个 udf 来清理所有这些东西。
  • 是的,错误很明显,您需要将 coulmn 转换为 Double java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Double
  • 哦,好的!我明白!这意味着我必须做更多的挖掘工作!感谢您的回复!
【解决方案2】:
#Convert DataFrame to DataSet using case class & then convert it to list

#It'll return the list of type of your class object.All the variables inside the #class(mapping to fields in your table)will be pre-typeCasted) Then you won't need to #type cast every time.

#Please execute below code to check it-
#Sample to check & verify(scala)-

val wa = Array("one","two","two")
val wr = sc.parallelize(wa,3).map(x=>(x,"x",1))
val wdf = wr.toDF("a","b","c")
case class wc(a:String,b:String,c:Int)
val myList= wds.collect.toList
myList.foreach(x=>println(x))
myList.foreach(x=>println(x.a.getClass,x.b.getClass,x.c.getClass))

【讨论】:

  • 您好!它给了我这个错误:error: too many arguments for method println: (x: Any)Unit myList.foreach(x=>println(x.a.getClass,x.b.getClass,x.c.getClass))
  • 您使用的是哪个版本的 spark?或者您可以使用 - myList.foreach(x=>println(xagetClass)) 仅检查单个元素数据类型,同样您可以检查单个列的数据类型或将它们连接成单个字符串(这只是检查数据类型)。跨度>
【解决方案3】:
myDataFrame.select("_c1", "_c2").collect().map(each => (each.getAs[Double]("_c1"), each.getAs[Double]("_c2"))).toList

【讨论】:

  • 这会返回什么类型的列表?
  • 这种方法需要我的 DataFrame 的一列并将其传递给序列?如何获取我的 DataFrame 的所有列?我可以像使用列表一样使用序列吗?
  • 是的,与 List 和 myDataFrame.select("column1", "column2").collect().map(each => (each.getAs[String]("column1"), each .getAs[String]("column2")) ).toList 你会在这里得到元组列表
  • 谢谢!现在我想问一下,这个List中会存在什么类型的元素呢?字符串还是双精度?
  • 在此示例中,我将两列都转换为字符串。您必须根据您的数据框进行投射。在本例中,您将获得元组的列表 ( List[(String, String)] )
猜你喜欢
  • 2017-06-11
  • 2019-11-16
  • 2019-06-26
  • 1970-01-01
  • 1970-01-01
  • 2020-07-29
  • 2018-01-07
  • 2020-03-04
  • 1970-01-01
相关资源
最近更新 更多