我在选择前n%个最大和最小的元素时遇到问题 来自每个数据矩阵行。具体来说,我想找到前n%个元素的列号。如果每一行具有相同数量的非NA元素,这将不是问题,但是在这种情况下,每一行的拾取元素数量是不同的。这是这种情况的示例(实际数据矩阵为195x1030,所以我不会在这里使用它),其中前40%被选中
data=
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 1 NA 100 98 200 78 80 35 NA 55
[2,] 32 67 15 73 NA 12 91 230 3 99
[3,] NA NA NA 45 53 26 112 64 80 41
[4,] 54 38 60 70 163 69 109 205 5 31
[5,] 107 28 296 254 30 40 NA 18 28 90
产生的前40%列数矩阵应如下所示(选取的元素的数量是通过舍入计算的,就像integer函数一样)
largest= smallest=
[,1] [,2] [,3] [,4] [,1] [,2] [,3] [,4]
[1,] 5 3 4 NA [1,] 1 8 10 NA
[2,] 8 10 7 NA [2,] 9 6 3 NA
[3,] 7 9 NA NA [3,] 6 10 NA NA
[4,] 8 5 7 4 [4,] 9 10 2 1
[5,] 3 4 1 10 [5,] 8 9 2 5
因此,仅查看行的非NA元素即可选择最上面的数字。例如,数据矩阵的第一行仅包含8个非NA编号,因此选择40%* 8 = 3,2〜3个元素。这将为所得矩阵创建NA。
我再次尝试使用for循环(此代码是找到最大的40%):
largest <- matrix(rep(NA, 20), nrow = 5)
for(i in 1:5){
largest[i,]<-order(data[i,], decreasing=T)
[1:as.integer(0.4*nrow(data[complete.cases(data[,i]),]))]
}
但是R返回一个错误:“要替换的项目数不是替换长度的倍数”,我认为这意味着,由于并不是在循环时并没有替换原始最大矩阵的所有元素,因此此for循环无法使用。我说的对吗?
如何进行这种挑选?
答案 0 :(得分:1)
以下内容再现了您的预期输出
# Determine number of columns for output matrix as
# maximum of 40% of all non-NA values per row
ncol <- max(floor(apply(mat, 1, function(x) sum(!is.na(x))) * 0.4))
# Top 40% largest
t(apply(mat, 1, function(x) {
n <- floor(sum(!is.na(x)) * 0.4);
replace(rep(NA, ncol), 1:n, order(x, decreasing = T)[1:n])
}))
# [,1] [,2] [,3] [,4]
#[1,] 5 3 4 NA
#[2,] 8 10 7 NA
#[3,] 7 9 NA NA
#[4,] 8 5 7 4
#[5,] 3 4 1 NA
# Top 40% smallest
t(apply(mat, 1, function(x) {
n <- floor(sum(!is.na(x)) * 0.4);
replace(rep(NA, ncol), 1:n, order(x, decreasing = F)[1:n])
}))
# [,1] [,2] [,3] [,4]
#[1,] 1 8 10 NA
#[2,] 9 6 3 NA
#[3,] 6 10 NA NA
#[4,] 9 10 2 1
#[5,] 8 2 9 NA
说明:我们首先确定两个输出矩阵的最大列数;然后,我们逐行遍历mat
,确定非n
条目的行特定编号NA
,对应于所有非NA
数字中的40%该行,并返回填充了vector
的前40%减少/增加的条目中的列NA
。最终转置给出了预期的输出。
答案 1 :(得分:1)
以函数形式发布我的(不太准确和非常相似的)答案,这可能很方便:
toppct <- function(x, p, largest = TRUE){
t(apply(x, 1, function(y){
c(which(y %in% sort(y, decreasing = largest)[1:floor(length(which(!is.na(y)))*p)]),
rep(NA, floor(length(y)*p) - floor(length(which(!is.na(y)))*p)))
}))
}
这将产生问题的输出,而无需对排名靠前的位置进行排序。对于smallest
,只需设置largest = FALSE
。
> toppct(mat, .4)
[,1] [,2] [,3] [,4]
[1,] 3 4 5 NA
[2,] 7 8 10 NA
[3,] 7 9 NA NA
[4,] 4 5 7 8
[5,] 1 3 4 NA
> toppct(mat, .4, largest = FALSE)
[,1] [,2] [,3] [,4]
[1,] 1 8 10 NA
[2,] 3 6 9 NA
[3,] 6 10 NA NA
[4,] 1 2 9 10
[5,] 2 8 9 NA
我想强调一点,我认为莫里斯的答案是可以接受的,因为他的输出完全符合预期。