Как объединить два фрейма данных в общих столбцах в R с суммой других? - PullRequest
22 голосов
/ 24 апреля 2011

R Версия 2.11.1 32-разрядная в Windows 7

Я получил два набора данных: data_A и data_B:

data_A

USER_A USER_B ACTION
1      11     0.3
1      13     0.25
1      16     0.63
1      17     0.26
2      11     0.14
2      14     0.28

data_B

USER_A USER_B ACTION
1      13     0.17
1      14     0.27
2      11     0.25

Теперь я хочу добавить ДЕЙСТВИЕ data_B к data_A, если их USER_A и USER_B равны.Как и в примере выше, результат будет:

data_A

USER_A USER_B ACTION
1      11     0.3
1      13     0.25+0.17
1      16     0.63
1      17     0.26
2      11     0.14+0.25
2      14     0.28

Так как же я могу достичь этого?

Ответы [ 3 ]

16 голосов
/ 24 апреля 2011

Вы можете использовать ddply в упаковке plyr и комбинировать его с merge:

library(plyr)
ddply(merge(data_A, data_B, all.x=TRUE), 
  .(USER_A, USER_B), summarise, ACTION=sum(ACTION))

Обратите внимание, что merge вызывается с параметром all.x=TRUE - это возвращает все значения в первом data.frame, переданном в merge, т.е. data_A:

  USER_A USER_B ACTION
1      1     11   0.30
2      1     13   0.25
3      1     16   0.63
4      1     17   0.26
5      2     11   0.14
6      2     14   0.28
15 голосов
/ 24 апреля 2011

Подобные вещи довольно легко сделать с помощью операций, подобных базам данных.Здесь я использую пакет sqldf, чтобы выполнить левое (внешнее) соединение, а затем суммировать полученный объект:

require(sqldf)
tmp <- sqldf("select * from data_A left join data_B using (USER_A, USER_B)")

Это приводит к:

> tmp
  USER_A USER_B ACTION ACTION
1      1     11   0.30     NA
2      1     13   0.25   0.17
3      1     16   0.63     NA
4      1     17   0.26     NA
5      2     11   0.14   0.25
6      2     14   0.28     NA

Теперь нам просто нужно сложитьдва ACTION столбца:

data_C <- transform(data_A, ACTION = rowSums(tmp[, 3:4], na.rm = TRUE))

, что дает желаемый результат:

> data_C
  USER_A USER_B ACTION
1      1     11   0.30
2      1     13   0.42
3      1     16   0.63
4      1     17   0.26
5      2     11   0.39
6      2     14   0.28

Это можно сделать с помощью стандартной функции R merge:

> merge(data_A, data_B, by = c("USER_A","USER_B"), all.x = TRUE)
  USER_A USER_B ACTION.x ACTION.y
1      1     11     0.30       NA
2      1     13     0.25     0.17
3      1     16     0.63       NA
4      1     17     0.26       NA
5      2     11     0.14     0.25
6      2     14     0.28       NA

Таким образом, мы можем заменить приведенный выше вызов sqldf() на:

tmp <- merge(data_A, data_B, by = c("USER_A","USER_B"), all.x = TRUE)

, в то время как вторая строка, использующая transform(), останется прежней.

1 голос
/ 03 марта 2019

Я написал пакет safejoin , который решает это очень кратко:

# devtools::install_github("moodymudskipper/safejoin")
library(safejoin)
safe_left_join(data_A,data_B, by = c("USER_A", "USER_B"), 
               conflict = ~ .x+ ifelse(is.na(.y),0,.y))
#   USER_A USER_B ACTION
# 1      1     11   0.30
# 2      1     13   0.42
# 3      1     16   0.63
# 4      1     17   0.26
# 5      2     11   0.39
# 6      2     14   0.28

В случае конфликта функция, переданная в аргумент conflict, будетиспользоваться на парах конфликтующих столбцов

...