Desvincular en Spark SQL/PySpark

Resuelto Manish Mehra asked hace 7 años • 2 respuestas

Tengo a mano un planteamiento de problema en el que quiero desvincular la tabla en Spark SQL/PySpark. Revisé la documentación y pude ver que solo hay soporte para pivot, pero hasta ahora no hay soporte para despivotar. ¿Hay alguna manera de lograr esto?

Deje que mi tabla inicial se vea así:

Deja que mi tabla inicial se vea así.

Cuando hago pivotesto en PySpark:

df.groupBy("A").pivot("B").sum("C")

Obtengo esto como resultado:

Después de que la tabla dinámica se vea así

Ahora quiero desvincular la tabla dinámica. En general, esta operación puede o no producir la tabla original según cómo he pivotado la tabla original.

Spark SQL a partir de ahora no proporciona soporte listo para usar para desvincular. ¿Hay alguna manera de lograr esto?

Manish Mehra avatar Feb 26 '17 13:02 Manish Mehra
Aceptado

Puede utilizar la función de pila integrada, por ejemplo en Scala:

scala> val df = Seq(("G",Some(4),2,None),("H",None,4,Some(5))).toDF("A","X","Y", "Z")
df: org.apache.spark.sql.DataFrame = [A: string, X: int ... 2 more fields]

scala> df.show
+---+----+---+----+
|  A|   X|  Y|   Z|
+---+----+---+----+
|  G|   4|  2|null|
|  H|null|  4|   5|
+---+----+---+----+


scala> df.select($"A", expr("stack(3, 'X', X, 'Y', Y, 'Z', Z) as (B, C)")).where("C is not null").show
+---+---+---+
|  A|  B|  C|
+---+---+---+
|  G|  X|  4|
|  G|  Y|  2|
|  H|  Y|  4|
|  H|  Z|  5|
+---+---+---+

O en pyspark:

In [1]: df = spark.createDataFrame([("G",4,2,None),("H",None,4,5)],list("AXYZ"))

In [2]: df.show()
+---+----+---+----+
|  A|   X|  Y|   Z|
+---+----+---+----+
|  G|   4|  2|null|
|  H|null|  4|   5|
+---+----+---+----+

In [3]: df.selectExpr("A", "stack(3, 'X', X, 'Y', Y, 'Z', Z) as (B, C)").where("C is not null").show()
+---+---+---+
|  A|  B|  C|
+---+---+---+
|  G|  X|  4|
|  G|  Y|  2|
|  H|  Y|  4|
|  H|  Z|  5|
+---+---+---+
Andrew Ray avatar Mar 10 '2017 17:03 Andrew Ray

Chispa 3.4+

df = df.melt(['A'], ['X', 'Y', 'Z'], 'B', 'C')
#  OR
df = df.unpivot(['A'], ['X', 'Y', 'Z'], 'B', 'C')
+---+---+----+
|  A|  B|   C|
+---+---+----+
|  G|  Y|   2|
|  G|  Z|null|
|  G|  X|   4|
|  H|  Y|   4|
|  H|  Z|   5|
|  H|  X|null|
+---+---+----+

Para filtrar valores nulos:df = df.filter("C is not null")


Chispa 3.3 y por debajo

to_melt = {'X', 'Y', 'Z'}
new_names = ['B', 'C']

melt_str = ','.join([f"'{c}', `{c}`" for c in to_melt])
df = df.select(
    *(set(df.columns) - to_melt),
    F.expr(f"stack({len(to_melt)}, {melt_str}) ({','.join(new_names)})")
).filter(f"!{new_names[1]} is null")

Prueba completa:

from pyspark.sql import functions as F
df = spark.createDataFrame([("G", 4, 2, None), ("H", None, 4, 5)], list("AXYZ"))

to_melt = {'X', 'Y', 'Z'}
new_names = ['B', 'C']

melt_str = ','.join([f"'{c}', `{c}`" for c in to_melt])
df = df.select(
    *(set(df.columns) - to_melt),
    F.expr(f"stack({len(to_melt)}, {melt_str}) ({','.join(new_names)})")
).filter(f"!{new_names[1]} is null")

df.show()
# +---+---+---+
# |  A|  B|  C|
# +---+---+---+
# |  G|  Y|  2|
# |  G|  X|  4|
# |  H|  Y|  4|
# |  H|  Z|  5|
# +---+---+---+
ZygD avatar Nov 12 '2022 15:11 ZygD