从矩阵行中挑选元素的前n%个百分比,每行元素的数量不同

时间:2018-07-05 12:02:09

标签: r loops matrix picking

我在选择前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循环无法使用。我说的对吗?

如何进行这种挑选?

2 个答案:

答案 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

我想强调一点,我认为莫里斯的答案是可以接受的,因为他的输出完全符合预期。