Измените df на основе наличия пары значений столбца в другом df в R

отредактировано — исправлены опечатки, на которые указали Фрэнк и ycw.

У меня возникли проблемы с определением пар значений в фрейме данных, которые существуют в другом фрейме данных. Поскольку мои данные имеют длинный формат и каждый столбец содержит одно и то же значение много раз, я получаю слишком общие результаты, когда пытаюсь найти совпадения. Я пробовал несколько способов и не могу получить точные результаты, которые мне нужны. Учитывая, насколько проста операция, я ожидаю, что упускаю что-то очень очевидное.

В моем примере у меня есть набор записей о людях в длинном формате, df ppl. У меня также есть другой набор наблюдений за людьми за определенные периоды времени, в этом примере это отсутствие в определенные дни dfabs. Я хочу изменить ppl, чтобы создать новый столбец, который будет показывать, когда строка человеко-дней соответствует наблюдению в человеко-днях в df dfabs. Однако у меня возникают проблемы, когда я пытаюсь мутировать, так как мне не ясно, как создать подмножество на основе двух столбцов одновременно.

Пример ниже:

name <- c("Bob", "Bob", "Ana","Ana", "Jorge","Jorge")
day <- c(1,2,1,2,1,2)
eval <- c(4,3,5,5,2,5)
ppl <- as.data.frame(cbind(name,day, eval), names=TRUE)

   name day eval
1   Bob   1    4
2   Bob   2    3
3   Ana   1    5
4   Ana   2    5
5 Jorge   1    2
6 Jorge   2    5

nameabs <- c("Bob","Jorge","Cindy")
dayabs <- c(1,2,1)
dfabs <- as.data.frame(cbind(nameabs, dayabs), names=TRUE)
dfabs

  nameabs dayabs
1     Bob      1
2   Jorge      2
3   Cindy      1

Результат, который я хочу увидеть:

    name day eval absent
1   Bob   1    4      1
2   Bob   2    3      0
3   Ana   1    5      0
4   Ana   2    5      0
5 Jorge   1    2      0
6 Jorge   2    5      1

Для этого я попытался использовать функцию mutate:

mutate(ppl, absent = ifelse(((name %in% dfabs$nameabs) & (day %in% dfabs$dayabs)),1,0))

Результат:

   name day eval absent
1   Bob   1    4      1
2   Bob   2    3      1
3   Ana   1    5      0
4   Ana   2    5      0
5 Jorge   1    2      1
6 Jorge   2    5      1

Это неправильно. В нем указано, что Боб и Хорхе отсутствовали оба дня. Кажется, что в моем операторе ifelse() он оценивал два логических выражения (name %in% dfabs$nameabs) и (day %in% dfabs$dayabs) в отдельных строках.

Использование других функций, таких как filter(), вызывает ту же проблему. Я не могу понять, как заставить его оценить все выражение в одной строке. В общем, с dplyr и без него у меня было много проблем с этой общей проблемой: как подмножить один df на основе присутствия пары (по двум столбцам) в другом df? Я работаю с гораздо большим и более сложным набором данных, и мне было бы очень полезно иметь обобщаемый ответ.

Заранее спасибо за помощь!


person MrMr    schedule 29.08.2017    source источник
comment
Есть ошибки, когда я запускал ваш код. Пожалуйста, исправьте свой код.   -  person www    schedule 29.08.2017
comment
Кстати, это неэффективный способ использования cbind для создания фрейма данных, поскольку вы уже используете data.frame. abs — это встроенная функция R. Пожалуйста, используйте другие имена для вашего фрейма данных, если это возможно.   -  person www    schedule 29.08.2017
comment
Это просто левое соединение. left_join(ppl, abs, by = c("Name" = "nameabs", "Day" = "dayabs"))   -  person Gregor Thomas    schedule 29.08.2017
comment
К вашему сведению, вы говорите, что ваши данные в широком формате, но на самом деле это называется длинным форматом. Кроме того, вот аналог data.table, если вам интересно: stackoverflow.com/q/40314562   -  person Frank    schedule 29.08.2017
comment
Я все еще не понимаю, как использовать левое соединение, чтобы получить оценку TRUE/FALSE, которая мне нужна внутри оператора ifelse(), если мой вызов mutate будет работать.   -  person MrMr    schedule 29.08.2017
comment
Я не думаю, что правильно помечать это как дубликат вопроса о присоединении? Я думаю, что здесь есть несколько дополнительных шагов, которые не сразу интуитивно понятны.   -  person MrMr    schedule 29.08.2017
comment
@MrMr Я склонен согласиться, но на него можно ответить некоторыми такими соединениями. Вот один неуклюжий способ: dfabs %>% mutate(v = 1) %>% right_join(ppl, by = c("nameabs" = "name", "dayabs" = "day")) %>% mutate(v = as.integer(!is.na(v))) Я думаю, что есть другой обман, который лучше подходит где-то (похож на ссылку data.table в моем последнем комментарии).   -  person Frank    schedule 29.08.2017