R dplyr join by range or virtual column

后端 未结 6 1341
独厮守ぢ
独厮守ぢ 2020-12-10 16:33

I want to join two tibbles by a range or a virtual column. but it seems the by - parameter just allow to handle chr oder vector(chr) o

6条回答
  •  夕颜
    夕颜 (楼主)
    2020-12-10 17:05

    We can use mutate and case_when from dplyr.

    library(dplyr)
    
    d2 <- d %>%
      mutate(class = case_when(
        value >= 1 & value < 2 ~ "A",
        value >= 2 & value < 3 ~ "B",
        value >= 3 & value < 4 ~ "C",
        value >= 4 & value < 5 ~ "D",
        value >= 5 & value < 6 ~ "E",
        value >= 6             ~ "F"
      ))
    d2
    # A tibble: 26 x 2
       value class
        
     1   1.0     A
     2   1.2     A
     3   1.4     A
     4   1.6     A
     5   1.8     A
     6   2.0     B
     7   2.2     B
     8   2.4     B
     9   2.6     B
    10   2.8     B
    # ... with 16 more rows
    

    Update

    Here is a workaround by defining a function for this task.

    d <- tibble(value = seq(1,6, by = 0.2))
    r <- tibble(from = seq(1,6), to = c(seq(2,6),Inf), class = LETTERS[seq(1,6)])
    
    library(dplyr)
    
    # Define a function for dynamic join
    dynamic_join <- function(d, r){
    
      if (!("class" %in% colnames(d))){
        d[["class"]] <- NA_character_
      }
    
      d <- d %>%
        mutate(class = ifelse(value >= r$from & value < r$to, r$class, class))
      return(d)
    }
    
    re_dynamic_join <- function(d, r){
      r_list <- split(r, r$class)
      for (i in 1:length(r_list)){
        d <- dynamic_join(d, r_list[[i]])
      }
      return(d)
    }
    
    # Apply the function
    d2 <- d %>% re_dynamic_join(r)
    d2
    # A tibble: 26 x 2
       value class
        
     1   1.0     A
     2   1.2     A
     3   1.4     A
     4   1.6     A
     5   1.8     A
     6   2.0     B
     7   2.2     B
     8   2.4     B
     9   2.6     B
    10   2.8     B
    # ... with 16 more rows
    

提交回复
热议问题