Заполнение фрейма данных pyspark нулевыми значениями

#python #dataframe #pyspark

#python #фрейм данных #pyspark

Вопрос:

У меня есть фрейм данных pyspark, который содержит 4 столбца.

  ----- ----- ----- ----- 
|col1 |col2 |col3 |col4 |
 ----- ----- ----- ----- 
|10   | 5.0 | 5.0 | 5.0 |
|20   | 5.0 | 5.0 | 5.0 |
|null | 5.0 | 5.0 | 5.0 |
|30   | 5.0 | 5.0 | 6.0 |
|40   | 5.0 | 5.0 | 7.0 |
|null | 5.0 | 5.0 | 8.0 |
|50   | 5.0 | 6.0 | 9.0 |
|60   | 5.0 | 7.0 | 10.0|
|null | 5.0 | 8.0 | 11.0|
|70   | 6.0 | 9.0 | 12.0|
|80   | 7.0 | 10.0| 13.0|
|null | 8.0 | 11.0| 14.0|
 ----- ----- ----- ----- 
  

Некоторые значения в col1 отсутствуют, и я хочу установить эти недостающие значения на основе следующего подхода:

попробуйте установить его на основе среднего значения col1 записей, которые имеют одинаковые значения col2, col3, col4

если такой записи нет, задайте ее на основе среднего значения col1 записей, которые имеют одинаковые значения col2, col3

если такой записи по-прежнему нет, установите ее на основе среднего значения col1 записей, имеющих одинаковые значения col2

Если ничего из вышеперечисленного не удалось найти, установите для него среднее значение всех других не пропущенных значений в col1

Например, учитывая фрейм данных выше, только первые две строки имеют те же значения col2, col3, col4, что и строка 3. Таким образом, значение null в col1 для строки 3 следует заменить средним значением col1 в строках 1 и 2. Для значения null в col1 в строке 6 это будет среднее значение col1 в строках 4 и 5, потому что только эти строки имеют одинаковые значения col2 и col3, а не одинаковые значения col4, как в строке 6. И этот список можно продолжить…

  ----- ----- ----- ----- 
|col1 |col2 |col3 |col4 |
 ----- ----- ----- ----- 
|10   | 5.0 | 5.0 | 5.0 |
|20   | 5.0 | 5.0 | 5.0 |
|15   | 5.0 | 5.0 | 5.0 |
|30   | 5.0 | 5.0 | 6.0 |
|40   | 5.0 | 5.0 | 7.0 |
|25   | 5.0 | 5.0 | 8.0 |
|50   | 5.0 | 6.0 | 9.0 |
|60   | 5.0 | 7.0 | 10.0|
|35   | 5.0 | 8.0 | 11.0|
|70   | 6.0 | 9.0 | 12.0|
|80   | 7.0 | 10.0| 13.0|
|45   | 8.0 | 11.0| 14.0|
 ----- ----- ----- ----- 
  

Каков наилучший способ сделать это?

Комментарии:

1. For null value in col1 in row 6 почему вы не считаете строку 1,2,3? Похоже, что ваш вывод не соответствует вашим правилам.

2. @Steven Вы правы, я отредактировал вопрос.

Ответ №1:

Я не нахожу точно таких же значений, как у вас, но, основываясь на том, что вы сказали, код будет примерно таким :

 from pyspark.sql import functions as F

df_2_3_4 = df.&roupBy("col2", "col3", "col4").a&&(
    F.av&("col1").alias("av&_col1_by_2_3_4")
)
df_2_3 = df.&roupBy("col2", "col3").a&&(F.av&("col1").alias("av&_col1_by_2_3"))
df_2 = df.&roupBy("col2").a&&(F.av&("col1").alias("av&_col1_by_2"))
av&_value = df.&roupBy().a&&(F.av&("col1").alias("av&_col1")).first().av&_col1


df_out = (
    df.join(df_2_3_4, how="left", on=["col2", "col3", "col4"])
    .join(df_2_3, how="left", on=["col2", "col3"])
    .join(df_2, how="left", on=["col2"])
)

df_out.select(
    F.coalesce(
        F.col("col1"),
        F.col("av&_col1_by_2_3_4"),
        F.col("av&_col1_by_2_3"),
        F.col("av&_col1_by_2"),
        F.lit(av&_value),
    ).alias("col1"),
    "col2",
    "col3",
    "col4",
).show()

 ---- ---- ---- ---- 
|col1|col2|col3|col4|
 ---- ---- ---- ---- 
|10.0| 5.0| 5.0| 5.0|
|15.0| 5.0| 5.0| 5.0|
|20.0| 5.0| 5.0| 5.0|
|30.0| 5.0| 5.0| 6.0|
|40.0| 5.0| 5.0| 7.0|
|25.0| 5.0| 5.0| 8.0|
|50.0| 5.0| 6.0| 9.0|
|60.0| 5.0| 7.0|10.0|
|35.0| 5.0| 8.0|11.0|
|70.0| 6.0| 9.0|12.0|
|80.0| 7.0|10.0|13.0|
|45.0| 8.0|11.0|14.0|
 ---- ---- ---- ----