PySpark заменяет значение в нескольких столбцах одновременно - PullRequest
2 голосов
/ 12 апреля 2019

Я хочу заменить значение в столбце dataframe другим значением, и я должен сделать это для многих столбцов (скажем, 30/100 столбцов)

Я прошел this и это уже.

from pyspark.sql.functions import when, lit, col

df = sc.parallelize([(1, "foo", "val"), (2, "bar", "baz"), (3, "baz", "buz")]).toDF(["x", "y", "z"])
df.show()

# I can replace "baz" with Null separaely in column y and z
def replace(column, value):
    return when(column != value, column).otherwise(lit(None))

df = df.withColumn("y", replace(col("y"), "baz"))\
    .withColumn("z", replace(col("z"), "baz"))
df.show()    

enter image description here

Я могу заменить «baz» на Null отдельно в столбце y и z,Но я хочу сделать это для всех столбцов - что-то вроде понимания списка, как показано ниже

[replace(df[col], "baz") for col in df.columns]

Ответы [ 3 ]

2 голосов
/ 12 апреля 2019

используйте функцию reduce():

from functools import reduce

reduce(lambda d, c: d.withColumn(c, replace(col(c), "baz")), [df, 'y', 'z']).show()
#+---+----+----+
#|  x|   y|   z|
#+---+----+----+
#|  1| foo| val|
#|  2| bar|null|
#|  3|null| buz|
#+---+----+----+
1 голос
/ 12 апреля 2019

Поскольку существует 30/100 столбцов, давайте добавим еще несколько столбцов к DataFrame, чтобы хорошо его обобщить.

# Loading the requisite packages
from pyspark.sql.functions import col, when
df = sc.parallelize([(1,"foo","val","baz","gun","can","baz","buz","oof"), 
                     (2,"bar","baz","baz","baz","got","pet","stu","got"), 
                     (3,"baz","buz","pun","iam","you","omg","sic","baz")]).toDF(["x","y","z","a","b","c","d","e","f"])
df.show()
+---+---+---+---+---+---+---+---+---+ 
|  x|  y|  z|  a|  b|  c|  d|  e|  f| 
+---+---+---+---+---+---+---+---+---+ 
|  1|foo|val|baz|gun|can|baz|buz|oof| 
|  2|bar|baz|baz|baz|got|pet|stu|got| 
|  3|baz|buz|pun|iam|you|omg|sic|baz| 
+---+---+---+---+---+---+---+---+---+

Допустим, мы хотим replace baz с Null во всех столбцах, кроме столбцов x и a.Используйте list comprehensions, чтобы выбрать те столбцы, для которых необходимо выполнить replacement.

# This contains the list of columns where we apply replace() function
all_column_names = df.columns
print(all_column_names)
    ['x', 'y', 'z', 'a', 'b', 'c', 'd', 'e', 'f']
columns_to_remove = ['x','a']
columns_for_replacement = [i for i in all_column_names if i not in columns_to_remove]
print(columns_for_replacement)
    ['y', 'z', 'b', 'c', 'd', 'e', 'f']

Наконец, выполните замену, используя when(), который фактически является псевдонимом для if условие.

# Doing the replacement on all the requisite columns
for i in columns_for_replacement:
    df = df.withColumn(i,when((col(i)=='baz'),None).otherwise(col(i)))
df.show()
+---+----+----+---+----+---+----+---+----+ 
|  x|   y|   z|  a|   b|  c|   d|  e|   f| 
+---+----+----+---+----+---+----+---+----+ 
|  1| foo| val|baz| gun|can|null|buz| oof| 
|  2| bar|null|baz|null|got| pet|stu| got| 
|  3|null| buz|pun| iam|you| omg|sic|null| 
+---+----+----+---+----+---+----+---+----+

Нет необходимости создавать UDF и определять функцию для замены, если это можно сделать с помощью обычного предложения if-else.UDF с, как правило, являются дорогостоящей операцией, и ее следует избегать, когда это возможно.

1 голос
/ 12 апреля 2019

Вы можете использовать select и понимание списка:

df = df.select([replace(f.col(column), 'baz').alias(column) if column!='x' else f.col(column)
                for column in df.columns])
df.show()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...