web-dev-qa-db-de.com

Apache Spark - Weisen Sie das Ergebnis der UDF mehreren Datenrahmenspalten zu

Ich verwende pyspark, lade eine große csv-Datei in einen Datenrahmen mit spark-csv und muss als Vorverarbeitungsschritt eine Reihe von Operationen auf die in einer der Spalten verfügbaren Daten anwenden (die eine JSON-Zeichenfolge enthalten). . Dadurch werden X-Werte zurückgegeben, von denen jeder in einer eigenen separaten Spalte gespeichert werden muss.

Diese Funktionalität wird in einer UDF implementiert. Ich bin mir jedoch nicht sicher, wie ich eine Liste von Werten aus dieser UDF zurückgeben und diese in einzelne Spalten einspeisen soll. Unten ist ein einfaches Beispiel:

(...)
from pyspark.sql.functions import udf
def udf_test(n):
    return [n/2, n%2]

test_udf=udf(udf_test)


df.select('amount','trans_date').withColumn("test", test_udf("amount")).show(4)

Das ergibt folgendes:

+------+----------+--------------------+
|amount|trans_date|                test|
+------+----------+--------------------+
|  28.0|2016-02-07|         [14.0, 0.0]|
| 31.01|2016-02-07|[15.5050001144409...|
| 13.41|2016-02-04|[6.70499992370605...|
| 307.7|2015-02-17|[153.850006103515...|
| 22.09|2016-02-05|[11.0450000762939...|
+------+----------+--------------------+
only showing top 5 rows

Was wäre der beste Weg, um die beiden (in diesem Beispiel) Werte, die vom udf zurückgegeben werden, in separaten Spalten zu speichern? Im Moment werden sie als Zeichenfolgen eingegeben:

df.select('amount','trans_date').withColumn("test", test_udf("amount")).printSchema()

root
 |-- amount: float (nullable = true)
 |-- trans_date: string (nullable = true)
 |-- test: string (nullable = true)
38
Everaldo Aguiar

Es ist nicht möglich, mehrere Spalten der obersten Ebene mit einem einzigen UDF-Aufruf zu erstellen, Sie können jedoch ein neues struct erstellen. Es erfordert eine UDF mit dem angegebenen returnType:

from pyspark.sql.functions import udf
from pyspark.sql.types import *

schema = StructType([
    StructField("foo", FloatType(), False),
    StructField("bar", FloatType(), False)
])

def udf_test(n):
    return (n / 2, n % 2) if n and n != 0.0 else (float('nan'), float('nan'))

test_udf = udf(udf_test, schema)
df = sc.parallelize([(1, 2.0), (2, 3.0)]).toDF(["x", "y"])

foobars = df.select(test_udf("y").alias("foobar"))
foobars.printSchema()
## root
##  |-- foobar: struct (nullable = true)
##  |    |-- foo: float (nullable = false)
##  |    |-- bar: float (nullable = false)

Sie reduzieren das Schema mit einfachem select weiter:

foobars.select("foobar.foo", "foobar.bar").show()
## +---+---+
## |foo|bar|
## +---+---+
## |1.0|0.0|
## |1.5|1.0|
## +---+---+

Siehe auch Leiten Sie mehrere Spalten aus einer einzelnen Spalte in einem Spark DataFrame ab

58
zero323