it-swarm.com.ru

Spark Dataframe различает столбцы с дублированным именем

Итак, как я знаю в 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}))
]

Приведенный выше результат создается путем соединения с самим фреймом данных, вы можете видеть, что есть столбцы 4 с двумя a и f.

Проблема в том, что когда я пытаюсь сделать больше вычислений со столбцом a, я не могу найти способ выбрать a, я пробовал df[0] и df.select('a'), оба вернули меня ниже сообщения об ошибке:

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

Есть ли так или иначе в Spark API, что я могу снова отличить столбцы от дублированных имен? или, может быть, какой-нибудь способ позволить мне изменить имена столбцов?

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

Результирующий DataFrame будет иметь schema 

(df1_a, df1_f, df2_a, df2_f)
35
Glennie Helles Sindholt

Начнем с некоторых данных:

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

Существует более простой способ, чем написание псевдонимов для всех столбцов, к которым вы присоединяетесь, выполнив:

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

Это работает, если ключ, к которому вы присоединяетесь, одинаков в обеих таблицах.

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

6
Paul Bendevis

После поиска в Spark API я обнаружил, что сначала могу использовать 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"))
3
StrongYoung

Вот как мы можем объединить два Dataframes с одинаковыми именами столбцов в PySpark.

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

Если вы выполните printSchema() после этого, то увидите, что повторяющиеся столбцы были удалены.

1
Nikhil Redij

Предположим, что к фреймам данных, к которым вы хотите присоединиться, относятся df1 и df2, и вы объединяете их в столбце «a», тогда у вас есть 2 метода

Метод 1

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

Это потрясающий метод, и он настоятельно рекомендуется.

Метод 2

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

1
typhoonbxq