it-swarm.com.de

Spark Dataframe unterscheidet Spalten mit doppeltem Namen

Wie ich in Spark Dataframe weiß, kann dieser für mehrere Spalten denselben Namen haben, wie in der folgenden Datenframe-Momentaufnahme dargestellt:

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

Das obige Ergebnis wird durch Verbinden mit einem Datenrahmen mit sich selbst erstellt. Sie sehen, dass es 4 Spalten mit beiden a und f gibt.

Das Problem ist, wenn ich versuche, mehr mit der Spalte a zu berechnen. Ich kann keine Möglichkeit finden, die Variable a auszuwählen. Ich habe versucht df[0] und df.select('a').

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

Gibt es in Spark API überhaupt, dass ich die Spalten wieder von den duplizierten Namen unterscheiden kann? oder vielleicht eine Möglichkeit, die Spaltennamen ändern zu lassen?

39
resec

Ich würde empfehlen, dass Sie die Spaltennamen für Ihre join ändern.

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)

Die resultierende DataFrame hat schema 

(df1_a, df1_f, df2_a, df2_f)

Beginnen wir mit einigen Daten:

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

Es gibt einige Möglichkeiten, wie Sie dieses Problem angehen können. Zunächst können Sie untergeordnete Tabellenspalten mit übergeordneten Spalten eindeutig referenzieren:

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

Sie können auch Tabellen-Aliase verwenden:

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

Schließlich können Sie Spalten programmatisch umbenennen:

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

Es gibt einen einfacheren Weg, als für alle Spalten, für die Sie beitreten, Aliase zu schreiben, indem Sie Folgendes tun:

df1.join(df2,['a'])

Dies funktioniert, wenn der Schlüssel, mit dem Sie sich verbinden, in beiden Tabellen identisch ist.

Siehe https://docs.databricks.com/spark/latest/faq/join-two-dataframes-duplicated-column.html

6
Paul Bendevis

Nachdem ich mich mit der Spark-API befasst hatte, konnte ich zunächst mit alias einen Alias ​​für das ursprüngliche Datenframe erstellen. Dann benutze ich withColumnRenamed, um jede Spalte des Alias ​​manuell umzubenennen. Dadurch wird die join-Anweisung ohne Doppelung des Spaltennamens ausgeführt.

Weitere Details finden Sie unter Spark Dataframe API :

pyspark.sql.DataFrame.alias

pyspark.sql.DataFrame.withColumnRenamed

Ich denke jedoch, dass dies nur ein problematischer Workaround ist, und ich frage mich, ob es einen besseren Weg für meine Frage gibt.

5
resec

Sie können die def drop(col: Column)-Methode verwenden, um die duplizierte Spalte zu löschen, zum Beispiel:

DataFrame:df1

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

DataFrame:df2

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

wenn ich df1 mit df2 verbinde, sieht der DataFrame wie folgt aus:

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

DataFrame:newDf

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

Jetzt können wir die def drop(col: Column)-Methode verwenden, um die duplizierte Spalte 'a' oder 'f' wie folgt zu löschen:

val newDfWithoutDuplicate = df1.join(df2,df1("a")===df2("a")).drop(df2("a")).drop(df2("f"))
3
StrongYoung

Auf diese Weise können wir zwei Dataframes mit gleichen Spaltennamen in PySpark verbinden.

df = df1.join(df2, ['col1','col2','col3'])

Wenn Sie danach printSchema() ausführen, können Sie sehen, dass doppelte Spalten entfernt wurden.

1
Nikhil Redij

Angenommen, die DataFrames, an denen Sie teilnehmen möchten, sind df1 und df2, und Sie treten ihnen in Spalte 'a' bei, dann haben Sie zwei Methoden

Methode 1

df1.join (df2, 'a', 'left_outer')

Dies ist eine tolle Methode und wird dringend empfohlen.

Methode 2

df1.join (df2, df1.a == df2.a, 'left_outer'). drop (df2.a)

1
typhoonbxq

Dies ist möglicherweise nicht der beste Ansatz, aber wenn Sie die doppelten Spalten (nach dem Join) umbenennen möchten, können Sie dies mit dieser winzigen Funktion tun.

def rename_duplicate_columns(dataframe):
    columns = dataframe.columns
    duplicate_column_indices = list(set([columns.index(col) for col in columns if columns.count(col) == 2]))
    for index in duplicate_column_indices:
        columns[index] = columns[index]+'2'
    dataframe = dataframe.toDF(*columns)
    return dataframe
0
Akash