嗨,您能在Pyspark中创建新列时帮我解决问题吗?我解释了以下问题:

时间:2018-10-20 12:00:26

标签: pyspark pyspark-sql

我正在使用的查询:

我想在条件上用新值替换现有列,如果另一个col的值= ABC,则该列保持不变,否则应为null或空白。 按逻辑给出结果,但仅针对循环中遇到的最后一列。

import pyspark.sql.functions as F

for i in df.columns:
    if i[4:]!='ff':        
        new_df=df.withColumn(i,F.when(df.col_ff=="abc",df[i])\
       .otherwise(None))

df:
+------+----+-----+-------+
| col1 |col2|col3 | col_ff|
+------+----+-----+-------+
|   a  | a  | d   | abc   |
|   a  | b  | c   | def   |
|   b  | c  | b   | abc   |
|   c  | d  | a   | def   |
+------+----+-----+-------+

必需的输出:

+------+----+-----+-------+
| col1 |col2|col3 | col_ff|
+------+----+-----+-------+
|   a  | a  | d   | abc   |
| null |null|null | def   |
|   b  | c  | b   | abc   |
| null |null|null | def   |
+------+----+-----+-------+

1 个答案:

答案 0 :(得分:1)

代码中的问题是,在循环的每次迭代中,您都用原始DataFrame new_df覆盖了df。您可以先在循环外设置new_df = df,然后在循环内对withColumn进行new_df操作来解决此问题。

例如,如果df为以下内容:

df.show()
#+----+----+----+------+
#|col1|col2|col3|col_ff|
#+----+----+----+------+
#|   a|   a|   d|   abc|
#|   a|   b|   c|   def|
#|   b|   c|   b|   abc|
#|   c|   d|   a|   def|
#+----+----+----+------+

将代码更改为:

import pyspark.sql.functions as F

new_df = df
for i in df.columns:
    if i[4:]!='ff':        
        new_df = new_df.withColumn(i, F.when(F.col("col_ff")=="abc", F.col(i)))

请注意,我删除了.otherwise(None)部分,因为如果不满足条件,when将默认返回null

您也可以使用functools.reduce做同样的事情:

from functools import reduce  # for python3
new_df = reduce(
    lambda df, i: df.withColumn(i, F.when(F.col("col_ff")=="abc", F.col(i))),
    [i for i in df.columns if i[4:] != "ff"], 
    df
)

在两种情况下结果都是相同的:

new_df.show()
#+----+----+----+------+
#|col1|col2|col3|col_ff|
#+----+----+----+------+
#|   a|   a|   d|   abc|
#|null|null|null|   def|
#|   b|   c|   b|   abc|
#|null|null|null|   def|
#+----+----+----+------+