Donc, comme je le sais dans Spark Dataframe, pour plusieurs colonnes, le nom doit être identique à celui présenté ci-dessous: instantané de dataframe:
[
Row(a=107831, f=SparseVector(5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0}), a=107831, f=SparseVector(5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0})),
Row(a=107831, f=SparseVector(5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0}), a=125231, f=SparseVector(5, {0: 0.0, 1: 0.0, 2: 0.0047, 3: 0.0, 4: 0.0043})),
Row(a=107831, f=SparseVector(5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0}), a=145831, f=SparseVector(5, {0: 0.0, 1: 0.2356, 2: 0.0036, 3: 0.0, 4: 0.4132})),
Row(a=107831, f=SparseVector(5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0}), a=147031, f=SparseVector(5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0})),
Row(a=107831, f=SparseVector(5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0}), a=149231, f=SparseVector(5, {0: 0.0, 1: 0.0032, 2: 0.2451, 3: 0.0, 4: 0.0042}))
]
Le résultat ci-dessus est créé par jointure avec une structure de données à elle-même. Vous pouvez voir qu'il existe des colonnes 4
avec à la fois deux variables a
et f
.
Le problème est que lorsque j'essaie de faire plus de calculs avec la colonne a
, je ne trouve pas le moyen de sélectionner la a
, j’ai essayé df[0]
et df.select('a')
.
AnalysisException: Reference 'a' is ambiguous, could be: a#1333L, a#1335L.
Y at-il de toute façon dans Spark API que je peux distinguer à nouveau les colonnes des noms dupliqués? ou peut-être un moyen de me laisser changer les noms de colonne?
Je vous recommande de changer les noms de colonne pour votre join
df1.select('a as "df1_a", 'f as "df1_f")
.join(df2.select('a as "df2_a", 'f as "df2_f"), 'df1_a === 'df2_a)
La DataFrame
résultante aura schema
(df1_a, df1_f, df2_a, df2_f)
Commençons par quelques données:
from pyspark.mllib.linalg import SparseVector
from pyspark.sql import Row
df1 = sqlContext.createDataFrame([
Row(a=107831, f=SparseVector(
5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0})),
Row(a=125231, f=SparseVector(
5, {0: 0.0, 1: 0.0, 2: 0.0047, 3: 0.0, 4: 0.0043})),
])
df2 = sqlContext.createDataFrame([
Row(a=107831, f=SparseVector(
5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0})),
Row(a=107831, f=SparseVector(
5, {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0})),
])
Vous pouvez aborder ce problème de plusieurs manières. Tout d’abord, vous pouvez référencer sans ambiguïté les colonnes d’une table enfant à l’aide de colonnes parent:
df1.join(df2, df1['a'] == df2['a']).select(df1['f']).show(2)
## +--------------------+
## | f|
## +--------------------+
## |(5,[0,1,2,3,4],[0...|
## |(5,[0,1,2,3,4],[0...|
## +--------------------+
Vous pouvez également utiliser des alias de table:
from pyspark.sql.functions import col
df1_a = df1.alias("df1_a")
df2_a = df2.alias("df2_a")
df1_a.join(df2_a, col('df1_a.a') == col('df2_a.a')).select('df1_a.f').show(2)
## +--------------------+
## | f|
## +--------------------+
## |(5,[0,1,2,3,4],[0...|
## |(5,[0,1,2,3,4],[0...|
## +--------------------+
Enfin, vous pouvez renommer les colonnes par programme:
df1_r = df1.select(*(col(x).alias(x + '_df1') for x in df1.columns))
df2_r = df1.select(*(col(x).alias(x + '_df2') for x in df2.columns))
df1_r.join(df2_r, col('a_df1') == col('a_df2')).select(col('f_df1')).show(2)
## +--------------------+
## | f_df1|
## +--------------------+
## |(5,[0,1,2,3,4],[0...|
## |(5,[0,1,2,3,4],[0...|
## +--------------------+
Il existe un moyen plus simple que d'écrire des alias pour toutes les colonnes que vous rejoignez:
df1.join(df2,['a'])
Cela fonctionne si la clé à laquelle vous vous associez est la même dans les deux tables.
Voir https://docs.databricks.com/spark/latest/faq/join-two-dataframes-duplicated-column.html
Après avoir exploré l’API de Spark, j’ai découvert que je pouvais d’abord utiliser alias
pour créer un alias pour le dataframe d’origine, puis utiliser withColumnRenamed
pour renommer manuellement toutes les colonnes de l’alias. Le join
sera créé sans provoquer la duplication du nom de colonne.
Pour plus de détails, voir ci-dessous API Spark Dataframe :
pyspark.sql.DataFrame.withColumnRenamed
Cependant, je pense qu’il s’agit là d’une solution de contournement gênante, et je me demande s’il existe un meilleur moyen de répondre à ma question.
Vous pouvez utiliser la méthode def drop(col: Column)
pour supprimer la colonne dupliquée, par exemple:
DataFrame:df1
+-------+-----+
| a | f |
+-------+-----+
|107831 | ... |
|107831 | ... |
+-------+-----+
DataFrame:df2
+-------+-----+
| a | f |
+-------+-----+
|107831 | ... |
|107831 | ... |
+-------+-----+
quand je rejoins df1 avec df2, le DataFrame sera comme ci-dessous:
val newDf = df1.join(df2,df1("a")===df2("a"))
DataFrame:newDf
+-------+-----+-------+-----+
| a | f | a | f |
+-------+-----+-------+-----+
|107831 | ... |107831 | ... |
|107831 | ... |107831 | ... |
+-------+-----+-------+-----+
Maintenant, nous pouvons utiliser la méthode def drop(col: Column)
pour supprimer la colonne dupliquée 'a' ou 'f', comme suit:
val newDfWithoutDuplicate = df1.join(df2,df1("a")===df2("a")).drop(df2("a")).drop(df2("f"))
C'est comment nous pouvons joindre deux Dataframes sur les mêmes noms de colonne dans PySpark.
df = df1.join(df2, ['col1','col2','col3'])
Si vous exécutez printSchema()
après cela, vous pouvez voir que les colonnes en double ont été supprimées.
Supposons que les DataFrames que vous voulez rejoindre soient df1 et df2, et que vous les rejoigniez sur la colonne 'a', vous avez alors 2 méthodes
Méthode 1
df1.join (df2, 'a', 'left_outer')
C'est une méthode géniale et elle est fortement recommandée.
Méthode 2
df1.join (df2, df1.a == df2.a, 'left_outer'). drop (df2.a)