как соединить фреймы данных с разным количеством строк

У меня есть два фрейма данных с разным количеством строк, например:

val df = sc.parallelize(Array((0, 1.0, 0.4, 0.1),
                               (1, 0.9, 0.3, 0.3),
                               (2, 0.2, 0.9, 0.2),
                               (3, 0.9, 0.2, 0.2)))
                               .toDF("id", "prop1", "prop2", "prop3")

val df2 = sc.parallelize(Array((0, 3.0, 0.2, 0.1),
                               (1, 0.9, 0.3, 0.3),
                               (2, 0.2, 0.5, 0.2),
                               (3, 0.8, 0.1, 0.1),
                               (4, 0.3, 0.5, 0.5)))
                               .toDF("id", "prop1", "prop2", "prop3")

Я хотел бы присоединиться к ним, используя столбец id в качестве ключа, поэтому я делаю:

val joined = df2.join(df, df("id")===df2("id"), "leftouter")

joined.show()

+---+-----+-----+-----+----+-----+-----+-----+
| id|prop1|prop2|prop3|  id|prop1|prop2|prop3|
+---+-----+-----+-----+----+-----+-----+-----+
|  0|  3.0|  0.2|  0.1|   0|  1.0|  0.4|  0.1|
|  1|  0.9|  0.3|  0.3|   1|  0.9|  0.3|  0.3|
|  2|  0.2|  0.5|  0.2|   2|  0.2|  0.9|  0.2|
|  3|  0.8|  0.1|  0.1|   3|  0.9|  0.2|  0.2|
|  4|  0.3|  0.5|  0.5|null| null| null| null|
+---+-----+-----+-----+----+-----+-----+-----+

на данный момент два вопроса:

  • почему добавлен второй столбец id? как я могу избавиться от него?
  • как поместить нулевые значения в ноль?

person user299791    schedule 03.02.2016    source источник


Ответы (2)


Чтобы избавиться от второго столбца «id», сначала переименуйте его:

val df = sc.parallelize(Array((0, 1.0, 0.4, 0.1),
                               (1, 0.9, 0.3, 0.3),
                               (2, 0.2, 0.9, 0.2),
                               (3, 0.9, 0.2, 0.2)))
                               .toDF("id2", "prop1", "prop2", "prop3")

Я также переименовал имена других столбцов, чтобы избежать двусмысленности (и AnalysisException).

val df2 = sc.parallelize(Array((0, 3.0, 0.2, 0.1),
                               (1, 0.9, 0.3, 0.3),
                               (2, 0.2, 0.5, 0.2),
                               (3, 0.8, 0.1, 0.1),
                               (4, 0.3, 0.5, 0.5)))
                               .toDF("id", "prop1_2", "prop2_2", "prop3_2")

Теперь drop нежелательный id2 столбец

val joined = df2.join(df, df("id2")===df2("id"), "outer").drop("id2")

Чтобы указать значение по умолчанию в случае нулей, используйте na и fill:

joined.na.fill(0).show

+---+-------+-------+-------+-----+-----+-----+
| id|prop1_2|prop2_2|prop3_2|prop1|prop2|prop3|
+---+-------+-------+-------+-----+-----+-----+
|  0|    3.0|    0.2|    0.1|  1.0|  0.4|  0.1|
|  1|    0.9|    0.3|    0.3|  0.9|  0.3|  0.3|
|  2|    0.2|    0.5|    0.2|  0.2|  0.9|  0.2|
|  3|    0.8|    0.1|    0.1|  0.9|  0.2|  0.2|
|  4|    0.3|    0.5|    0.5|  0.0|  0.0|  0.0|
+---+-------+-------+-------+-----+-----+-----+

Есть несколько способов вызвать fill, вы можете прочитать об этом в документация по API. В приведенном мной примере fill(0) заменяет нулевые значения в числовых столбцах значением 0.

person Ton Torres    schedule 03.02.2016
comment
Если вы не можете переименовать его в источнике, вы можете использовать метод withColumnRenamed для DataFrame следующим образом: val dfRenamed = df.withColumnRenamed("id", "id2"). Что касается фреймов данных, не имеющих одинакового количества строк, вы можете указать тип соединения в зависимости от того, что вам нужно. В своем ответе я указал внешний, чтобы соединение стало левым внешним соединением. - person Ton Torres; 03.02.2016
comment
да, я удалил свой комментарий, потому что понял, что withColumnRenamed() был вариант ... только что принял ваш ответ, спасибо! - person user299791; 03.02.2016

Просто чтобы добавить к ответу Торреса, вы можете выбрать только то, что вам нужно показать. Что-то вроде этого: -

joined.select(df2("id"), df("prop1"),df("prop2"),df("prop3")).na.fill(0).show()
person Sumit    schedule 03.02.2016