多组变量的 R rowSums 使用变量名称前缀的变异和 for 循环

R rowSums for multiple groups of variables using mutate and for loops by prefix of variable names

我有多个变量按前缀组合在一起(par___、fri___、gp___ 等),其中有 29 个这样的组。

每个变量的值为 0 或 1。我需要做的是对这些组求和(即 partner___1 + partner___2 等),如果 rowSums = 0,则使每个变量 NA.

例如。我的数据如下所示:

par___ par___2 fri___1 fri___2
0 0 1 1
0 1 0 0
0 0 1 0
0 0 0 0

我希望它看起来像这样:

par___ par___2 fri___1 fri___2
NA NA 1 1
0 1 NA NA
NA NA 1 0
NA NA NA NA

我可以这样单独做:

  df<- df%>%
    mutate(rowsum = rowSums(.[grep("par___", names(.))])) %>% 
    mutate_at(grep("par___", names(.)), funs(ifelse(rowsum == 0, NA, .))) %>%
    select(-rowsum) 

我想我可以做这样的事情:

vars <- c('par___', "fri___','gp___')


for (i in vars) {
  df<- df%>%
    # creates a "rowsum" column storing the sum of columns 1:2 
    mutate(rowsum = rowSums(.[grep(i, names(.))])) %>% 
    # applies, to columns 1:2, a function that puts NA when the sum of the rows is 0
    mutate_at(grep(i, names(.)), funs(ifelse(rowsum == 0, NA, .))) %>%
    select(-rowsum) 
    }

没有错误消息,但它不起作用。

此外,我尝试了 mutate(across()) 而不是 mutate_at() 并得到了这个错误:

错误:mutate() 输入 ..1 有问题。 x 无法将列表转换为函数 i 输入 ..1across(grep(i, names(.)), list(ifelse(rowsum == 0, NA, .))).

而且,我尝试使用 list 而不是 funs 并得到这个错误:

行和错误 == 0 : 比较 (1) 仅适用于原子和列表类型

如有任何帮助,我们将不胜感激!

非常感谢。

tidyverse 选项将是:

df %>%
  stack() %>%
  group_by(ind) %>%
  group_by(grp = row_number(), grp2 = str_remove(ind, "_.*")) %>%
  mutate(values = values + na_if(all(values==0), 1)) %>%
  pivot_wider(grp, ind, values_from = values)
  
# A tibble: 4 x 5
# Groups:   grp [4]
    grp par___1 par___2 fri___1 fri___2
  <int>   <int>   <int>   <int>   <int>
1     1      NA      NA       1       1
2     2       0       1      NA      NA
3     3      NA      NA       1       0
4     4      NA      NA      NA      NA

如果另一方面,您更喜欢 base R,那么您可以这样做:

d <- ave(unlist(df), row(df), sub("_.*", "", names(df))[col(df)], FUN = function(x) x * NA ^ all(x==0))
array(d, dim(df), dimnames(df))

  par___1 par___2 fri___1 fri___2
1      NA      NA       1       1
2       0       1      NA      NA
3      NA      NA       1       0
4      NA      NA      NA      NA

请注意,最后一个是矩阵,您可以将其转换为数据框。

Base R 选项使用 split.default :

do.call(cbind, unname(lapply(split.default(df, 
     sub('(\w+)_.*', '\1', names(df))), function(x) {
           x[rowSums(x) == 0, ] <- NA
           x
})))

#  fri___1 fri___2 par___ par___2
#1       1       1     NA      NA
#2      NA      NA      0       1
#3       1       0     NA      NA
#4      NA      NA     NA      NA