Pyspark udf возвращает один столбец в определениях условий, принимая несколько столбцов в качестве входных данных

Я использую искру 2.1 и использую pyscripting

Постановка проблемы: есть сценарий, в котором необходимо передать несколько столбцов в качестве входных данных и вернуть один столбец в качестве выходных данных. Ниже приведен мой входной фрейм данных из 3 столбцов.

a b c

S S S

S NS NS

S NS S

S S NS

NS S NS

мой вывод должен быть таким, как показано ниже

a b c d

S S S S

S NS NS NS

S NS S S

S S NS NS

NS S NS NS

Я пытаюсь зарегистрировать UDF для передачи этих 3 столбцов [a, b, c] в качестве ввода и возврата столбца d в ​​качестве вывода здесь a, b, c, d - это имена столбцов.

Мне трудно получить вывод ниже, это используемый синтаксис

def return_string(x):
      if [x.a=='s' & x.b=='S' & x.c=='s']
          return 'S'
      else if[x.a=='s' & x.b=='NS' & x.c=='s']
          return 'S'
      else if[x.a=='s' & x.b=='S' & x.c=='NS']
          return 'NS;

func= udf(returnstring,types.StringType())

Может ли кто-нибудь помочь мне в завершении этой логики.


person user3292373    schedule 23.08.2017    source источник
comment
Все ли три столбца важны? Для этого примера выходных данных он, кажется, зависит только от C.   -  person Steven Laan    schedule 23.08.2017
comment
Возможный дубликат Pyspark: передать несколько столбцов в UDF   -  person Steven Laan    schedule 23.08.2017
comment
Да, все три важны, так как упущена еще одна логика, если x.a=='NS' & x.b=='S' | x.c=='NS' возвращает 'NS', но то, что вы упомянули, подходит для этого примера вывода, другие столбцы можно рассматривать только   -  person user3292373    schedule 23.08.2017


Ответы (2)


Я пытался сделать это, используя встроенный withColumn и when функции:

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

df.withColumn('d', when(
     ((col('A') == 'S') & (col('B') == 'S') & (col('C')=='S'))
   | ((col('A') == 'S') & (col('B') == 'NS') & (col('C')=='S'))
 , lit('S')
 ).otherwise(lit('NS'))
).show()

Это также предполагает, что два значения являются взаимоисключающими (отсюда и otherwise)

person Steven Laan    schedule 23.08.2017

Должен быть:

@udf
def return_string(a, b, c):
    if a == 's' and b == 'S' and c == 's':
        return 'S'
    if a == 's' and b == 'NS' and c == 's':
        return 'S'
    if a == 's' and b == 'S' and c == 'NS':
        return 'NS'

df = sc.parallelize([('s', 'S', 'NS'), ('?', '?', '?')]).toDF(['a', 'b', 'c'])

df.withColumn('result', return_string('a', 'b', 'c')).show()
## +---+---+---+------+
## |  a|  b|  c|result|
## +---+---+---+------+
## |  s|  S| NS|    NS|
## |  ?|  ?|  ?|  null|
## +---+---+---+------+
  • Все аргументы должны быть перечислены (если вы не передаете данные как struct).
  • Вы должны использовать and, а не & (вы оцениваете логические выражения, а не выражения SQL).
  • Условия должны быть выражениями, а не списками (непустой список всегда правдив).

Лично я бы пропустил все ifs и использовал простой dict:

@udf
def return_string(a, b, c):
    mapping = {
        ('s', 'S', 's'): 'S',
        ('s', 'NS' 's'): 'S',
        ('s', 'S', 'NS'): 'NS',
    }
    return mapping.get((a, b, c))

Настройте условия в соответствии с вашими требованиями.

В целом вам следует предпочесть выражения SQL, как показано в отличном ответе, предоставленном Стивеном Лааном (вы можете связать несколько условий с помощью when(..., ...).when(..., ...)).

person Alper t. Turker    schedule 23.08.2017