Разбиение столбца типа структуры на два столбца ключей и значений в pyspark - PullRequest
1 голос
/ 14 марта 2020

У меня есть pyspark df, схема которого выглядит следующим образом

 root
 |-- company: struct (nullable = true)
 |    |-- 0: string (nullable = true)
 |    |-- 1: string (nullable = true)
 |    |-- 10: string (nullable = true)
 |    |-- 100: string (nullable = true)
 |    |-- 101: string (nullable = true)
 |    |-- 102: string (nullable = true)
 |    |-- 103: string (nullable = true)
 |    |-- 104: string (nullable = true)
 |    |-- 105: string (nullable = true)
 |    |-- 106: string (nullable = true)
 |    |-- 107: string (nullable = true)
 |    |-- 108: string (nullable = true)
 |    |-- 109: string (nullable = true)

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

id    name
0     "foo"
1     "laa"
10    "bar"
100   "gee"
101   "yoo"
102    "koo"

вместо

  0        1         10       100      101        102 
"foo"    "laa"      "bar"    "gee"    "yoo"      "koo"

это то, что я получаю, используя расширение 'col. *'

Я нашел ответ по этой ссылке Как разбить StructType на строки из json в кадре данных в Spark, а не на столбцы

но это scala искра, а не pyspark. Я не знаком с концепцией сокращения карты, чтобы сам поменять сценарий на pyspark.

Я прикрепляю образец кадра данных в аналогичной схеме и структуре ниже ..

from pyspark.sql import *
Employee = Row('employee1', 'employee2', 'employee3', 'employee4', 'employee5')
Salaries = Row('100000', '120000', '140000', '160000', '160000')

departmentWithEmployees1 = Row(employees=[Employee, Salaries])

departmentsWithEmployees_Seq = [departmentWithEmployees1]
dframe = spark.createDataFrame(departmentsWithEmployees_Seq)
dframe.show()

Структура структуры этот фрейм данных похож на этот

root
 |-- employees: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- _1: string (nullable = true)
 |    |    |-- _2: string (nullable = true)
 |    |    |-- _3: string (nullable = true)
 |    |    |-- _4: string (nullable = true)
 |    |    |-- _5: string (nullable = true)

Как я хочу, чтобы мой окончательный фрейм данных был таким

Firstname         Salary
employee1         10000
employee2         120000

Ответы [ 2 ]

1 голос
/ 15 марта 2020

Это можно сделать с помощью двух простых операторов i-1027 *.

Обратите внимание, что два предоставленных вами примера немного отличаются, во втором примере структура col находится внутри массива col.

Я расскажу о более сложном, но для первого (и оригинального df) вы можете пропустить первый оператор выбора.

dframe\
.selectExpr('employees[0] AS `key`', 'employees[1] AS `value`')\
.select(
    F.explode(F.map_from_arrays(F.array('key.*'),F.array('value.*'))
             ).alias('Firstname','Salary')
)

Я попытаюсь объяснить логику c ниже.

root
 |-- employees: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- _1: string (nullable = true)
 |    |    |-- _2: string (nullable = true)
 |    |    |-- _3: string (nullable = true)
 |    |    |-- _4: string (nullable = true)
 |    |    |-- _5: string (nullable = true)

Глядя на схему выше, вам нужно сделать следующее:

1) Свести первый столбец массива, чтобы отобразить struct

2) Повернуть оба struct столбцов на две array столбцов, создайте один столбец map с map_from_arrays() столбиками и взорвитесь.

map_from_arrays() берет один элемент из одной и той же позиции из обоих array столбцов (думаю, Python zip()).

Дайте мне знать, если это поможет!

1 голос
/ 14 марта 2020

Сначала используйте element_at, чтобы получить столбцы firstname и salary, затем преобразуйте их из структуры в массив, используя F.array и F.arrays_zip столбцы, прежде чем explode, а затем select все взорвалось колонки на молнии.

from pyspark.sql import functions as F
dframe.withColumn("firstname", F.element_at("employees", 1))\
.withColumn("salary",F.element_at("employees",2))\
.drop("employees")\
.withColumn("firstname",F.array("firstname.*"))\
.withColumn("salary", F.array("salary.*"))\
.withColumn("zip",F.explode(F.arrays_zip("firstname","salary")))\
.select("zip.*").show(truncate=False)

+---------+------+
|firstname|salary|
+---------+------+
|employee1|100000|
|employee2|120000|
|employee3|140000|
|employee4|160000|
|employee5|160000|
+---------+------+
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...