21

Così come ho di comunicare in Spark dataframe, che per più colonne possono avere lo stesso nome, come mostrato in seguito dataframe snapshot:Spark dataframe distinguere le colonne con il nome duplicato

[ 
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})) 
] 

Sopra risultato è stato creato da unire con un dataframe a sé stesso, puoi vedere che ci sono 4 colonne con entrambi i due a e f.

Il problema è c'è quando provo a fare di più di calcolo con la colonna a, non posso trovare un modo per selezionare il a, ho cercare df[0] e df.select('a'), entrambi mi ha restituito sotto l'errore mesaage:

AnalysisException: Reference 'a' is ambiguous, could be: a#1333L, a#1335L. 

C'è comunque nell'API Spark che posso distinguere nuovamente le colonne dai nomi duplicati? o forse un modo per farmi cambiare i nomi delle colonne?

risposta

13

mi sento di raccomandare di cambiare i nomi delle colonne per il vostro 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 risultante DataFrame avrà schema

(df1_a, df1_f, df2_a, df2_f) 
+0

Grazie, la risposta è una soluzione molto semplice alla mia domanda! – resec

+0

Potrebbe essere necessario correggere la risposta poiché le virgolette non sono regolate correttamente tra i nomi delle colonne. –

+0

@SamehSharaf Suppongo che tu sia l'unico a votare la mia risposta? Ma la risposta è in realtà corretta al 100% - sto semplicemente usando lo scala '' -shorthand per la selezione delle colonne, quindi non c'è alcun problema con le virgolette. –

3

Dopo scavare API Spark, ho trovato che posso utilizzare prima alias per creare un alias per il dataframe originale quindi utilizzare withColumnRename per rinominare manualmente ogni colonna di alias, infine fare il join senza causare il nome della colonna duplicazione.

Maggiori dettagli si riferiscono a seguito Spark Dataframe API:

pyspark.sql.DataFrame.alias

pyspark.sql.DataFrame.withColumnRenamed

Tuttavia, penso che questa è solo una soluzione problematica, e si chiede se ci sia un modo migliore per la mia domanda .

39

Iniziamo con alcuni dati:

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})), 
]) 

Ci sono alcuni modi s puoi affrontare questo problema.Prima di tutto si può senza ambiguità riferimento alle colonne della tabella del bambino utilizzando le colonne genitore:

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

è anche possibile utilizzare gli alias di tabella:

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

Infine è possibile a livello di codice rinominare le colonne:

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...| 
## +--------------------+ 
+3

Grazie per il tuo editing per mostrare così tanti modi di ottenere la colonna corretta in questi casi ambigui, penso che i tuoi esempi dovrebbero andare nella guida alla programmazione Spark. Ho imparato molto! – resec

1

È possibile utilizzare il metodo def drop(col: Column) per eliminare la colonna duplicata, ad esempio:

DataFrame:df1 

+-------+-----+ 
| a  | f | 
+-------+-----+ 
|107831 | ... | 
|107831 | ... | 
+-------+-----+ 

DataFrame:df2 

+-------+-----+ 
| a  | f | 
+-------+-----+ 
|107831 | ... | 
|107831 | ... | 
+-------+-----+ 

quando mi unisco df1 con DF2, il dataframe sarà come di seguito:

val newDf = df1.join(df2,df1("a")===df2("a")) 

DataFrame:newDf 

+-------+-----+-------+-----+ 
| a  | f | a  | f | 
+-------+-----+-------+-----+ 
|107831 | ... |107831 | ... | 
|107831 | ... |107831 | ... | 
+-------+-----+-------+-----+ 

Ora, possiamo usare def drop(col: Column) metodo per eliminare la colonna duplicata 'a' o 'f', proprio come nel seguente modo:

val newDfWithoutDuplicate = df1.join(df2,df1("a")===df2("a")).drop(df2("a")).drop(df2("f")) 
Problemi correlati