Объединение значений по столбцам и pyspark и поворот

#pyspark #pivot

#pyspark #сводная

Вопрос:

У меня есть pypark df вот так:

  ------- ------- ----------- ----------- ----------- ----------- ----------- ----------- 
| SEQ_ID|TOOL_ID|kurtosis_1m|kurtosis_2m|kurtosis_3m|kurtosis_4m|kurtosis_5m|kurtosis_6m|
 ------- ------- ----------- ----------- ----------- ----------- ----------- ----------- 
|3688539|  99725|     6.7484|     6.2753|     6.2055|     7.2076|     7.0501|     7.5099|
|3689076|  99705|     4.8109|     4.3774|     4.1131|     4.4084|     4.1568|     4.4445|
 ------- ------- ----------- ----------- ----------- ----------- ----------- ----------- 
  

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

  ------- ------- ----------- 
| SEQ_ID|TOOL_ID|kurtosis   |
 ------- ------- ----------- 
|3688539|  99725|     6.7484|
|3688539|  99725|     6.2753|
|3688539|  99725|     6.2055|
|3688539|  99725|     7.2076|
|3688539|  99725|     7.0501|
|3688539|  99725|     7.5099|
|3689076|  99705|     4.8109|
|3689076|  99705|     4.3774|
|3689076|  99705|     4.1131|
|3689076|  99705|     4.4084|
|3689076|  99705|     4.1568|
|3689076|  99705|     4.4445|
 ------- ------- ----------- 
  

Я подумал, что одним из способов было бы создать kurtosis столбец как столбец массива, а затем развернуть его. Как объединить значения столбцов в фрейме данных в один столбец в виде массива.
У меня есть другие столбцы, такие как mean_1m , mean_2m и т.д. … которые мне нужно повернуть таким же образом.
Есть идеи?
Спасибо

Ответ №1:

Вы можете создать массив фреймов данных и объединить их.

Сначала определите kurtosis столбцы:

 sub_string = "kurtosis"
kurtosis_col = [x for x in df.schema.names if sub_string in x]
  

Теперь создайте массив фреймов данных, равный количеству kurtosis столбцов:

 from functools import reduce
from pyspark.sql import DataFrame
from pyspark.sql.functions import col

df_array = [df.withColumn('col', F.concat(F.col(x)))
                .select('seq_id', 'tool_id', 'col') for x in kurtosis_col]

# Union them
reduce(DataFrame.unionAll, df_array).withColumnRenamed("col", "kurtosis").show()
  

Вывод:

  ------- ------- -------- 
| seq_id|tool_id|kurtosis|
 ------- ------- -------- 
|3688539|  99725|  6.7484|
|3688539|  99725|  7.2076|
|3688539|  99725|  6.2753|
|3688539|  99725|  6.2055|
|3688539|  99725|  7.5099|
|3688539|  99725|  7.0501|
|3689076|  99705|  4.4084|
|3689076|  99705|  4.1131|
|3689076|  99705|  4.8109|
|3689076|  99705|  4.4445|
|3689076|  99705|  4.3774|
|3689076|  99705|  4.1568|
 ------- ------- -------- 
  

Вы можете следовать аналогичному подходу для других установленных столбцов, таких как mean_1m , и т.д. Один из способов объединить их обратно и избежать дублирования — использовать row_number() и monotonically_increasing_id() перед объединением. Дайте мне знать, если вам нужен этот фрагмент кода.

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

1. Я думаю, что использование встроенной array функции pyspark может быть проще. Спасибо за ваше решение, Cena. Я действительно ценю это!

Ответ №2:

Вы можете использовать array для объединения нескольких столбцов в один массив, а затем — как вы уже описали в своем вопросе — разбить массив.

 from pyspark.sql import functions as F

cols = [x for x in df.schema.names if "kurtosis" in x]

df.withColumn("kurtosis", F.explode(F.array(cols))) 
    .drop(*cols) 
    .show()
  

Вывод:

  ------- ------- -------- 
| SEQ_ID|TOOL_ID|kurtosis|
 ------- ------- -------- 
|3688539|  99725|  6.7484|
|3688539|  99725|  6.2753|
|3688539|  99725|  6.2055|
|3688539|  99725|  7.2076|
|3688539|  99725|  7.0501|
|3688539|  99725|  7.5099|
|3689076|  99705|  4.8109|
|3689076|  99705|  4.3774|
|3689076|  99705|  4.1131|
|3689076|  99705|  4.4084|
|3689076|  99705|  4.1568|
|3689076|  99705|  4.4445|
 ------- ------- -------- 
  

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

1. if string in x подбирает все слова с буквами. Как мне заставить его выбрать точное слово? Например if 'UL' in x , выбирает столбцы с именами UL , и MUL я хочу, чтобы он выбирал только UL

2. @thentangler замените in на a == , как вы бы сделали в обычном условии if. Некоторые примеры можно найти здесь