如何在Pyspark DataFrame中删除列

158
>>> 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,我想删除其中一个。该怎么做?

9个回答

192

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

自从Spark 1.4版本以来,就有一个名为drop(col)的函数,可以在数据框中使用Pyspark进行操作。

你可以用两种方式来使用它:

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

Pyspark文档 - Drop


33
当数据量较大时,collect()可能会导致堆空间错误。你还可以通过 ndf = df.drop('age') 创建一个删除了额外字段的新数据帧。 - mnis.p
2
完全没有必要在这个操作中使用 collect,所以我从答案中将其删除了。 - qwr

157

除了@Patrick的答案,你还可以使用以下方法删除多列

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

4
我需要重新将删除后的结果分配回数据框中:df = df.drop(*columns_to_drop)。 - avgbody
1
请注意,如果列不存在,您将不会收到错误提示。 - Guido
在删除一列并使用.show()后,我遇到了一个错误,提示TreeNodeException: Binding attribute, tree: _gen_alias_34#34 - frlzjosh
2
*columns_to_drop 中,星号 * 代表什么意思? - Juan-Kabbali
3
* 用来解包列表。(*[a,b,c]) 变为 (a,b,c) - Clock Slave

36

一个简单的方法是使用 "select" 并意识到您可以通过 df.columns 获取 dataframe 的所有 columns 列表。

drop_list = ['a column', 'another column', ...]

df.select([column for column in df.columns if column not in drop_list])

1
谢谢,这对我来说非常有效,因为它可以删除与另一列具有相同名称的重复列,其中我使用 df.select([df.columns[column_num] for column_num in range(len(df.columns)) if column_num!=2]),其中我想要删除的列的索引是2。 - Shane Halloran

24

您可以有两种方式:

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()版本,因为它会将完整的数据集发送到主节点,这会耗费大量的计算资源!


14

您可以明确地命名您想要保留的列,例如:

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) - deusxmach1na
好的,那应该和我的答案完全一样,因为我非常确定 select 可以接受字符串或列 (https://spark.apache.org/docs/latest/api/python/pyspark.sql.html#pyspark.sql.DataFrame)。顺便说一下,在你的代码行 keep = ... 中,对于 a 来说没有必要使用列表推导式:a.columns + [c for c in b.columns if c != 'id'] 应该可以实现完全相同的功能,因为 a.columns 已经是一个字符串列表了。 - karlson
@deusxmach1na 实际上,基于字符串的列选择对于 OP 来说是行不通的,因为这样无法解决“id”列的歧义。在这种情况下,您必须在“select”中使用“Column”实例。 - karlson
所有的观点都很好。我在Spark 1.3中尝试了你的解决方案,但出现了错误,所以我发布的实际上对我有用。为了解决id的歧义,我在连接之前重命名了我的id列,然后使用keep列表在连接之后删除了它。希望这能帮助像我一样卡住的人。 - deusxmach1na

4
也许有些偏题,但以下是使用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: _*)

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()

0

您可以像这样删除列:

df.drop("column Name).columns

在你的情况下:
df.drop("id").columns

如果您想删除多个列,可以执行以下操作:

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

1
Spark 2.4(及以上版本)不接受多个列名。 - seufagner
能否按索引删除列? - DataBach
1
@seufagner 它只是将其作为列表传递。 - Topde

-1

考虑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|
+----+----+----+

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接