【问题标题】:Why does getInt inside RDD[Row].map give "error: value getInt is not a member of Any"?为什么 RDD[Row].map 中的 getInt 会给出“错误:值 getInt 不是 Any 的成员”?
【发布时间】:2017-10-16 15:43:51
【问题描述】:

我是 Scala-Spark 的新手,但我需要用它来开发我的最终项目学士学位。

我正在尝试从数据中构建 K-means 算法。 数据来自kaggle:https://www.kaggle.com/murderaccountability/homicide-reports

我读取了包含数据的文件。 创建一个案例类,如:

case class CrimeReport (Record_ID: String, Agency_Name: String, 
City: String, State: String, Year: Int, Month: Int, Crime_Type: String, 
Crime_Solved: String, Victim_Sex: String, Victim_Age: Int, Victim_Race: String, 
Perpetrator_Sex: String, Perpetrator_Age: String, Perpetrator_Race: String, Relationship: String, Victim_Count: String)

我将我的数据与案例类进行映射。例如,月份是字符串,我需要 Int(在我的特征向量之后创建)我定义了一个函数来解析这个:

    //Parsear Month:    String  ===>    Int
    def parseMonthToNumber(month: String) : Int = {
        var result = 0
        month match {
            case "January" => result = 1
            case "February" => result = 2
            case "March" => result = 3
            case "April" => result = 4
            case "May" => result = 5
            case "June" => result = 6
            case "July" => result = 7
            case "August" => result = 8
            case "September" => result = 9
            case "October" => result = 10
            case "November" => result = 11
            case _ => result = 12
        }
        result
    }

    data = sc.textFile (... .csv)
    val data_split = data.map(line => line.split(","))

    val allData = data_split.map(p => CrimeReport(p(0).toString,
    p(1).toString, p(2).toString, p(3).toString, parseInt(p(4)),
     parseMonthToNumber(p(5)), p(6).toString, p(7).toString, p(8).toString,
     parseInt(p(9)), p(10).toString, p(11).toString, p(12).toString,
     p(13).toString, p(14).toString, p(15).toString))
//DataFrame
val allDF = allData.toDF()

//convert data to RDD which will be passed to KMeans
val rowsRDD = allDF.rdd.map( x => 

                (x(0).getString, x.getString(1), x.getString(2), x.getString(3), x(4).getInt, x(5).getInt, x.getString(6), x.getString(7), x.getString(8), x(9).getInt, x.getString(10), x.getString(11), x.getString(12), x.getString(13), x.getString(14), x.getString(15))
                )

但我收到此错误:

error: value getInt is not a member of Any
                       (x(0).getString, x.getString(1), x.getString(2), x.getString(3), x(4).getInt, x(5).getInt, x.getString(6), x.getString(7), x.getString(8), x(9).getInt, x.getString(10), x.getString(11), x.getString(12), x.getString(13), x.getString(14), x.getString(15))
                                                                                                          ^

为什么?

【问题讨论】:

    标签: scala apache-spark k-means


    【解决方案1】:

    我假设是最新版本的Spark 2.1.1

    我先问你一个问题,既然有DataFrame-based KMeans implementation in Spark,为什么要将DataFrame转换为RDD[Row]来执行KMeans。

    阅读KMeans in Spark MLlib

    因为Spark MLlib's RDD-based API is deprecated,我不会这样做:

    此页面记录了基于 RDD 的 API(spark.mllib 包)的 MLlib 指南部分。请参阅基于 DataFrame 的 API(spark.ml 包)的 MLlib 主指南,它现在是 MLlib 的主要 API。


    话虽如此,让我们看看你面临什么问题。

    如果我是你(并且无视坚持使用 Spark MLlib 的基于 DataFrame 的 API 的建议),我会执行以下操作:

    // val allDF = allData.toDF()
    val allDF = allData.toDS
    

    使用上述方法,您将拥有一个Dataset[CrimeReport],它比纯Row 更令人愉快。

    完成转换后,你可以做

    val rowsRDD = allDF.rdd.map { x => ... }
    

    x 属于您的类型 CrimeReport,并且相信您会知道如何处理它。


    直接回答你的问题,错误原因:

    错误:值 getInt 不是 Any 的成员

    x(5)(和其他)是 Any 类型,所以您必须将其转换为您的类型,或者只需将 x(5) 替换为 x.getInt(5)

    查看Row 的scaladoc。

    【讨论】:

    • 非常感谢! :) 在您的帮助下,我能够意识到错误在哪里。有两个:首先,将DataFrame替换为DataSet;另一个是在 val rowsRDD = allDF.rdd.map { x => ... } 我必须用列的名称调用属性,即用我在案例类中定义的名称进行调用,没有位置(例如 x(5),x(6),...)
    【解决方案2】:

    当我们在案例类中处理字符串数据类型而不是双精度时,我们如何使用 kmeans?我拥有的这段代码将无法工作,因为向量需要双倍。

    // Passing in Crime_Type, Crime_Solved, Perpetrator_Race to KMeans as 
    the attributes we want to use to assign the instance to a cluster.
    
    val vectors = allDF.rdd.map(r => Vectors.dense( r.Crime_Type, r.Crime_Solved, r.Perpetrator_Race ))
    
    //KMeans model with 2 clusters and 10 iterations
    
    val kMeansModel = KMeans.train(vectors, 2, 10)
    

    【讨论】:

    • 我在新评论中回复你,只是为了你能清楚地看到格式。
    【解决方案3】:

    您应该将要在方法 Vector.dense 中使用的属性定义为 int/double

    之后,当您将案例类与文件中的数据映射时,您应该调用之前定义的函数。正如你在这里看到的:

    val data_split = data.map(line => line.split(","))
    
    val allData = data_split.map(p => 
                                    CrimeReport(p(0).toString, p(1).toString, p(2).toString, p(3).toString, parseInt(p(4)), parseMonthToNumber(p(5)), p(6).toString, parseSolved(p(7)), parseSex(p(8)), parseInt(p(9)), parseRaceToNumber(p(10)), p(11).toString, p(12).toString, p(13).toString, p(14).toString, p(15).toString))
    

    功能有:

    //Filter and Cleaning data      =>    Crime Solved
    def parseSolved (solved: String): Int = {
        var result = 0
        solved match {
            case "Yes" => result = 1
            case _ => result = 0
         }
         result
    }
    

    或者:

    //Parsear   Victim_Race:    String  ===>    Int
    def parseRaceToNumber (crType : String) : Int = {
        var result = 0
        val race = crType.split("/")
        race(0) match {
            case "White" => result = 1
            case "Black" => result = 2
            case "Asian" => result = 3
            case "Native American" => result = 4
            case _ => result = 0
        }
        result
    }
    

    【讨论】:

      猜你喜欢
      • 2020-02-06
      • 1970-01-01
      • 2021-12-20
      • 1970-01-01
      • 2016-05-14
      • 2020-05-02
      • 2014-01-07
      • 1970-01-01
      • 2022-10-22
      相关资源
      最近更新 更多