提问人:Rosa 提问时间:9/4/2023 最后编辑:Rosa 更新时间:9/4/2023 访问量:91
在 R 中按行计算可变列范围的最小值/最大值
Calculate rowwise Min/Max across a variable range of columns in R
问:
对于 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
答:
因此,在经过一些反馈后,我找到了一个解决方案,即创建一个逐行遍历数据的 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)
不过,我很想知道是否有其他解决方案!
评论
ID
indexD1
2+1
V2