Самый эффективный способ выполнить пользовательское горячее кодирование на фрейме данных PySpark? - PullRequest
0 голосов
/ 06 июня 2019

Допустим, у нас есть этот фрейм данных PySpark:

+----+-------------+
| id | string_data |
+----+-------------+
| 1  | "test"      |
+----+-------------+
| 2  | null        |
+----+-------------+
| 3  | "9"         |
+----+-------------+
| 4  | "deleted__" |

Я хочу выполнить некоторую операцию, которая приведет к этому фрейму данных:

+----+-------------+---------------------+-------------------------+---------------------------------------+-----------------------+
| id | string_data | is_string_data_null | is_string_data_a_number | does_string_data_contain_keyword_test | is_string_data_normal |
+----+-------------+---------------------+-------------------------+---------------------------------------+-----------------------+
| 1  | "test"      | 0                   | 0                       | 1                                     | 0                     |
+----+-------------+---------------------+-------------------------+---------------------------------------+-----------------------+
| 2  | null        | 1                   | 0                       | 0                                     | 0                     |im
+----+-------------+---------------------+-------------------------+---------------------------------------+-----------------------+
| 3  | "9"         | 0                   | 1                       | 0                                     | 0                     |
+----+-------------+---------------------+-------------------------+---------------------------------------+-----------------------+
| 4  | "deleted__" | 0                   | 0                       | 0                                     | 1                     |
+----+-------------+---------------------+-------------------------+---------------------------------------+-----------------------+
|    |             |                     |                         |                                       |                       |
+----+-------------+---------------------+-------------------------+---------------------------------------+-----------------------+

Где каждый из новых столбцовимеет 1 или 0 в зависимости от значения истинности.В настоящее время я реализовал это с помощью пользовательской пользовательской функции, которая проверяет значение столбца string_data, но это невероятно медленно.Я также попытался реализовать UDF, который не создает новые столбцы, а вместо этого перезаписывает исходный с закодированным вектором [1, 0, 0 ...] и т. Д. Это также слишком медленно, потому что мы должны применить это к миллионамстроки и тысячи столбцов.

Есть ли лучший способ сделать это?Я понимаю, что UDF - не самый эффективный способ решения проблем в PySpark, но я не могу найти какие-либо встроенные функции PySpark, которые работают.

Любые мысли приветствуются!

1 Ответ

2 голосов
/ 06 июня 2019

Редактировать : Извините, с мобильного телефона я не увидел ожидаемого результата полностью, поэтому мой предыдущий ответ был очень неполным.

В любом случае, ваша операция должна выполняться в два этапа, начиная с этого кадра данных:

>>> df.show()
+---+-----------+
| id|string_data|
+---+-----------+
|  1|       test|
|  2|       null|
|  3|          9|
|  4|  deleted__|
+---+-----------+
  1. Создание логических полей на основе условий в поле string_data:
>>> df = (df
    .withColumn('is_string_data_null', df.string_data.isNull())
    .withColumn('is_string_data_a_number', df.string_data.cast('integer').isNotNull())
    .withColumn('does_string_data_contain_keyword_test', coalesce(df.string_data, lit('')).contains('test'))
    .withColumn('is_string_normal', ~(col('is_string_data_null') | col('is_string_data_a_number') | col('does_string_data_contain_keyword_test')))
    )
>>> df.show()
+---+-----------+-------------------+-----------------------+-------------------------------------+----------------+
| id|string_data|is_string_data_null|is_string_data_a_number|does_string_data_contain_keyword_test|is_string_normal|
+---+-----------+-------------------+-----------------------+-------------------------------------+----------------+
|  1|       test|              false|                  false|                                 true|           false|
|  2|       null|               true|                  false|                                false|           false|
|  3|          9|              false|                   true|                                false|           false|
|  4|  deleted__|              false|                  false|                                false|            true|
+---+-----------+-------------------+-----------------------+-------------------------------------+----------------+
  1. Теперь, когда у нас есть столбцы, мы можем привести их к целым числам:
>>> df = (df
    .withColumn('is_string_data_null', df.is_string_data_null.cast('integer'))
    .withColumn('is_string_data_a_number', df.is_string_data_a_number.cast('integer'))
    .withColumn('does_string_data_contain_keyword_test', df.does_string_data_contain_keyword_test.cast('integer'))
    .withColumn('is_string_normal', df.is_string_normal.cast('integer'))
    )
>>> df.show()
+---+-----------+-------------------+-----------------------+-------------------------------------+----------------+
| id|string_data|is_string_data_null|is_string_data_a_number|does_string_data_contain_keyword_test|is_string_normal|
+---+-----------+-------------------+-----------------------+-------------------------------------+----------------+
|  1|       test|                  0|                      0|                                    1|               0|
|  2|       null|                  1|                      0|                                    0|               0|
|  3|          9|                  0|                      1|                                    0|               0|
|  4|  deleted__|                  0|                      0|                                    0|               1|
+---+-----------+-------------------+-----------------------+-------------------------------------+----------------+

Это должно быть гораздо более производительным, чем UDF, так как все операции выполняются самим Spark, поэтому переключение контекста с Spark на Python отсутствует.

...