每行对不同范围的列求和

Sum different range of columns per row

我想在我的数据集中创建一个新变量来对特定范围的列求和,但是要求和的列范围因每一行而异。

这是我的示例数据集。我想创建一个新变量 NUM1,它是第 1 列到 ARRAYEND 的总和,其中变量 ARRAYEND 指定 NUM1 列的总和。

#create sample dataset
r1<-c(1,1,1,1,0,2)
r2<-c(1,1,0,1,1,4)
df<-as.data.frame(rbind(r1,r2))
names(df)<-c("Flag1","Flag2","Flag3","Flag4","Flag5","ARRAYEND")

   Flag1 Flag2 Flag3 Flag4 Flag5 ARRAYEND
r1     1     1     1     1     0        2
r2     1     1     0     1     1        4

这是我想要的结果:

  Flag1 Flag2 Flag3 Flag4 Flag5 ARRAYEND NUM1
r1     1     1     1     1     0        2    2
r2     1     1     0     1     1        4    3

我试图通过 dplyr 执行此操作,但它给我一个错误。

df <-df %>% mutate(NUM1 = rowSums(.[1:df$ARRAYEND]))

Warning messages:
1: Problem with `mutate()` input `NUM1`.
ℹ numerical expression has 2 elements: only the first used
ℹ Input `NUM1` is `rowSums(.[1:df$ARRAYEND])`. 
2: In 1:df$ARRAYEND :
  numerical expression has 2 elements: only the first used

A base R 选项将循环遍历具有 applyMARGIN = 1 的行,然后获取 'ARRAYEND' 的 sequence,子集'x' 的元素并得到 sum

df$NUM1 <- apply(df, 1, function(x)  sum(x[seq(x['ARRAYEND'])]))

-输出

df
#   Flag1 Flag2 Flag3 Flag4 Flag5 ARRAYEND NUM1
#r1     1     1     1     1     0        2    2
#r2     1     1     0     1     1        4    3

注意:tidyverse 不保留行名。所以,使用 base R

可能会更好

如果我们想要 tidyverse,一个选项是首先将行名作为列

library(tibble)
library(dplyr)
df %>%
    rownames_to_column('rn') %>% 
    rowwise %>% 
    mutate(NUM1 = sum(c_across(starts_with("Flag"))[seq(ARRAYEND)])) %>%    
    ungroup %>%
    column_to_rownames('rn')

-输出

#   Flag1 Flag2 Flag3 Flag4 Flag5 ARRAYEND NUM1
#r1     1     1     1     1     0        2    2
#r2     1     1     0     1     1        4    3

另一个基本 R 选项使用 Reduce

transform(
  df,
  NUM1 = list2DF(Reduce("+", df, accumulate = TRUE))[cbind(seq_along(ARRAYEND), ARRAYEND)]
)

给予

   Flag1 Flag2 Flag3 Flag4 Flag5 ARRAYEND NUM1
r1     1     1     1     1     0        2    2
r2     1     1     0     1     1        4    3