R功能在数据帧中查找第一个非真

时间:2016-09-01 17:38:07

标签: r function loops apply which

我试图为数据框中的每一行找到第一个非True(减1)。

结果如下:

     V1    V2    V3    V4    V5 true
1  TRUE FALSE FALSE  TRUE FALSE    1
2  TRUE FALSE FALSE FALSE    NA    1
3 FALSE FALSE FALSE FALSE  TRUE    0
4 FALSE FALSE FALSE FALSE FALSE    0
5 FALSE FALSE FALSE FALSE FALSE    0
6 FALSE FALSE FALSE FALSE FALSE    0

以下代码有效,但由于循环而耗时太长。我不确定如何使用apply语句正确执行此操作。

#Create the function to find the first non-true
min.true <- function(x,i){
min(which(x[i,]==!TRUE))-1
}

#Create a null column
match.words$true <- NA

#Find the first non true in each row
for (i in 1:nrow(match.words)){
match.words$true[i] <-  min.true(match.words,i)  

}

基本上我正在寻找能够跑得更快的这样的事情

match.words$true <- apply(match.words, 1, min.true(match.words))

谢谢,

5 个答案:

答案 0 :(得分:4)

基础R中的一个简单变体:

match.words$true <- apply(match.words, 1, which.min) - 1

功能which.min(x) 返回向量x中的最小值索引,或者在逻辑向量的情况下,返回第一个FALSE值的索引。这在?which.min的帮助页面中进行了描述:

  

Min()或Max()在哪里或第一个为TRUE或FALSE?

     

描述

     

确定位置,即数字(或逻辑)向量的(第一个)最小值或最大值的索引。

因此which.min()的输出正是我们在这种情况下所需要的。剩下要做的就是将其包含到带有边距1的apply()中以获取每行的索引,并按照问题陈述中的要求减去1

修改

如果data.frame保留所有值为TRUE的行,则会出现一种特殊情况。然后,which.min()返回这些行的第一个索引,这可能不合适。由于未找到FALSE值,因此最好返回NA。如果出现这种情况,可以在创建match.words $ true column:

之前识别相关的行
NArows <- which(apply(df1, 1, all))
match.words$true <- apply(match.words, 1, which.min) - 1
match.words$true[NArows] <- NA

答案 1 :(得分:2)

像你这样的一些数据:

t <- matrix(c(TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE,
              FALSE, FALSE, NA), nrow=2)
t
#      [,1]  [,2]  [,3]  [,4]  [,5]
# [1,]  TRUE FALSE FALSE FALSE FALSE
# [2,] FALSE  TRUE  TRUE FALSE    NA

略微修改功能:

min.true <- function(x){
  min(which(x==!TRUE))-1
}

在一行测试:

min.true(t[1,])
# [1] 1

将其应用于每一行:

apply(t, 1, min.true)
# [1] 1 0

答案 2 :(得分:2)

?max.col可以适应在这里工作,这应该相对较快。为简单起见,将@ TARehman的data_mat重命名为mat

tmp <- replace(!mat, is.na(mat), FALSE)
replace(max.col(tmp,"first")-1, rowSums(tmp)==0, NA)
#[1]  1  1  0 NA  0  0 NA  3

答案 3 :(得分:1)

你可以试试这个:

match.words$true = apply(match.words,MARGIN = 1,function(t){return(min(which(t!=T))-1)})

答案 4 :(得分:1)

这是一个使用不同机制rle功能的选项。它的好处是几乎不需要输入消毒。

data_mat <- matrix(c(TRUE, FALSE, FALSE, TRUE, TRUE,
                     TRUE, FALSE, FALSE, FALSE, NA, 
                     FALSE, FALSE, TRUE, FALSE, FALSE,
                     TRUE, TRUE, TRUE, TRUE, TRUE,
                     FALSE, TRUE, TRUE, TRUE, TRUE,
                     FALSE, FALSE, FALSE, FALSE, FALSE,
                     NA, NA, NA, NA, NA,
                     NA, NA, TRUE, FALSE, TRUE), nrow=8, byrow = TRUE)

func_first_nontrue_row <- function(input_row) {

    row <- rle(input_row)
    first_nontrue <- head(x = head(x = cumsum(c(1,row$lengths)),n = -1)[which(!row$values)],
                          n = 1) - 1
    if(length(first_nontrue) == 0) {return(-99)} else {return(first_nontrue)}
}

output <- apply(X = data_mat,MARGIN = 1,FUN = func_first_true_row)
output
## [1]   1   1   0 -99   0   0 -99   3

编辑修改和解释: rle函数创建一个对象,该对象对向量中的数据运行长度进行编码(因此rle用于运行长度编码)。

通过获取由1和lengths(起始点加上每个项目的长度)组成的向量的累积和,然后删除最后一个元素,您将获得每次运行的起始位置。使用values参数,您可以将该向量子集化为仅FALSE语句。因此,调用head()抓取第一个,并事先调用head()以删除最后一个元素。我对它进行了清理,以便通过检查输出的长度是否为0来检查没有FALSE语句的行。您可以根据需要调整它。

速度方面,我不确定这会比其他解决方案更好,但它总是能产生一些东西,因为rle调用将始终创建实际值,即使是整个NAs向量。