Использование полного объединения для сопоставления значений в двух разных кадрах данных

#r #join #merge #match

Вопрос:

У меня есть два кадра данных.Первый фрейм данных состоит из четырех столбцов: 1) Идентификатор, 2) Местоположение, 3) Глубина и 4) Плотность. Второй фрейм данных состоит из 1) идентификатора, 2) Сайта и 3) Выбора.

df1

   ID Sites Depth Density
  1     B   0.2       0
  2     B   0.2       1
  3     D   0.3       0
  4     D   0.3       1
  5     B   0.2       2
 

df2

   ID Sites Choice 
  1     A    No
  1     B    Yes     
  1     C    No
  1     D    No
  2     A    No
  2     B    Yes
  2     C    No
  2     D    No
  3     A    No
  3     B    No
  3     C    No
  3     D    Yes
  4     A    No
  4     B    No
  4     C    No
  4     D    Yes
  5     A    No
  5     B    Yes
  5     C    No
  5     D    No
 

То, что я пытаюсь сделать, это добавить столбец в df2, который имеет плотность на каждом сайте, когда идентификатор имеет «Да». Ниже приведено то, что я хочу, чтобы результат был:

Желаемый Результат

   ID Sites Choice Depth  Density
  1     A    No     0.1     0
  1     B    Yes    0.2     0 
  1     C    No     0.3     0 
  1     D    No     0.4     0
  2     A    No     0.1     0
  2     B    Yes    0.2     1
  2     C    No     0.3     0
  2     D    No     0.4     0
  3     A    No     0.1     0
  3     B    No     0.2     1
  3     C    No     0.3     0
  3     D    Yes    0.4     0
  4     A    No     0.1     0
  4     B    No     0.2     1
  4     C    No     0.3     0
  4     D    Yes    0.4     1
  5     A    No     0.1     0
  5     B    Yes    0.2     2
  5     C    No     0.3     0
  5     D    No     0.4     1
 

Я пробовал использовать следующее, но это не работает:

      df3<-df2 %>%
     full_join(df1, by = c("ID", "Sites")) %>%
     group_by(ID) %>%
     mutate(Density = Density[Choice == "Yes"]) %>%
     distinct(ID, Sites, .keep_all = TRUE) 
 

Спасибо вам за вашу помощь, сообщество stackoverflow.

Комментарии:

1. Откуда Depth = 0.1 взялось, когда ID = 1 и Сайты = A? Я не вижу этого ни в одной таблице.

Ответ №1:

Это то, что вы ищете?

 df1<-data.frame(stringsAsFactors=FALSE,
                ID = c(1, 2, 3, 4, 5),
                Sites = c("B", "B", "D", "D", "B"),
                Depth = c(0.2, 0.2, 0.3, 0.3, 0.2),
                Density = c(0, 1, 0, 1, 2)
)

df2<-data.frame(stringsAsFactors=FALSE,
                ID = c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5),
                Sites = c("A", "B", "C", "D", "A", "B", "C", "D", "A", "B", "C", "D",
                          "A", "B", "C", "D", "A", "B", "C", "D"),
                Choice = c("No", "Yes", "No", "No", "No", "Yes", "No", "No", "No", "No",
                           "No", "Yes", "No", "No", "No", "Yes", "No", "Yes", "No",
                           "No")
)

df3<-df2 %>%
  left_join(df1, by = c("ID", "Sites")) %>%
  mutate(Density=if_else(Choice=="Yes",Density, 0))
 

Ответ №2:

Данные.

   df1 <- data.frame(
      ID = seq(from = 1, to = 5, by = 1),
      Sites = c("B", "B", "D", "D", "B"),
      Depth = c(0.2, 0.2, 0.3, 0.3, 0.2),
      Density = c(0,1,0,1,2)
    )

qw <- c("No", "Yes")
  
df2 <- data.frame(
  ID = c(rep(1:5, times = 5)),
  Sites = sample(LETTERS[1:4], size = 25, replace = TRUE),
  Choice = sample(qw, size = 25, replace = T)
)
 

Но я немного смущен тем, что вам нужно от этого репрекса. В вашем заявлении создается впечатление, что вам нужен подмножество DF3, которое содержит только записи, в которых значение CHOICE == «ДА» является ИСТИННЫМ, а идентификатор = ИДЕНТИФИКАТОР и Сайт = Сайт. Очевидно, что это приведет к очень небольшому количеству записей.

 df3 <- merge(df1, df2, by = c("Sites", "ID")) %>% 
filter(Choice == "Yes") # only one record from the dummy data.
 

Если выбор » Да » является свойством идентификатора, но не сайта, вот вариант.

 df3 <- df1 %>% 
select(-Sites) %>% 
  left_join(df2 %>% filter(Choice == "Yes"), by = "ID")
 

Я думаю, я просто запутался, должны ли совпадать оба сайта и идентификаторы. Если это так, то здесь просто не так много записей.

Ответ №3:

Решение data.table:

 df1[df2[ID %in% df2[Choice == "Yes", unique(ID)], ], 
    on = .(ID, Sites)][is.na(Density), 
                           Density := 0][]
 

Что там внутри:

  • df2[Choice == "Yes", unique(ID) фильтры, где выбор «да», и возвращает уникальные идентификаторы. Они понадобятся нам для фильтрации df2 .
  • df2[ID %in% df2[Choice == "Yes", unique(ID)], ] фильтрует только те случаи, когда идентификатор совпадает с идентификаторами, в которых есть хотя бы одно «да» в выборе.
  • df1[df_x, on = .(ID, Sites)] делает левое соединение df1 с тем, что находится внутри df_x (в нашем случае отфильтрованное df2 .
  • [is.na(Density), Density := 0] фильтрует строки, в которых указана плотность NA , и только в этих строках присваивает 0 плотности.
  • [] Печать для отображения полученных данных, на самом деле вам это не нужно.