如何在Spark dataframe中用新列覆盖整个现有列?

17

我想用一个新的二进制标志列覆盖Spark列。

我尝试直接覆盖列id2,但为什么它不像Pandas中的就地操作一样运行?

如何在不使用withcolumn()创建新列和drop()删除旧列的情况下完成此操作?

我知道Spark DataFrame是不可变的,这是原因还是有其他方法可以在不使用withcolumn()和drop()的情况下进行覆盖?

    df2 = spark.createDataFrame(
        [(1, 1, float('nan')), (1, 2, float(5)), (1, 3, float('nan')), (1, 4, float('nan')), (1, 5, float(10)), (1, 6, float('nan')), (1, 6, float('nan'))],
        ('session', "timestamp1", "id2"))

    df2.select(df2.id2 > 0).show()

+---------+
|(id2 > 0)|
+---------+
|     true|
|     true|
|     true|
|     true|
|     true|
|     true|
|     true|
+---------+
 # Attempting to overwriting df2.id2
    df2.id2=df2.select(df2.id2 > 0).withColumnRenamed('(id2 > 0)','id2')
    df2.show()
#Overwriting unsucessful
+-------+----------+----+
|session|timestamp1| id2|
+-------+----------+----+
|      1|         1| NaN|
|      1|         2| 5.0|
|      1|         3| NaN|
|      1|         4| NaN|
|      1|         5|10.0|
|      1|         6| NaN|
|      1|         6| NaN|
+-------+----------+----+

1
Spark 无法像 Pandas 一样进行原地写入,如果您正在寻找这种功能的话。DataFrames 是不可变的结构,它们无法被覆盖。 - eliasah
3个回答

28

你可以使用

d1.withColumnRenamed("colName", "newColName")
d1.withColumn("newColName", $"colName")

withColumnRenamed 重命名现有列的名称。

withColumn 使用给定的名称创建一个新列。如果已经存在同名的列,则会创建一个新的列,并删除旧的列。

在您的情况下,更改不会应用于原始数据框df2,它更改了列的名称并返回一个新的数据框,应该将其分配给新变量以供进一步使用。

d3 = df2.select((df2.id2 > 0).alias("id2"))

上述方法在您的情况下应该可以正常工作。

希望这能帮到您!


8
如上所述,DataFrame对象是不可变集合,无法覆盖,因此所有转换都会返回新的DataFrame。
实现您想要的效果的最快方法是使用withColumn
df = df.withColumn("col", some expression)

其中col是你想要“替换”的列的名称。运行后,df变量的值将被新的DataFrame替换为列col的新值。您可能希望将其分配给新变量。

在您的情况下,它可能如下所示:

df2 = df2.withColumn("id2", (df2.id2 > 0) & (df2.id2 != float('nan')))

我已经添加了对于 nan 的比较,因为我假定你不希望将 nan 视为大于0。


id2列最初存在于df2中。因此,当我们尝试使用withColumn()创建一个具有现有名称id2的新列时,为什么它不会抛出冲突错误,比如说“id2已经存在,因此无法更改”,因为数据框是不可变的?请解释一下这个问题以及withColumn()的工作原理。 - GeorgeOfTheRF
3
如果列已经存在,withColumn()不会抛出异常。相反,它删除旧列并创建一个带有更改数据的新列。请注意,此操作将更改DataFrame的架构。 - koiralo

1
如果你正在处理不同联接表中具有相同名称的多列,可以在withColumn中的colName中使用表别名。
例如:df1.join(df2, df1.id = df2.other_id).withColumn('df1.my_col', F.greatest(df1.my_col, df2.my_col)) 如果你只想保留df1的列,也可以调用.select('df1.*') 如果你改为df1.join(df2, df1.id = df2.other_id).withColumn('my_col', F.greatest(df1.my_col, df2.my_col)),我认为它会覆盖名为my_col的最后一列。因此,输出结果如下:id, my_col (df1.my_col原始值), id, other_id, my_col (新计算的my_col)

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