【问题标题】:Comparing all rows within a dataframe and apply a function conditionally比较数据框中的所有行并有条件地应用函数
【发布时间】:2019-05-06 15:54:16
【问题描述】:

我有这个数据框,我想交叉比较这个数据框内的所有值。

dat <- tibble::tibble(
name = c("a","b","c"),
value = c(1,2,3))

我想比较这个数据框中的所有行对,在这种情况下,我想用较小的数字除以较大的数字。

最终的数据框应如下所示:

a,b,0.5
a,c,0.33
b,c,0.66

有没有办法做到这一点?

【问题讨论】:

    标签: r dataframe tidyverse


    【解决方案1】:

    使用data.table包,我们可以将dat与自己连接,条件是一个值小于另一个值,并计算与连接表的列的比率。

    library(data.table)
    setDT(dat)
    
    out <- 
      dat[dat, on = .(value < value), 
           .(name1 = x.name,
             name2 = i.name,
             ratio = x.value/i.value)]
    
    out <- out[!is.na(ratio)]
    
    out
    #    name1 name2     ratio
    # 1:     a     b 0.5000000
    # 2:     a     c 0.3333333
    # 3:     b     c 0.6666667
    

    【讨论】:

    • 简洁的解决方案。可能是一个班轮:as_tibble(setDT(dat)[dat, on = .(value &lt; value), .(name1 = x.name, name2 = i.name, ratio = x.value/i.value)][!is.na(ratio)]) cc:@MKR
    【解决方案2】:

    一种选择是

    v1 <-  setNames(dat$value, dat$name)
    do.call(rbind, combn(v1, 2, FUN = function(x) 
     setNames(data.frame(as.list(names(x)), round(Reduce(`/`, x[order(x)]), 2)), 
          c("col1", "col2", "val")), simplify = FALSE))
    #   col1 col2  val
    #1    a    b 0.50
    #2    a    c 0.33
    #3    b    c 0.67
    

    或者fuzzyjoin 的选项(灵感来自@IceCreamToucan 的帖子)

    library(fuzzyjoin)
    fuzzy_inner_join(dat, dat, by = "name", match_fun = list(`<`)) %>% 
        transmute(col1 = name.x, col2 = name.y, val = value.x/value.y)
    # A tibble: 3 x 3
    #  col1  col2    val
    #  <chr> <chr> <dbl>
    #1 a     b     0.5  
    #2 a     c     0.333
    #3 b     c     0.667
    

    【讨论】:

      【解决方案3】:

      我们可以使用tidyverse:

      library(tidyverse)
      dat %>% expand(name, name) %>% cbind(expand(dat, value,value)) %>%
              filter(value1>value) %>%
              mutate(ratio=value/value1)
      
          #>   name name1 value value1     ratio
          #> 1    a     b     1      2 0.5000000
          #> 2    a     c     1      3 0.3333333
          #> 3    b     c     2      3 0.6666667
      

      或者只是在baser中涂鸦:

      df <- cbind(expand.grid(dat$name,dat$name), expand.grid(dat$value, dat$value))   
      df <- df[order(df[,3], -df[,4]),]    
      df <- df[df[,3] < df[,4],]
      df$ratio <- df[,3] / df[,4]
      df[,-c(3,4)] -> df
      df
      
          #>   Var1 Var2     ratio
          #> 7    a    c 0.3333333
          #> 4    a    b 0.5000000
          #> 8    b    c 0.6666667
      

      【讨论】:

        猜你喜欢
        • 2021-05-10
        • 2021-08-15
        • 1970-01-01
        • 2016-02-19
        • 2020-02-07
        • 2021-10-20
        • 2022-11-19
        • 1970-01-01
        • 2021-10-15
        相关资源
        最近更新 更多