在 R 中按行计算可变列范围的最小值/最大值

Calculate rowwise Min/Max across a variable range of columns in R

提问人:Rosa 提问时间:9/4/2023 最后编辑:Rosa 更新时间:9/4/2023 访问量:91

问:

对于 R 中的数据分析,我正在尝试计算变量 A1,它是一系列值中的最小值。棘手的是,范围的开始取决于前一个变量 D1 的索引(即前几列的最大值)。

例:

df <- data.frame(ID = 1:5, V1 = c(2, 5, 2, 8, 3), V2 = c(3, 4, 4, 7, 1), V3 = c(7, 2, 8, 1, 5), V4 = c( 1, 2,3, 4, 6), V5 = c(3, 2, 5, 2, 8))
df

D1_range <- 2:3
df$D1 <- apply(df[,D1_range],1, max)
df$indexD1 <- apply(df[,D1_range], 1,which.max)
df

D1 是 V1:V2 的最大值。A1 的范围从 indexD1 + 1 开始。因此,例如,对于 ID=5,这将从 V2 开始,而对于 ID=1,这将从 V3 开始。

现在,我尝试以多种不同的方式指示 A1 的范围。例如,通过计算范围:

df$A1_start <- df$indexD1+1
df$A1_end <- 6
df
df$A1 <- df %>% rowwise() %>% do.call(pmin, df[,df$A1_start:df$A1_end])

或者通过使用 apply

df$A1 <- apply(df[,df$A1_start:6], min)
df
df$A1 <- df %>% rowwise() %>% apply(df[,df$A1_start:6], min)
df

和 mutate:

df <- df %>% rowwise() %>% mutate(A1 = min(c_across(A1_range)))
df

我还尝试将范围写成字符串:


df$A1_range <- "{df$A1_start}:{df$A1_end}"

但这只会创建一个非常奇怪的变量,其文本为“{df$A1_start}:{df$A1_end}”

我还发现了另一个使用子集的帖子,并在管道中尝试过,但是如果我这样做,我会得到一个错误:

df <- df %>% rowwise() %>% mutate(A1test = min(subset(., select = A1_startname:A1_endname)))

(注意:在我的真实数据中,我计算了 A1_startname 和 A1_endname,它们也是字符串而不是索引的列名)

问题是:即使我可以获得计算值 A1 的代码,它也会将列表中第一个值 (ID=1) 的 A1_start 值作为每行范围的开始。但是,在某些情况下,这是不正确的。例如,对于 ID=5,D1 是 V1 中的值,因此 A1 的范围应以 V2 开头,但现在它以 V3 开头。

有人可以帮我找到一种方法在找到最小值的函数中使用变量范围吗? 谢谢!

编辑以包含所需的输出:

如果该函数有效,它应该看起来像这样:

df <- data.frame(ID = 1:5, V1 = c(2, 5, 2, 8, 3), V2 = c(3, 4, 4, 7, 1), V3 = c(7, 2, 8, 1, 5), V4 = c( 1, 2,3, 4, 6), V5 = c(3, 2, 5, 2, 8), D1 = c(3, 5,4,8,3), D1index = c(1,1,2,2,1), A1start= c(3,2,3,3,2), A1 = c(1, 2, 3, 1,1))
df

如果 A1 的范围没有根据行而变化(因此,如果它采用值 A1start[1] 作为数据框中 /all/ 行范围的开始),那么您将在 ID=5 中得到不正确的 A1,因为在 3:5 范围内,最小值将是 5,但 A1 的实际正确值应该是该行中的 1(因为范围从 V2 开始行)。

希望这会有所帮助。:)

注意:我刚刚创建了一个非常简单的数据框来说明,但实数不是整数,而是有 6 位数字/小数。因此,对于真实数据,我认为我们可以放心地假设任何地方都不会有重复的值。

注2: 我将 D1index 和 A1start 添加到数据帧中作为中间步骤。但是,如果可以在没有这两个变量的情况下计算 A1,那也没问题。 因此,所需的输出也可能只是:

df <- data.frame(ID = 1:5, V1 = c(2, 5, 2, 8, 3), V2 = c(3, 4, 4, 7, 1), V3 = c(7, 2, 8, 1, 5), V4 = c( 1, 2,3, 4, 6), V5 = c(3, 2, 5, 2, 8), D1 = c(3, 5,4,8,3), A1 = c(1, 2, 3, 1,1))
df

R 范围 最小

评论

0赞 Mark 9/4/2023
嗨,罗莎!欢迎来到 StackOverflow!请向我们展示您想要的输出
0赞 Rosa 9/4/2023
嗨,马克,感谢您在 StackOverflow 上帮助我。我在消息末尾添加了一个具有所需输出的数据框作为编辑。
0赞 r2evans 9/4/2023
“A1 的范围从 indexD1 + 1 开始。因此,例如,对于 ID=5,这将从 V2 开始,而对于 ID=1,这将从 V3 开始。让我感到困惑。对于 == 5,是 2,所以是 3,这如何转化为?IDindexD12+1V2
0赞 Rosa 9/4/2023
是的,你是对的。我在编辑时更改了数据框中的一些值,以更好地说明问题。如果再次运行代码,则 ID=5 的 indexD1 现在应为 1,而 A1 的开头现在应为 2。很抱歉造成混乱!

答:

0赞 Rosa 9/4/2023 #1

因此,在经过一些反馈后,我找到了一个解决方案,即创建一个逐行遍历数据的 for 循环。喜欢这个:

df <- df %>% mutate(A1_start = indexD1 +1, A1_end = 5)

df$A1 <- NA
for (i in 1:nrow(df)){
  A1_range <- df$A1_start[i]:5
  df$A1 <- apply(df[,A1_range], 1, min)

不过,我很想知道是否有其他解决方案!