R Заполняет столбец на основе совпадающих значений строк в двух разных фреймах данных

#r #merge

#r #слияние

Вопрос:

У меня есть два разных фрейма данных ‘df1’ и ‘df2’ с шестью совпадающими именами столбцов. Я хочу просканировать df2 на наличие строк, которые точно совпадают в df1, и если они есть, введите 1 в столбец «обнаружение» df1, а если нет, введите 0 в этот столбец. В настоящее время все значения ‘detect’ в df1 равны 0, но я хочу, чтобы они менялись на 1, когда между двумя фреймами данных есть точное совпадение. Это будет выглядеть так:

df1

Сайт ddate ssegment spp vtype tperiod обнаружение
BMA 6/1/2021 1 AMRO Песня 1 0
BMC 6/15/2021 1 WISN Барабан 1 0
BMA 6/15/2021 1 NOFL Песня 2 0
BMC 6/29/2021 2 AMRO Вызов 1 0
BMA 6/29/2021 2 WISN Вызов 2 0

df2

Сайт ddate ssegment spp vtype tperiod
BMA 6/1/2021 1 AMRO Вызов 1
BMC 6/15/2021 1 WISN Барабан 1
BMA 6/15/2021 1 NOFL Песня 2
BMC 6/29/2021 2 AMRO Барабан 1
BMA 6/29/2021 2 WISN Вызов 2

После их сканирования df1 теперь будет выглядеть так:

df1

Сайт ddate ssegment spp vtype tperiod обнаружение
BMA 6/1/2021 1 AMRO Песня 1 0
BMC 6/15/2021 1 WISN Барабан 1 1
BMA 6/15/2021 1 NOFL Песня 2 1
BMC 6/29/2021 2 AMRO Вызов 1 0
BMA 6/29/2021 2 WISN Вызов 2 1

Я думал, что базовая функция R ‘merge’ может быть полезной, но я не совсем понимаю это. Спасибо за вашу помощь!

Ответ №1:

Начните detect только со столбца в df2 , затем объедините:

 df1$detect = NULL
df2$detect = 1
result = merge(df1, unique(df2), all.x = TRUE)
 

Это создаст detect столбец как 1s, когда есть точные совпадения, и NA s, когда их нет. Если вы хотите, вы можете изменить NA s на 0s.

Тот же метод может работать с dplyr :

 library(dplyr)
df1 %>% 
  select(-detect) %>%
  left_join(
    df2 %>% mutate(detect = 1) %>% unique)
  )
 

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

1. Этот ответ, похоже, работает, однако математика не складывается. По сути, мой фактический df1 имеет 38880 строк, а df2 — 5854 строки. ‘result’ должен содержать 38880 строк (таких же, как df1), потому что все, что я хочу, это чтобы данные столбца ‘detect’ изменились на 1 для 5854 строк df1, которые точно соответствуют df2. Я знаю, что в df1 есть соответствующая строка для каждой строки в df2. Ваш результат оставляет мне 42702 строки в «результате». Есть идеи, что может происходить?

2. Это означает, что у вас есть несколько строк с несколькими совпадениями. Дедупликация df2 сначала должна это исправить. Я отредактирую для использования unique(df2) в merge() .

3. Это кажется правильным. Спасибо за ваши усилия по этому!

Ответ №2:

Существует anti_join и semi_join для объединения фильтров двух таблиц:

 library(tidyverse)

df1 <- tribble(
  ~site,      ~ddate, ~ssegment,   ~spp, ~vtype, ~tperiod, ~detect,
  "BMA",  "6/1/2021",        1L, "AMRO", "Song",       1L,      0L,
  "BMC", "6/15/2021",        1L, "WISN", "Drum",       1L,      0L,
  "BMA", "6/15/2021",        1L, "NOFL", "Song",       2L,      0L,
  "BMC", "6/29/2021",        2L, "AMRO", "Call",       1L,      0L,
  "BMA", "6/29/2021",        2L, "WISN", "Call",       2L,      0L
  )

df2 <- tibble::tribble(
~site,      ~ddate, ~ssegment,   ~spp, ~vtype, ~tperiod,
"BMA",  "6/1/2021",        1L, "AMRO", "Call",       1L,
"BMC", "6/15/2021",        1L, "WISN", "Drum",       1L,
"BMA", "6/15/2021",        1L, "NOFL", "Song",       2L,
"BMC", "6/29/2021",        2L, "AMRO", "Drum",       1L,
"BMA", "6/29/2021",        2L, "WISN", "Call",       2L
)


bind_rows(
  df1 %>% select(-detect) %>% anti_join(df2) %>% mutate(detect = 0),
  df1 %>% select(-detect) %>% semi_join(df2) %>% mutate(detect = 1)
)
#> Joining, by = c("site", "ddate", "ssegment", "spp", "vtype", "tperiod")
#> Joining, by = c("site", "ddate", "ssegment", "spp", "vtype", "tperiod")
#> # A tibble: 5 x 7
#>   site  ddate     ssegment spp   vtype tperiod detect
#>   <chr> <chr>        <int> <chr> <chr>   <int>  <dbl>
#> 1 BMA   6/1/2021         1 AMRO  Song        1      0
#> 2 BMC   6/29/2021        2 AMRO  Call        1      0
#> 3 BMC   6/15/2021        1 WISN  Drum        1      1
#> 4 BMA   6/15/2021        1 NOFL  Song        2      1
#> 5 BMA   6/29/2021        2 WISN  Call        2      1
 

Создано 2021-12-08 пакетом reprex (v2.0.1)

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

1. Этот ответ, похоже, работает просто отлично, как и приведенный ниже. Я недостаточно знаю о R, чтобы предлагать одно над другим. Спасибо за ваше время!

Ответ №3:

Пожалуйста, найдите одно возможное и очень простое решение с data.table помощью библиотеки

Reprex

  • Код
 library(data.table)

setDT(df1)
setDT(df2)

df1[df2, on = .(site, ddate, ssegment, spp, vtype, tperiod), detect := TRUE][]
 
  • Вывод
 
#>    site     ddate ssegment  spp vtype tperiod detect
#> 1:  BMA  6/1/2021        1 AMRO  Song       1      0
#> 2:  BMC 6/15/2021        1 WISN  Drum       1      1
#> 3:  BMA 6/15/2021        1 NOFL  Song       2      1
#> 4:  BMC 6/29/2021        2 AMRO  Call       1      0
#> 5:  BMA 6/29/2021        2 WISN  Call       2      1
 

Создано 2021-12-08 пакетом reprex (v2.0.1)

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

1. Вы забыли добавить ‘spp’ в свой код, поэтому я добавил его после ‘ssegment’ и запустил его, но получил эту ошибку: Ошибка в [.data.frame (df1, df2, on = .(site, ddate, ssegment, : неиспользуемый аргумент (on = .(site, ddate, ssegment, spp, vtype, tperiod))

2. Извините за ошибку… Итак, я добавил отсутствующую переменную в свой код, и она все еще работает. Пожалуйста, дайте мне знать.

3. Я думаю, ваша проблема в том, что df1 и df2 являются фреймами данных. Поэтому вам нужно преобразовать его в data.table before с setDT(df1) помощью, и setDT(df2) я добавлю это в свой ответ. Пожалуйста, дайте мне знать.

4. Это решение также работает. Спасибо вам за приложенные усилия!

5. Спасибо за ваш отзыв. Я желаю вам всего наилучшего в вашей работе. Ваше здоровье