【问题标题】:How to delete columns in pyspark dataframe如何删除pyspark数据框中的列
【发布时间】:2015-06-18 11:44:00
【问题描述】:
>>> a
DataFrame[id: bigint, julian_date: string, user_id: bigint]
>>> b
DataFrame[id: bigint, quan_created_money: decimal(10,0), quan_created_cnt: bigint]
>>> a.join(b, a.id==b.id, 'outer')
DataFrame[id: bigint, julian_date: string, user_id: bigint, id: bigint, quan_created_money: decimal(10,0), quan_created_cnt: bigint]

有两个id: bigint,我想删除一个。我该怎么办?

【问题讨论】:

    标签: apache-spark apache-spark-sql pyspark


    【解决方案1】:

    阅读 Spark 文档后,我发现了一个更简单的解决方案。

    从 spark 1.4 版开始,有一个函数 drop(col) 可以在数据帧上的 pyspark 中使用。

    你可以通过两种方式使用它

    1. df.drop('age')
    2. df.drop(df.age)

    Pyspark Documentation - Drop

    【讨论】:

    • 当数据量很大时,collect()可能会导致堆空间错误。您还可以创建一个新的数据框,通过 ndf = df.drop('age') 删除额外的字段
    • 绝对没有理由使用collect 进行此操作,因此我将其从该答案中删除
    【解决方案2】:

    是的,可以像这样通过切片来删除/选择列:

    slice = data.columns[a:b]

    data.select(slice).show()

    例子:

    newDF = spark.createDataFrame([
                               (1, "a", "4", 0), 
                                (2, "b", "10", 3), 
                                (7, "b", "4", 1), 
                                (7, "d", "4", 9)],
                                ("id", "x1", "x2", "y"))
    
    
    slice = newDF.columns[1:3]
    newDF.select(slice).show()
    

    使用select方法获取特征列:

    features = newDF.columns[:-1]
    newDF.select(features).show()
    

    使用drop方法获取最后一列:

    last_col= newDF.drop(*features)
    last_col.show()
    

    【讨论】:

      【解决方案3】:

      您可以像这样删除列:

      df.drop("column Name).columns
      

      在你的情况下:

      df.drop("id").columns
      

      如果你想删除不止一列,你可以这样做:

      dfWithLongColName.drop("ORIGIN_COUNTRY_NAME", "DEST_COUNTRY_NAME")
      

      【讨论】:

      • Spark 2.4(和最低版本)不接受多个列名。
      • 是否可以按索引删除列?
      • @seufagner 它只是将其作为列表传递
      【解决方案4】:

      考虑 2 个数据帧:

      >>> aDF.show()
      +---+----+
      | id|datA|
      +---+----+
      |  1|  a1|
      |  2|  a2|
      |  3|  a3|
      +---+----+
      

      >>> bDF.show()
      +---+----+
      | id|datB|
      +---+----+
      |  2|  b2|
      |  3|  b3|
      |  4|  b4|
      +---+----+
      

      要完成您正在寻找的,有两种方法:

      1.不同的加入条件。而不是说aDF.id == bDF.id

      aDF.join(bDF, aDF.id == bDF.id, "outer")
      

      这样写:

      aDF.join(bDF, "id", "outer").show()
      +---+----+----+
      | id|datA|datB|
      +---+----+----+
      |  1|  a1|null|
      |  3|  a3|  b3|
      |  2|  a2|  b2|
      |  4|null|  b4|
      +---+----+----+
      

      这将自动摆脱额外的丢弃过程。

      2。使用别名:您将在此丢失与 B 特定 ID 相关的数据。

      >>> from pyspark.sql.functions import col
      >>> aDF.alias("a").join(bDF.alias("b"), aDF.id == bDF.id, "outer").drop(col("b.id")).show()
      
      +----+----+----+
      |  id|datA|datB|
      +----+----+----+
      |   1|  a1|null|
      |   3|  a3|  b3|
      |   2|  a2|  b2|
      |null|null|  b4|
      +----+----+----+
      

      【讨论】:

        【解决方案5】:

        添加到@Patrick 的答案,您可以使用以下内容删除多列

        columns_to_drop = ['id', 'id_copy']
        df = df.drop(*columns_to_drop)
        

        【讨论】:

        • 我不得不将删除结果重新分配回数据框:df = df.drop(*columns_to_drop)
        • 注意如果列不存在不会报错
        • 我在删除一列并使用 .show() 后收到错误消息 TreeNodeException: Binding attribute, tree: _gen_alias_34#34
        • **columns_to_drop 中的星号是什么意思?
        • * 是解包列表。 (*[a,b,c]) 变为 (a,b,c)
        【解决方案6】:

        你可以使用两种方式:

        1: 您只需保留必要的列:

        drop_column_list = ["drop_column"]
        df = df.select([column for column in df.columns if column not in drop_column_list])  
        

        2:这是更优雅的方式。

        df = df.drop("col_name")
        

        你应该避免使用 collect() 版本,因为它会将完整的数据集发送给 master,需要大量的计算!

        【讨论】:

          【解决方案7】:

          执行此操作的一种简单方法是用户“select”并意识到您可以获得dataframedfdf.columns 的所有columns 的列表

          drop_list = ['a column', 'another column', ...]
          
          df.select([column for column in df.columns if column not in drop_list])
          

          【讨论】:

          • 谢谢,这对我删除与另一列同名的重复列很有用,我使用 df.select([df.columns[column_num] for column_num in range(len(df.columns)) if column_num!=2]),我要删除的列的索引为 2。
          【解决方案8】:

          也许有点离题,但这里是使用 Scala 的解决方案。从您的oldDataFrame 中创建一个列名Array,并删除您要删除("colExclude") 的列。然后将Array[Column] 传递给select 并解压。

          val columnsToKeep: Array[Column] = oldDataFrame.columns.diff(Array("colExclude"))
                                                         .map(x => oldDataFrame.col(x))
          val newDataFrame: DataFrame = oldDataFrame.select(columnsToKeep: _*)
          

          【讨论】:

            【解决方案9】:

            您可以明确命名要保留的列,如下所示:

            keep = [a.id, a.julian_date, a.user_id, b.quan_created_money, b.quan_created_cnt]
            

            或者在更一般的方法中,您可以通过列表理解包含除特定列之外的所有列。比如像这样(不包括b中的id列):

            keep = [a[c] for c in a.columns] + [b[c] for c in b.columns if c != 'id']
            

            最后你对你的加入结果做出选择:

            d = a.join(b, a.id==b.id, 'outer').select(*keep)
            

            【讨论】:

            • 我想我得到了答案。 Select 需要获取字符串列表而不是列列表。所以这样做:keep = [c for c in a.columns] + [c for c in b.columns if c != 'id']d = a.join(b, a.id==b.id, 'outer').select(*keep)
            • 嗯,这应该与我的回答完全相同,因为我很确定 select 接受字符串或列 (spark.apache.org/docs/latest/api/python/…)。顺便说一句,在您的keep = ... 行中,无需对a 使用列表理解:a.columns + [c for c in b.columns if c != 'id'] 应该实现完全相同的效果,因为a.columns 已经是字符串的list
            • @deusxmach1na 实际上,基于字符串的列选择不适用于 OP,因为这无法解决 id 列的歧义。在这种情况下,您必须使用 select 中的 Column 实例。
            • 所有优点。我在 Spark 1.3 中尝试了您的解决方案并遇到了错误,所以我发布的内容实际上对我有用。为了解决 id 歧义,我在加入之前重命名了我的 id 列,然后在加入之后使用保留列表将其删除。像我一样被卡住的其他人。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-11-26
            • 2020-10-06
            • 2021-01-01
            相关资源
            最近更新 更多