比较数据框中的所有行并有条件地应用函数

时间:2019-05-06 15:54:17

标签: r dataframe tidyverse

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

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

有没有实现这一目标的方法?

3 个答案:

答案 0 :(得分:3)

使用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

答案 1 :(得分: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

答案 2 :(得分:1)

我们可以使用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

或者只是base r中的涂鸦:

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