在 Scala / Spark 中将字符串转换为双精度?
Convert String to Double in Scala / Spark?
我有 JSON 数据集,其中包含像 "USD 5.00" 这样的字符串形式的价格。我想将数字部分转换为 Double 以在 MLLIB LabeledPoint 中使用,并设法将价格字符串拆分为字符串数组。下面创建了一个具有正确结构的数据集:
import org.apache.spark.mllib.linalg.{Vector,Vectors}
import org.apache.spark.mllib.regression.LabeledPoint
case class Obs(f1: Double, f2: Double, price: Array[String])
val obs1 = new Obs(1,2,Array("USD", "5.00"))
val obs2 = new Obs(2,1,Array("USD", "3.00"))
val df = sc.parallelize(Seq(obs1,obs2)).toDF()
df.printSchema
df.show()
val labeled = df.map(row => LabeledPoint(row.get(2).asInstanceOf[Array[String]].apply(1).toDouble, Vectors.dense(row.getDouble(0), row.getDouble(1))))
labeled.take(2).foreach(println)
输出如下:
df: org.apache.spark.sql.DataFrame = [f1: double, f2: double, price: array<string>]
root
|-- f1: double (nullable = false)
|-- f2: double (nullable = false)
|-- price: array (nullable = true)
| |-- element: string (containsNull = true)
+---+---+-----------+
| f1| f2| price|
+---+---+-----------+
|1.0|2.0|[USD, 5.00]|
|2.0|1.0|[USD, 3.00]|
+---+---+-----------+
但后来我得到了一个 ClassCastException:
java.lang.ClassCastException: scala.collection.mutable.WrappedArray$ofRef cannot be cast to [Ljava.lang.String;
我认为 ClassCastException 是由于 println。但我没想到;我该如何处理这种情况?
潜在的重复解决了我问题的一部分(谢谢),但 "promoting elements of a struct in a dataframe remain" 的更深层次的问题。我会让模组确定这是否真的是骗局。
我认为这里有问题:
.asInstanceOf[Array[String]]
让我提出一个替代解决方案,我认为它比玩所有 asInstanceOf
:
import org.apache.spark.ml.feature.VectorAssembler
import org.apache.spark.sql.Row
val assembler = new VectorAssembler()
.setInputCols(Array("f1", "f2"))
.setOutputCol("features")
val labeled = assembler.transform(df)
.select($"price".getItem(1).cast("double"), $"features")
.map{case Row(price: Double, features: Vector) =>
LabeledPoint(price, features)}
关于您的问题 ArrayType
作为 WrappedArray
存储在 Row
中,因此您会看到错误。您可以使用
import scala.collection.mutable.WrappedArray
row.getAs[WrappedArray[String]](2)
或者干脆
row.getAs[Seq[String]](2)
我有 JSON 数据集,其中包含像 "USD 5.00" 这样的字符串形式的价格。我想将数字部分转换为 Double 以在 MLLIB LabeledPoint 中使用,并设法将价格字符串拆分为字符串数组。下面创建了一个具有正确结构的数据集:
import org.apache.spark.mllib.linalg.{Vector,Vectors}
import org.apache.spark.mllib.regression.LabeledPoint
case class Obs(f1: Double, f2: Double, price: Array[String])
val obs1 = new Obs(1,2,Array("USD", "5.00"))
val obs2 = new Obs(2,1,Array("USD", "3.00"))
val df = sc.parallelize(Seq(obs1,obs2)).toDF()
df.printSchema
df.show()
val labeled = df.map(row => LabeledPoint(row.get(2).asInstanceOf[Array[String]].apply(1).toDouble, Vectors.dense(row.getDouble(0), row.getDouble(1))))
labeled.take(2).foreach(println)
输出如下:
df: org.apache.spark.sql.DataFrame = [f1: double, f2: double, price: array<string>]
root
|-- f1: double (nullable = false)
|-- f2: double (nullable = false)
|-- price: array (nullable = true)
| |-- element: string (containsNull = true)
+---+---+-----------+
| f1| f2| price|
+---+---+-----------+
|1.0|2.0|[USD, 5.00]|
|2.0|1.0|[USD, 3.00]|
+---+---+-----------+
但后来我得到了一个 ClassCastException:
java.lang.ClassCastException: scala.collection.mutable.WrappedArray$ofRef cannot be cast to [Ljava.lang.String;
我认为 ClassCastException 是由于 println。但我没想到;我该如何处理这种情况?
潜在的重复解决了我问题的一部分(谢谢),但 "promoting elements of a struct in a dataframe remain" 的更深层次的问题。我会让模组确定这是否真的是骗局。
我认为这里有问题:
.asInstanceOf[Array[String]]
让我提出一个替代解决方案,我认为它比玩所有 asInstanceOf
:
import org.apache.spark.ml.feature.VectorAssembler
import org.apache.spark.sql.Row
val assembler = new VectorAssembler()
.setInputCols(Array("f1", "f2"))
.setOutputCol("features")
val labeled = assembler.transform(df)
.select($"price".getItem(1).cast("double"), $"features")
.map{case Row(price: Double, features: Vector) =>
LabeledPoint(price, features)}
关于您的问题 ArrayType
作为 WrappedArray
存储在 Row
中,因此您会看到错误。您可以使用
import scala.collection.mutable.WrappedArray
row.getAs[WrappedArray[String]](2)
或者干脆
row.getAs[Seq[String]](2)