したがって、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つのa
とf
の両方を持つ4
列があることがわかります。
問題は、a
列でさらに計算しようとするとそこにあり、a
を選択する方法が見つかりません。df[0]
とdf.select('a')
を試してみました。どちらもエラーメッセージの下に私を返しました:
AnalysisException: Reference 'a' is ambiguous, could be: a#1333L, a#1335L.
とにかくSpark APIに重複した名前から列を再度区別できるAPIがありますか?または、列名を変更する方法がありますか?
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)
結果のDataFrame
はschema
になります
(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...|
## +--------------------+
あなたが参加しているすべての列のエイリアスを書くよりも簡単な方法があります:
df1.join(df2,['a'])
これは、結合するキーが両方のテーブルで同じ場合に機能します。
https://kb.databricks.com/data/join-two-dataframes-duplicated-columns.html を参照してください
Spark APIを掘り下げた後、最初にalias
を使用して元のデータフレームのエイリアスを作成し、次にwithColumnRenamed
を使用してエイリアスのすべての列の名前を手動で変更できます。これにより、列名が重複することなくjoin
が実行されます。
詳細については、以下を参照してください Spark Dataframe API :
pyspark.sql.DataFrame.withColumnRenamed
しかし、これは面倒な回避策に過ぎず、私の質問にもっと良い方法があるのではないかと思います。
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"))
これは、PySparkで2つのデータフレーム同じ列名を結合する方法です。
df = df1.join(df2, ['col1','col2','col3'])
この後にprintSchema()
を実行すると、重複した列が削除されていることがわかります。
結合する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)
これは最善のアプローチではないかもしれませんが、重複した列の名前を変更したい場合(結合後)、この小さな関数を使用して変更できます。
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