计算一组列中存在的唯一字符

时间:2018-11-13 18:00:47

标签: r dplyr

我有以下数据集

dat <- data.frame(group = c(1,1,1,1,1), id = c(1,2,3,4,5),
              t1 = c('a','a','b','b','c'),p1 = c(0.98,1,0.5,0.9,1),
              t2 = c('b',NA,'a','c',NA),p2 = c(0.02,NA,0.25,0.10,NA),
              t3 = c(NA,NA,'c',NA,NA),p3 = c(NA,NA,0.25,NA,NA))

我试图计算包含多行(变量='group')的组中多列(t1,t2,t3)中出现的唯一字符的数量。是否计算每个字符取决于相关的p1,p2,p3值> = 0.05。

我尝试输入此代码以计算所有列中的唯一字符

b <- dat %>%
group_by(group) %>%
mutate(total = sum(n_distinct(t1[p1 >= 0.05], na.rm = TRUE),
                            n_distinct(t2[p2 >= 0.05], na.rm = TRUE),
                            n_distinct(t3[p3 >= 0.05], na.rm = TRUE)))

其结果是它计算t1,t2和t3的唯一字符,然后对其求和,得出以下“总”为6的数据集

dat <- data.frame(group = c(1,1,1,1,1), id = c(1,2,3,4,5),
              t1 = c('a','a','b','b','c'),p1 = c(0.98,1,0.5,0.9,1),
              t2 = c('b',NA,'a','c',NA),p2 = c(0.02,NA,0.25,0.10,NA),
              t3 = c(NA,NA,'c',NA,NA),p3 = c(NA,NA,0.25,NA,NA),
              total = c(6,6,6,6,6))

但是,我要做的是计算所有列中唯一字符的总数。换句话说,如果在t1列中看到“ a”,则不要在其他列(t2,t3)中计算“ a”。最终产品看起来像以下数据集,其中“ total”为3(表示a,b和c为存在的唯一字符)

dat <- data.frame(group = c(1,1,1,1,1), id = c(1,2,3,4,5),
              t1 = c('a','a','b','b','c'),p1 = c(0.98,1,0.5,0.9,1),
              t2 = c('b',NA,'a','c',NA),p2 = c(0.02,NA,0.25,0.10,NA),
              t3 = c(NA,NA,'c',NA,NA),p3 = c(NA,NA,0.25,NA,NA),
              total = c(3,3,3,3,3))

谢谢您的帮助

3 个答案:

答案 0 :(得分:3)

我们可以使用map2遍历每个对应的't'和'p'列,获取listfilter中基于“ p”列的值,pull“ t”列的值,获取不同元素的数量(n_distinct),并使用bind_cols

创建一个新列
library(tidyverse)
map2_int(paste0('t', 1:3), paste0('p', 1:3), ~ 
          dat %>%
             select(.x, .y)  %>% 
             filter_at(.y, all_vars(. >= 0.05)) %>%
             pull(.x) %>%
             n_distinct) %>% 
     bind_cols(dat, total = .)

,如果各列之间是“唯一的”,则不是每列获取n_distinct,而是unlist list然后应用n_distinct,然后使用mutate

在'dat'中创建新列
map2(paste0('t', 1:3), paste0('p', 1:3), ~ 
          dat %>% 
            select(.x, .y)  %>%
            filter_at(.y, all_vars(. >= 0.05)) %>%
            pull(.x) ) %>% 
            unlist %>% 
            n_distinct %>% 
            mutate(dat, total = .)
#   group id t1   p1   t2   p2   t3   p3 total
#1     1  1  a 0.98    b 0.02 <NA>   NA     3
#2     1  2  a 1.00 <NA>   NA <NA>   NA     3
#3     1  3  b 0.50    a 0.25    c 0.25     3
#4     1  4  b 0.90    c 0.10 <NA>   NA     3
#5     1  5  c 1.00 <NA>   NA <NA>   NA     3

更新

如果我们进行group_by n_distinct,则可以通过在按“组”分组后summarise将“ {total”的n_distinct进行更改来更改以上内容

map2_df(paste0('t', 1:3), paste0('p', 1:3), ~ 
      dat %>% 
         group_by(group) %>%
         select(.x, .y)  %>%
         filter_at(.y, all_vars(. >= 0.05))  %>% 
         select(-.y) %>% 
         rename_at(.x, ~ 'total')) %>% 
   summarise(total = n_distinct(total)) %>% 
   left_join(dat)

答案 1 :(得分:3)

首先通过功能lapply的{​​{1}}列进入p,然后选择具有>= 0.05的所有p列的结果为true的行。一旦有了这些行,就可以使用Reduce('&'选择要为其计算唯一性的数据,然后.SD[rows, paste0('t', 1:3)](将其强制为单个向量)进行计数,从而可以使用{{1} }直接计算不重复次数。

unlist

答案 2 :(得分:0)

这适用于任意数量的组和任意数量的列对。

dat %>%
  gather(key, value, -group, -id) %>%
  separate(key, c('key1', 'key2'), 1) %>%
  group_by(group, id, key2) %>%
  spread(key1, value) %>%
  filter(p >= 0.05) %>%
  pull(t) %>%
  n_distinct() %>% 
  mutate(dat, total = .)