【问题标题】:How to "negative select" columns in spark's dataframe如何“否定选择”火花数据框中的列
【发布时间】:2015-10-04 18:12:06
【问题描述】:

我想不通,但猜它很简单。我有一个火花数据框 df。此 df 具有列“A”、“B”和“C”。现在假设我有一个包含此 df 列名称的数组:

column_names = Array("A","B","C")

我想以这样的方式创建df.select(),以便我可以指定 选择哪些列。 示例:假设我不想选择列“B”。我试过了

df.select(column_names.filter(_!="B"))

但这不起作用,因为

org.apache.spark.sql.DataFrame 不能应用于 (Array[String])

所以,here 它说它应该与 Seq 一起使用。但是,尝试

df.select(column_names.filter(_!="B").toSeq)

结果

org.apache.spark.sql.DataFrame 不能应用于 (Seq[String])。

我做错了什么?

【问题讨论】:

    标签: scala apache-spark dataframe apache-spark-sql


    【解决方案1】:

    Since Spark 1.4你可以使用drop方法:

    斯卡拉

    case class Point(x: Int, y: Int)
    val df = sqlContext.createDataFrame(Point(0, 0) :: Point(1, 2) :: Nil)
    df.drop("y")
    

    Python

    df = sc.parallelize([(0, 0), (1, 2)]).toDF(["x", "y"])
    df.drop("y")
    ## DataFrame[x: bigint]
    

    【讨论】:

    • 谢谢!我没有意识到这一点——但我仍然在 spark 1.3 上。
    • 我想知道是否有任何方法可以按列位置删除,例如df.drop(1)df.drop(col(1))
    • @DavidArenburg df.drop(df.columns(i))?
    • 谢谢!好主意,虽然它需要方括号,如df.drop(df.columns[i])
    • @DavidArenburg Python 毕竟? :)
    【解决方案2】:

    我遇到了同样的问题并以这种方式解决了(oaffdf 是一个数据框):

    val dropColNames = Seq("col7","col121")
    val featColNames = oaffdf.columns.diff(dropColNames)
    val featCols = featColNames.map(cn => org.apache.spark.sql.functions.col(cn))
    val featsdf = oaffdf.select(featCols: _*)
    

    https://forums.databricks.com/questions/2808/select-dataframe-columns-from-a-sequence-of-string.html

    【讨论】:

      【解决方案3】:

      好的,这很丑,但是这个快速的 spark shell 会话显示了一些有用的东西:

      scala> val myRDD = sc.parallelize(List.range(1,10))
      myRDD: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[17] at parallelize at <console>:21
      
      scala> val myDF = myRDD.toDF("a")
      myDF: org.apache.spark.sql.DataFrame = [a: int]
      
      scala> val myOtherRDD = sc.parallelize(List.range(1,10))
      myOtherRDD: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[20] at parallelize at <console>:21
      
      scala> val myotherDF = myRDD.toDF("b")
      myotherDF: org.apache.spark.sql.DataFrame = [b: int]
      
      scala> myDF.unionAll(myotherDF)
      res2: org.apache.spark.sql.DataFrame = [a: int]
      
      scala> myDF.join(myotherDF)
      res3: org.apache.spark.sql.DataFrame = [a: int, b: int]
      
      scala> val twocol = myDF.join(myotherDF)
      twocol: org.apache.spark.sql.DataFrame = [a: int, b: int]
      
      scala> val cols = Array("a", "b")
      cols: Array[String] = Array(a, b)
      
      scala> val selectedCols = cols.filter(_!="b")
      selectedCols: Array[String] = Array(a)
      
      scala> twocol.select(selectedCols.head, selectedCols.tail: _*)
      res4: org.apache.spark.sql.DataFrame = [a: int]
      

      otherSO questions 中处理需要可变参数的函数。 select 的签名用于确保您的选定列列表不为空 - 这使得从选定列列表到varargs 的转换更加复杂。

      【讨论】:

        【解决方案4】:
        val columns = Seq("A","B","C")
        
        df.select(columns.diff(Seq("B")))
        

        【讨论】:

          【解决方案5】:

          在pyspark中你可以做

          df.select(list(set(df.columns) - set(["B"])))
          

          使用多行也可以

          cols = df.columns
          cols.remove("B")
          df.select(cols)
          

          【讨论】:

          • 为什么不使用 .drop() ?
          【解决方案6】:

          可以按照以下方式进行

          它使用 Spark 使用正则表达式选择列的能力。 并使用负前瞻表达式?!

          在这种情况下,数据框具有列 a、b、c 和正则表达式,不包括列表中的列 b。

          注意:您需要使用spark.sql.parser.quotedRegexColumnNames=true 会话设置为列名查找启用正则表达式。并且需要 Spark 2.3+

          select `^(?!b).*` 
          from (
             select 1 as a, 2 as b, 3 as c
          )
          

          【讨论】:

          • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
          • 更新了答案。感谢您的反馈。我最初的答案是 5 年前,所以当时我手边没有 Spark 2.3 :)
          【解决方案7】:

          对于 Spark v1.4 及更高版本,使用 drop(*cols) -

          返回没有指定列的新 DataFrame。

          例子-

          df.drop('age').collect()
          

          对于 Spark v2.3 及更高版本,您也可以使用 colRegex(colName) -

          根据指定为正则表达式的列名选择列并将其返回为Column

          例子-

          df = spark.createDataFrame([("a", 1), ("b", 2), ("c",  3)], ["Col1", "Col2"])
          df.select(df.colRegex("`(Col1)?+.+`")).show()
          

          参考 - colRegex, drop


          对于旧版本的 Spark,获取数据框中的列列表,然后删除要从中删除的列(可能使用集合操作),然后使用 select 选择结果列表。

          【讨论】:

            猜你喜欢
            • 2018-09-26
            • 1970-01-01
            • 2022-01-02
            • 2020-03-20
            • 2015-10-05
            • 2018-11-30
            • 1970-01-01
            • 1970-01-01
            • 2016-11-01
            相关资源
            最近更新 更多