Присоединиться на основе условия другого столбца - PullRequest
1 голос
/ 16 марта 2020

Итак, я хочу присоединить df_1 к df_2 на основе идентификатора:

df_1 <- data.frame(id=c(1,2,3,4,5))


df_2<- data.frame(id=c(1,1,2,3,3,4,4,5,5,5,5),name=c("a","a1","b","c","c2","d","d1","e","e1","e2","e3"),status=c("IN","OUT","OUT","PENDING","OUT","OUT","REFER","IN","OUT","REFER","OUT"))

, и вот как должен выглядеть мой результирующий набор данных:

df_merge<-data.frame(id=c(1,2,3,4,5),name=c("a","b","c","d1","e"))

Поэтому я хочу объединить имя, связанное с "IN", и если оно недоступно, то имя, связанное с "PENDING", и после этого оно должно быть "REFER", если ни одного из них нет, сопоставьте идентификатор со статусом "OUT". Как я могу это сделать?

1 Ответ

3 голосов
/ 16 марта 2020

Мы выполняем объединение, затем arrange по 'id' и factor конвертируем 'status' с levels в указанном порядке, сгруппированные по 'id', получаем первую строку с slice

library(dplyr)
left_join(df_2, df_1) %>% 
  arrange(id, factor(status, levels = c('IN', 'PENDING', 'REFER', 'OUT'))) %>% 
  group_by(id) %>%
  slice(1) %>%
  ungroup %>%
  select(-status)
# A tibble: 5 x 2
#     id name 
#  <dbl> <fct>
#1     1 a    
#2     2 b    
#3     3 c    
#4     4 d1   
#5     5 e    

Если дублируется 'df_1', затем выполните left_join со строками distinct, затем выполните right_join

df_1 <- data.frame(id=c(1,1,2,3,4,5,5)) 
left_join(df_2, distinct(df_1)) %>% 
    arrange(id, factor(status, levels = c('IN', 'PENDING', 'REFER', 'OUT'))) %>%  
    group_by(id) %>%
    slice(1) %>%
    ungroup %>%
    select(-status)  %>%
    right_join(df_1)
# A tibble: 7 x 2
#     id name 
#* <dbl> <fct>
#1     1 a    
#2     1 a    
#3     2 b    
#4     3 c    
#5     4 d1   
#6     5 e    
#7     5 e   

Или мы можем получить list столбец or гнездо the 'id' and the unnest`

library(tidyr)
df_1 %>% 
    group_by(id) %>% 
    nest %>%
    right_join(df_2) %>%
    arrange(id, factor(status, levels = c('IN', 'PENDING', 'REFER', 'OUT'))) %>%   
    group_by(id) %>%
    slice(1) %>%
    ungroup %>%
    select(-status) %>% 
    unnest

или с использованием data.table

library(data.table)
setDT(df_2)[df_1,  .(name = name[order(match(status,
      c('IN', 'PENDING', 'REFER', 'OUT')))[1]]), on = .(id), by = .EACHI]
#   id name
#1:  1    a
#2:  2    b
#3:  3    c
#4:  4   d1
#5:  5    e

или base R вариант сначала order набор данных 'df_2', а затем извлекать элементы 'name' на основе duplicated элементов в 'id'

df_2n <- df_2[order(df_2$id, factor(df_2$status, levels = c('IN', 'PENDING', 'REFER', 'OUT'))),] 
df_1$name <-  df_2n$name[!duplicated(df_2$id)]
...