web-dev-qa-db-fra.com

Supprimer les colonnes en double après un DF rejoindre dans Spark

Lorsque vous joignez deux DF avec des noms de colonne similaires:

df = df1.join(df2, df1['id'] == df2['id'])

La jointure fonctionne bien, mais vous ne pouvez pas appeler la colonne id car elle est ambiguë et vous obtiendrez l'exception suivante:

pyspark.sql.utils.AnalysisException: "Reference 'id' is ambiguous, could be: id#5691, id#5918.;"

Cela rend id plus utilisable ...

La fonction suivante résout le problème:

def join(df1, df2, cond, how='left'):
    df = df1.join(df2, cond, how=how)
    repeated_columns = [c for c in df1.columns if c in df2.columns]
    for col in repeated_columns:
        df = df.drop(df2[col])
    return df

Ce que je n'aime pas, c'est que je dois parcourir les noms des colonnes et les supprimer par un. Cela semble vraiment maladroit ...

Connaissez-vous une autre solution permettant de joindre et de supprimer les doublons de manière plus élégante ou de supprimer plusieurs colonnes sans itérer sur chacune d’elles?

10
thecheech

Si les colonnes de jointure des deux trames de données portent les mêmes noms et que vous avez seulement besoin de joindre équi, vous pouvez spécifier les colonnes de jointure sous forme de liste. Dans ce cas, le résultat ne conservera qu'une des colonnes de jointure:

df1.show()
+---+----+
| id|val1|
+---+----+
|  1|   2|
|  2|   3|
|  4|   4|
|  5|   5|
+---+----+

df2.show()
+---+----+
| id|val2|
+---+----+
|  1|   2|
|  1|   3|
|  2|   4|
|  3|   5|
+---+----+

df1.join(df2, ['id']).show()
+---+----+----+
| id|val1|val2|
+---+----+----+
|  1|   2|   2|
|  1|   2|   3|
|  2|   3|   4|
+---+----+----+

Sinon, vous devez donner les données de jointure alias et faire référence aux colonnes dupliquées par le alias plus tard:

df1.alias("a").join(
    df2.alias("b"), df1['id'] == df2['id']
).select("a.id", "a.val1", "b.val2").show()
+---+----+----+
| id|val1|val2|
+---+----+----+
|  1|   2|   2|
|  1|   2|   3|
|  2|   3|   4|
+---+----+----+
9
Psidom

Le code ci-dessous fonctionne avec Spark 1.6.0 et supérieur.

salespeople_df.show()
+---+------+-----+
|Num|  Name|Store|
+---+------+-----+
|  1| Henry|  100|
|  2| Karen|  100|
|  3|  Paul|  101|
|  4| Jimmy|  102|
|  5|Janice|  103|
+---+------+-----+

storeaddress_df.show()
+-----+--------------------+
|Store|             Address|
+-----+--------------------+
|  100|    64 E Illinos Ave|
|  101|         74 Grand Pl|
|  102|          2298 Hwy 7|
|  103|No address available|
+-----+--------------------+

En supposant, dans cet exemple, que le nom de la colonne partagée est le même:

joined=salespeople_df.join(storeaddress_df, ['Store'])
joined.orderBy('Num', ascending=True).show()

+-----+---+------+--------------------+
|Store|Num|  Name|             Address|
+-----+---+------+--------------------+
|  100|  1| Henry|    64 E Illinos Ave|
|  100|  2| Karen|    64 E Illinos Ave|
|  101|  3|  Paul|         74 Grand Pl|
|  102|  4| Jimmy|          2298 Hwy 7|
|  103|  5|Janice|No address available|
+-----+---+------+--------------------+

.join empêchera la duplication de la colonne partagée.

Supposons que vous souhaitiez supprimer la colonne Num dans cet exemple, vous pouvez simplement utiliser .drop('colname')

joined=joined.drop('Num')
joined.show()

+-----+------+--------------------+
|Store|  Name|             Address|
+-----+------+--------------------+
|  103|Janice|No address available|
|  100| Henry|    64 E Illinos Ave|
|  100| Karen|    64 E Illinos Ave|
|  101|  Paul|         74 Grand Pl|
|  102| Jimmy|          2298 Hwy 7|
+-----+------+--------------------+
1
hussam

En supposant que 'a' est un cadre de données avec la colonne 'id' et 'b' est un autre cadre de données avec la colonne 'id'

J'utilise les deux méthodes suivantes pour supprimer les doublons:

Méthode 1: Utilisation de l'expression de jointure de chaîne par opposition à l'expression booléenne. Cela supprime automatiquement une colonne en double pour vous

a.join(b, 'id')

Méthode 2: renommer la colonne avant la jointure et la supprimer après

b.withColumnRenamed('id', 'b_id')
joinexpr = a['id'] == b['b_id']
a.join(b, joinexpr).drop('b_id)
1
Heapify