web-dev-qa-db-ja.com

Sparkデータフレームは、重複した名前を持つ列を区別します

したがって、Spark 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}))
]

上記の結果は、それ自体へのデータフレームとの結合によって作成されます。2つのafの両方を持つ4列があることがわかります。

問題は、a列でさらに計算しようとするとそこにあり、aを選択する方法が見つかりません。df[0]df.select('a')を試してみました。どちらもエラーメッセージの下に私を返しました:

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

とにかくSpark AP​​Iに重複した名前から列を再度区別できるAPIがありますか?または、列名を変更する方法がありますか?

53
resec

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)

結果のDataFrameschemaになります

(df1_a, df1_f, df2_a, df2_f)

純粋なpythonソリューションが必要な場合は、selectExpr()の代わりにselect()を使用できます。これにより、SQLスタイルの名前変更を使用できます。

df1.selectExpr("a as df1_a", "f as df1_f")
   .join(df2.selectExpr("a as df2_a", "f as df2_f"), ["a"])

いくつかのデータから始めましょう:

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

この問題に対処する方法はいくつかあります。まず、親列を使用して子テーブル列を明確に参照できます。

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

テーブルエイリアスを使用することもできます。

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

最後に、プログラムで列の名前を変更できます。

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

あなたが参加しているすべての列のエイリアスを書くよりも簡単な方法があります:

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

これは、結合するキーが両方のテーブルで同じ場合に機能します。

https://kb.databricks.com/data/join-two-dataframes-duplicated-columns.html を参照してください

12
Paul Bendevis

Spark AP​​Iを掘り下げた後、最初にaliasを使用して元のデータフレームのエイリアスを作成し、次にwithColumnRenamedを使用してエイリアスのすべての列の名前を手動で変更できます。これにより、列名が重複することなくjoinが実行されます。

詳細については、以下を参照してください Spark Dataframe API

pyspark.sql.DataFrame.alias

pyspark.sql.DataFrame.withColumnRenamed

しかし、これは面倒な回避策に過ぎず、私の質問にもっと良い方法があるのではないかと思います。

5
resec

def drop(col: Column)メソッドを使用して、重複した列を削除できます。次に例を示します。

DataFrame:df1

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

DataFrame:df2

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

df1とdf2を結合すると、DataFrameは次のようになります。

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

DataFrame:newDf

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

次のように、def drop(col: Column)メソッドを使用して、重複した列 'a'または 'f'を削除できます。

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

これは、PySparkで2つのデータフレーム同じ列名を結合する方法です。

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

この後にprintSchema()を実行すると、重複した列が削除されていることがわかります。

3
Nikhil Redij

結合するDataFramesがdf1とdf2であり、列 'a'で結合する場合、2つのメソッドがあります

方法1

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

これはひどい方法であり、強くお勧めします。

方法2

df1.join(df2、df1.a == df2.a、 'left_outer')。drop(df2.a)

2
typhoonbxq

これは最善のアプローチではないかもしれませんが、重複した列の名前を変更したい場合(結合後)、この小さな関数を使用して変更できます。

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