#python #pyspark
#питон #пыспарк
Вопрос:
У меня есть набор данных, в котором каждый элемент имеет строку «диапазон от» и «диапазон до» различных типов. Например, первый элемент может иметь 1A0 -gt; 1A9, а следующий элемент может быть 3C2 -gt;gt; 5F8 и так далее (с несколькими различными шаблонами, но обычно состоящий из статического раздела и раздела диапазона (кажется, что обычно любая буква статична, а цифры могут быть статичными или нет).
Есть ли в pyspark какая-либо готовая встроенная функция, которая может справиться с генерацией промежуточных значений в диапазоне? Или если нет никаких советов о том, как его построить?
вот мой случай :
from pyspark.sql.types import * spark = SparkSession.builder.master("local[*]") .appName('SparkTest.com') .getOrCreate() data = [ ('A', ['100', '105']), ('B', ['200']), ('C', ['1A0','1A3']), ('D', ['1BB', ]), ('E', ['3C8', '3D2']) ] df = spark.createDataFrame(data, ["id", "label"], ArrayType(StringType())) df.show() --- ---------- |id |label | --- ---------- |A |[100, 105]| |B |[200] | |C |[1A0, 1A3]| |D |[1BB] | |E |[3C8, 3D2]| --- ----------
ожидаемый :
--- ----- |id |label| --- ----- |A |100 | |A |101 | |A |102 | |A |103 | |A |104 | |A |105 | |B |200 | |C |1A0 | |C |1A1 | |C |1A2 | |C |1A3 | |D |1BB | |E |3C8 | |E |3C9 | |E |3D0 | |E |3D1 | |E |3D2 | --- -----
Ответ №1:
Я бы использовал UDF, который возвращает массив полного диапазона значений, а затем использовал explode()
бы этот массив. Вот моя попытка реализовать UDF.
from pyspark.sql.functions import explode, udf @udf(returnType=ArrayType(StringType())) def generate_range(endpoints): if len(endpoints) == 1: return endpoints current, end = endpoints results = [current] # get values of each position and the modulo for the increment math base = ["0" if "0" lt;= c lt;= "9" else "A" for c in current] values = [ord(c) - ord(b) for c, b in zip(current, base)] modulo = [10 if b == "0" else 26 for b in base] while current lt; end: # increment logic idx = -1 values[idx] = 1 while values[idx] == modulo[idx]: values[idx] = 0 idx -= 1 values[idx] = 1 current = "".join(chr(v ord(b)) for v, b in zip(values, base)) results.append(current) return results df.select("id", explode(generate_range("label")).alias("label")).show() --- ----- | id|label| --- ----- | A| 100| | A| 101| | A| 102| | A| 103| | A| 104| | A| 105| | B| 200| | C| 1A0| | C| 1A1| | C| 1A2| | C| 1A3| | D| 1BB| | E| 3C8| | E| 3C9| | E| 3D0| | E| 3D1| | E| 3D2| --- -----
Примечание: Это предполагает, что длина элементов в диапазоне не будет увеличиваться в течение диапазона, и если это произойдет, произойдет сбой. Дайте мне знать, если это предположение неверно.