J'ai le dataframe suivant

val input = Seq(("ZZ","a","a","b","b"),
("ZZ","a","b","c","d"),
("YY","b","e",null,"f"),
("YY","b","b",null,"f"),
("VV","a",null,"",""))
.toDF("main","value1","value2","value3","value4")
input.show()

+----+------+------+------+------+
|main|value1|value2|value3|value4|
+----+------+------+------+------+
|  ZZ|     a|     a|     b|     b|
|  ZZ|     a|     b|     c|     d|
|  YY|     b|     e|  null|     f|
|  YY|     b|     b|  null|     f|
|  VV|     a|  null|      |      |
+----+------+------+------+------+

J'ai fait ce qui suit pour aplatir les données

val newdf = input.select('main,array('value1,'value2,'value3,'value4).alias("values"))
.groupBy('main).agg(collect_set('values).alias("values"))
.select('main, flatten($"values").alias("values"))
newdf.show()

+----+--------------------+
|main|              values|
+----+--------------------+
|  ZZ|[a, a, b, b, a, b...|
|  YY|[b, e,, f, b, b,, f]|
|  VV|            [a,, , ]|
+----+--------------------+

Maintenant, je dois choisir chaque combinaison unique d'éléments en tant que paire dans le tableau et les avoir sous forme de lignes de données séparées. Donc, pour le dataframe donné ci-dessus, le résultat sera

+----+------+------+
|main|value1|value2|
+----+------+------+
|  ZZ|     a|     b|
|  ZZ|     a|     c|
|  ZZ|     a|     d|
|  ZZ|     b|     c|
|  ZZ|     d|     c|
|  YY|     b|     f|
|  YY|     b|     e|
|  YY|     e|     f|
|  VV|     a|      |
+----+------+------+

Comment réduire la colonne aux éléments uniques que je peux diviser en lignes distinctes?

1
Ajay Sangamithran 27 août 2020 à 15:23

2 réponses

Meilleure réponse

Utilisez explode deux fois et filtrez.

val newdf = input.select('main,array('value1,'value2,'value3,'value4).alias("values"))
.groupBy('main).agg(flatten(collect_set('values)).alias("values"))
.withColumn("value1", explode(array_distinct('values)))
.withColumn("value2", explode(array_distinct('values)))
.filter("value1 < value2")
.select('main, 'value1, 'value2)
newdf.show()

+----+------+------+
|main|value1|value2|
+----+------+------+
|  ZZ|     a|     b|
|  ZZ|     a|     c|
|  ZZ|     a|     d|
|  ZZ|     b|     c|
|  ZZ|     b|     d|
|  ZZ|     c|     d|
|  YY|     b|     e|
|  YY|     b|     f|
|  YY|     e|     f|
|  VV|      |     a|
+----+------+------+
2
Lamanus 27 août 2020 à 13:24

I need to pick every unique combination of items as a pair, comme si ZZ a des valeurs [a, b, c, d] alors essentiellement vous allez créer 6 paires (4 en choisir 2)? Dans ce cas, vous souhaiterez peut-être créer un UDAF (fonction d'agrégation définie par l'utilisateur).

input
.select('main,array('value1,'value2,'value3,'value4).alias("values"))
.groupBy('main).agg(<here comes your UDAF>)

Cet UDAF doit être tel qu'il collecte les valeurs sous la forme d'un ensemble (ou liste alors .distinct) et produit toutes les paires de combinaisons (peut être fait avec 2 boucles for).

Après ce point, votre dataframe devrait ressembler à

+----+------------------------------------+
|main|              values                |
+----+------------------------------------+
|  ZZ|[(a,b),(a,c),(a,d),(b,c),(b,d),(c,d)|
+----+------------------------------------+

Ensuite, vous pouvez .explode() pour obtenir un dataframe comme

+----+-------+
|main|values |
+----+-------+
|  ZZ|(a,b)  |
+----+-------+
|  ZZ|(a,c)  |
+----+-------+
|  ZZ|(a,d)  |
+----+-------+
|  ZZ|(b,c)  |
+----+-------+
|  ZZ|(b,d)  |
+----+-------+
|  ZZ|(c,d)  |
+----+-------+

Ensuite, vous pouvez définir la colonne value1 comme première valeur de ce tuple et la colonne value2 comme deuxième valeur.

0
Samir Vyas 27 août 2020 à 12:47