#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. Спасибо за ваш отзыв. Я желаю вам всего наилучшего в вашей работе. Ваше здоровье