我正在使用Spark Book跟踪机器学习并尝试将python代码转换为scala代码并使用Beaker笔记本共享变量,以便将值传递给python以使用matplotlib进行绘图,如本书所述。到目前为止,我已经能够转换大部分代码,但我在使用try-catch
数据集进行数据清理的u.item
转换时遇到了一些问题。下面的代码以无限循环结束,没有明确的错误是什么。
val movieData = sc.textFile("/Users/minHenry/workspace/ml-100k/u.item")
val movieDataSplit = movieData.first()
val numMovies = movieData.count()
def convertYear(x:String):Int = x.takeRight(4) match {
case x => x.takeRight(4).toInt
case _ => 1900
}
val movieFields = movieData.map(lines => lines.split('|'))
print(movieData.first())
val years1 = movieFields.map(fields => fields(2))
val years = movieFields.map(fields => fields(2).map(x=>convertYear(x.toString())))
val filteredYears = years.filter(x => x!=1900)
years.take(2).foreach(println)
我怀疑我的问题与我的模式匹配有关,但我不确定它的错误。我认为takeRight()
有效,因为它并没有抱怨这个函数被应用的类型。
更新
根据迄今为止提供的答案,我已根据以下建议更新了代码:
import scala.util.Try
val movieData = sc.textFile("/Users/minHenry/workspace/ml-100k/u.item")
def convertYear(x:String):Int = Try(x.toInt).getOrElse(1900)
val movieFields = movieData.map(lines => lines.split('|'))
val preYears = movieFields.map(fields => fields(2))
val years = preYears.map(x => x.takeRight(4))//.map(x=>convertYear(x))
println("=======> years")
years.take(2).foreach(println) //--output = 1995/n1995
println("=======> filteredYears")
val filteredYears = years.filter(x => x!=1900)
filteredYears.take(2).foreach(println)
//val movieAges = filteredYears.map(yr => (1998-yr)).countByValue()
我在map
之后注释了takeRight(4)
因为它比放置x=>convertYear(x.takeRight(4))
更容易评论,并且应该产生相同的输出。当我应用这个convertYear()
函数时,我仍然以无限循环结束。值显示在所显示的几个打印语句中。问题是如果我无法删除无法轻易转换为Int的数据点,那么我无法在最后一行运行countByValue()
函数。
以下是我的公共烧杯笔记本的链接以获取更多背景信息: https://pub.beakernotebook.com/#/publications/56eed31d-85ad-4728-a45d-14b3b08d673f
答案 0 :(得分:1)
movieData: RDD[String]
movieFields: RDD[Array[String]]
years1: RDD[String]
val years = movieFields.map(fields => fields(2).map(x=>convertYear(x.toString())))
- fields(2)
为String
,因此x
为Char
,因为String
被视为Seq[Char]
。 convertYear(x: String)
的所有输入只有一个字母字符串。 您的错误是类型不兼容隐藏(convertYear(x.toString())
)。它是警钟。始终在scala中使用类型系统,不要隐藏toString()
或isInstanceOf
或其他内容的问题。然后编译器在运行之前显示错误。
P.S。
takeRight
的第二次通话毫无用处。 def convertYear(x:String):Int = x.takeRight(4) match {
case x => x.takeRight(4).toInt
case _ => 1900
}
模式匹配是关于检查类型或条件(使用if语句)。你的第一个部分功能没有检查任何东西。所有输入都转到x.takeRight(4).toInt
。此外,没有针对toInt
例外的辩护。
请改用def convertYear(x: String): Int = Try(x.toInt).getOrElse(1900)
。
<强>更新强>
scala> import scala.util.Try
import scala.util.Try
scala> def convertYear(x:String):Int = Try(x.toInt).getOrElse(1900)
convertYear: (x: String)Int
scala> List("sdsdf", "1989", "2009", "1945", "asdf", "455")
res0: List[String] = List(sdsdf, 1989, 2009, 1945, asdf, 455)
scala> res0.map(convertYear)
res1: List[Int] = List(1900, 1989, 2009, 1945, 1900, 455)
与RDD完全相同,因为它是一个类似于List的函子。
val filteredYears = years.filter(x => x!=1900)
无法按预期工作。 x
是String而不是Int。 Scala没有隐式转换类型进行比较。所以你总是得到true
。