web-dev-qa-db-fra.com

Spark Dataframe distingue les colonnes avec un nom dupliqué

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?

39
resec

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)
35

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...|
## +--------------------+
60
zero323

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

6
Paul Bendevis

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.alias

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.

5
resec

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"))
3
StrongYoung

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.

1
Nikhil Redij

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)

1
typhoonbxq