web-dev-qa-db-fra.com

Comment faire pivoter plusieurs colonnes dans Spark SQL?

Je dois faire pivoter plusieurs colonnes dans un cadre de données pyspark. Échantillon de données,

 >>> d = [(100,1,23,10),(100,2,45,11),(100,3,67,12),(100,4,78,13),(101,1,23,10),(101,2,45,13),(101,3,67,14),(101,4,78,15),(102,1,23,10),(102,2,45,11),(102,3,67,16),(102,4,78,18)]
>>> mydf = spark.createDataFrame(d,['id','day','price','units'])
>>> mydf.show()
+---+---+-----+-----+
| id|day|price|units|
+---+---+-----+-----+
|100|  1|   23|   10|
|100|  2|   45|   11|
|100|  3|   67|   12|
|100|  4|   78|   13|
|101|  1|   23|   10|
|101|  2|   45|   13|
|101|  3|   67|   14|
|101|  4|   78|   15|
|102|  1|   23|   10|
|102|  2|   45|   11|
|102|  3|   67|   16|
|102|  4|   78|   18|
+---+---+-----+-----+

Maintenant, si je dois obtenir une colonne de prix dans une ligne pour chaque identifiant en fonction du jour, je peux alors utiliser la méthode pivot comme,

>>> pvtdf = mydf.withColumn('combcol',F.concat(F.lit('price_'),mydf['day'])).groupby('id').pivot('combcol').agg(F.first('price'))
>>> pvtdf.show()
+---+-------+-------+-------+-------+
| id|price_1|price_2|price_3|price_4|
+---+-------+-------+-------+-------+
|100|     23|     45|     67|     78|
|101|     23|     45|     67|     78|
|102|     23|     45|     67|     78|
+---+-------+-------+-------+-------+

donc, quand j'ai besoin d'unités de colonne aussi bien pour être transposées que de prix, soit je dois créer un dataframe supplémentaire comme ci-dessus pour les unités et ensuite joindre les deux en utilisant id.But, quand j'ai plus de colonnes en tant que telles, j'ai essayé une fonction pour le faire ,

>>> def pivot_udf(df,*cols):
...     mydf = df.select('id').drop_duplicates()
...     for c in cols:
...        mydf = mydf.join(df.withColumn('combcol',F.concat(F.lit('{}_'.format(c)),df['day'])).groupby('id').pivot('combcol').agg(F.first(c)),'id')
...     return mydf
...
>>> pivot_udf(mydf,'price','units').show()
+---+-------+-------+-------+-------+-------+-------+-------+-------+
| id|price_1|price_2|price_3|price_4|units_1|units_2|units_3|units_4|
+---+-------+-------+-------+-------+-------+-------+-------+-------+
|100|     23|     45|     67|     78|     10|     11|     12|     13|
|101|     23|     45|     67|     78|     10|     13|     14|     15|
|102|     23|     45|     67|     78|     10|     11|     16|     18|
+---+-------+-------+-------+-------+-------+-------+-------+-------+

Besoin de suggestions sur, si c'est une bonne pratique de le faire et si une autre meilleure façon de le faire. Merci d'avance!

13
Suresh

Comme dans la version spark 1.6, je pense que c'est le seul moyen car pivot ne prend qu'une seule colonne et qu'il existe deux autres valeurs d'attribut sur lesquelles vous pouvez transmettre les valeurs distinctes de cette colonne, ce qui accélérera l'exécution de votre code car sinon, spark devra l'exécuter pour vous. oui, c’est la bonne façon de le faire.

1
Ankit Kumar Namdeo

La solution à la question est la meilleure que je puisse obtenir. La seule amélioration consisterait à cache le jeu de données en entrée afin d’éviter une double analyse, c.-à-d.

mydf.cache
pivot_udf(mydf,'price','units').show()
1
Jacek Laskowski