Фрейм данных pyspark получает второе самое низкое значение для каждой строки - PullRequest
2 голосов
/ 02 марта 2020

Я хотел бы спросить, если у кого есть идея, как получить второе наименьшее значение в строке Dataframe в pyspark.

Например:

Входной Dataframe :

Col1  Col2  Col3  Col4 
83    32    14    62   
63    32    74    55   
13    88     6    46   

Ожидаемый результат :

Col1  Col2  Col3  Col4 Res
83    32    14    62   32   
63    32    74    55   55   
13    88     6    46   13

Спасибо

Ответы [ 2 ]

2 голосов
/ 03 марта 2020

Мы можем использовать функцию concat_ws для объединения всех столбцов строки, а затем использовать split для создания массива.

использовать array_sort функция для сортировки в массиве и извлечения second element[1] массива.

Example:

from pyspark.sql.functions import *

df=spark.createDataFrame([('83','32','14','62'),('63','32','74','55'),('13','88','6','46')],['Col1','Col2','Col3','Col4'])

df.selectExpr("array_sort(split(concat_ws(',',Col1,Col2,Col3,Col4),','))[1] Res").show()

#+---+
#|Res|
#+---+
#|32 |
#|55 |
#|13 |
#+---+

More Dynamic Way:

df.selectExpr("array_sort(split(concat_ws(',',*),','))[1]").show()

#+---+
#|Res|
#+---+
#|32 |
#|55 |
#|13 |
#+---+

EDIT:

#adding Res column to the dataframe
df1=df.selectExpr("*","array_sort(split(concat_ws(',',*),','))[1] Res")
df1.show()

#+----+----+----+----+---+
#|Col1|Col2|Col3|Col4|Res|
#+----+----+----+----+---+
#|  83|  32|  14|  62| 32|
#|  63|  32|  74|  55| 55|
#|  13|  88|   6|  46| 46|
#+----+----+----+----+---+
1 голос
/ 03 марта 2020

Вы можете создать столбец массива с помощью функции array, а затем отсортировать его с помощью array_sort. Наконец, получите второй элемент, используя element_at. Эти 2 последние функции доступны в Spark 2.4+.

df.withColumn("res", element_at(array_sort(array(*[col(c) for c in df.columns])), 2))\
  .show()

#+----+----+----+----+---+
#|Col1|Col2|Col3|Col4|res|
#+----+----+----+----+---+
#|83  |32  |14  |62  |32 |
#|63  |32  |74  |55  |55 |
#|13  |88  |6   |46  |13 |
#+----+----+----+----+---+

Другой способ - использовать функцию least. Сначала вычислите минимальное значение из всех столбцов, а затем в другой раз вычислите наименьшее из значений, которые больше min, используя выражение when:

df.withColumn("min", least(*[col(c) for c in df.columns]))\
  .withColumn("res", least(*[when(col(c) > col("min"), col(c)) for c in df.columns]))\
  .drop("min")\
  .show()
...