【问题标题】:Efficiently looping through rows and columns with if statementes使用 if 语句有效地循环遍历行和列
【发布时间】:2016-09-19 11:37:58
【问题描述】:

我有两个列名向量。每个向量都具有相同的长度和相同的名称,但只有一个数字。

columns <- paste0("q1h10_",1:9) # Filter columns
columns2 <- paste0("q1h4_", 1:9) # Columns where number is at

我想循环遍历数据框的行和向量一中的列,只要有 5,就在第二个向量中找到等效列并将数字带入其中。我还有其他条件可以带号码,你可以在下面的代码中看到。

value <- vector("numeric", nrow(psid))

for (i in 1:nrow(psid)) {
for (x in 1:length(columns)) {
    if (5 %in% psid[i, columns[x]] & all(as.numeric(psid[i, columns2[x]]) != 97:99)) {
        value[i] <- substr(columns[x], 7, 8)
    } else if (5 %in% psid[i, columns[x]] & psid[i, columns2[x]] %in% 97:99 & x != 1) {
        value[i] <- substr(columns[x - 1], 7, 8)
    } else if (5 %in% psid[i, columns[x]] & psid[i, columns2[x]] %in% 97:99 & x == 1) {
        value[i] <- 0
    }
  }
}
value
[1] "1" "2" "2" "3" "4" "0" "0" "0" "1" "0" "3" "1" "3" "2" "3" "0" "1" "3" "1" "1" "2"
[22] "2" "2" "1" "2" "3" "1" "1" "0" "1"

我设法得到了我想要的结果,但我发现这是实现它的缓慢方法。我已经尝试将其“追溯”到应用程序家庭,但我并不完全是专家,我无法正确地做到这一点。如果有人有更快、或许更易读的解决方案,我们将不胜感激。

数据:

  psid <- structure(list(q1h10_1 = c(5L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 5L, 
0L, 1L, 5L, 1L, 1L, 1L, 0L, 5L, 1L, 5L, 5L, 1L, 1L, 1L, 5L, 1L, 
1L, 5L, 1L, 0L, 5L), q1h10_2 = c(0L, 5L, 5L, 1L, 1L, 0L, 0L, 
0L, 0L, 0L, 1L, 0L, 1L, 5L, 1L, 0L, 0L, 1L, 0L, 0L, 5L, 5L, 5L, 
0L, 5L, 1L, 0L, 5L, 0L, 0L), q1h10_3 = c(0L, 0L, 0L, 5L, 1L, 
0L, 0L, 0L, 0L, 0L, 5L, 0L, 5L, 0L, 5L, 0L, 0L, 5L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 5L, 0L, 0L, 0L, 0L), q1h10_4 = c(0L, 0L, 0L, 
0L, 5L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), q1h10_5 = c(0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), q1h10_6 = c(0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), q1h10_7 = c(0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), q1h10_8 = c(0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), q1h10_9 = c(0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), q1h4_1 = c(1, 
2, 6, 4, 4, 0, 0, 0, 4, 0, 3, 4, 4, 4, 1, 0, 4, 4, 3, 1, 4, 6, 
4, 4, 4, 4, 4, 3, 0, 6), q1h4_2 = c(0, 3, 4, 3, 3, 0, 0, 0, 0, 
0, 2, 0, 6, 4, 6, 0, 0, 4, 0, 0, 6, 4, 4, 0, 6, 6, 0, 97, 0, 
0), q1h4_3 = c(0, 0, 0, 6, 2, 0, 0, 0, 0, 0, 6, 0, 6, 0, 6, 0, 
0, 6, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0), q1h4_4 = c(0, 0, 0, 
0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0), q1h4_5 = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), q1h4_6 = c(0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0), q1h4_7 = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
), q1h4_8 = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), q1h4_9 = c(0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0)), class = "data.frame", .Names = c("q1h10_1", 
"q1h10_2", "q1h10_3", "q1h10_4", "q1h10_5", "q1h10_6", "q1h10_7", 
"q1h10_8", "q1h10_9", "q1h4_1", "q1h4_2", "q1h4_3", "q1h4_4", 
"q1h4_5", "q1h4_6", "q1h4_7", "q1h4_8", "q1h4_9"), row.names = c(NA, 
-30L))

【问题讨论】:

  • 你能发布预期的结果吗?

标签: r


【解决方案1】:

我们可以使用以下方法更有效地执行您的逻辑:

value <- as.character(rep(0,nrow(psid)))

cond1 <- 5 == psid[,columns]
cond2 <- matrix(as.matrix(psid[,columns2]) %in% (97:99), nrow(psid))
ind1 <- which(cond1 & !cond2, arr.ind=TRUE)
if (length(ind1) > 0) value[ind1[,1]] <- substr(columns[ind1[,2]],7,8)
ind2 <- which(cond1 & cond2, arr.ind=TRUE)
ind2 <- matrix(ind2[ind2[,2]!=1,],ncol=2)
if (length(ind2) > 0) value[ind2[,1]] <- substr(columns[ind2[,2]-1],7,8)

我们首先计算两个布尔“矩阵”:

  1. cond1TRUE 在行 i 和列 x 如果 psid[i, columns[x]] == 5; FALSE 否则。此计算对columns 中的psid 中的所有行和所有列进行矢量化处理。
  2. 如果psid[i, columns2[x]]979899,则cond2TRUE 在行i 和列x。在这里,我们将psid[,columns2] 转换为矩阵,然后评估其元素是否为%in% (97:99)。然后将结果重新整形为具有原始尺寸的矩阵。

条件cond1 &amp; !cond2 是您的第一个if 中的条件。一旦我们对psid 中的所有行和所有列进行了评估,我们就可以使用whicharr.ind=TRUE 来检索条件为TRUE 的行和列索引。然后我们使用这些行和列进行子集化以相应地设置value

对于您的第一个elseif 中的条件,我们通过仅保留那些不是1 的列(或x)进一步子集which(cond1 &amp; cond2, arr.ind=TRUE) 的结果。同样,我们使用这些行和列进行子集化以相应地设置value

对于这两个条件的补充,我们将value 保留为"0"。请注意,which 可以返回一个空结果(即length(0)),我们必须将该条件作为边缘情况进行检查。

使用您的数据的结果符合预期:

print(value)
## [1] "1" "2" "2" "3" "4" "0" "0" "0" "1" "0" "3" "1" "3" "2" "3" "0" "1" "3" "1" "1" "2" "2"
##[23] "2" "1" "2" "3" "1" "1" "0" "1"

【讨论】:

  • 我猜purr::reduce 可以,只是,被Reduce 取代?此外,psid[, columns2] %in% (97:99) 可以更方便并且(至少在线性扫描很少的情况下)更有效。
  • @alexis_laz:感谢您的反馈。我相信如果我们将数据框转换为矩阵然后按照您的建议使用%in%,则不需要reduce
  • 你说得对,它需要转换,我错过了psid 是一个“data.frame”。然后我想,也可以预先转换为“矩阵”,这将有利于所有二进制操作。
  • 谢谢!这样就可以了。
【解决方案2】:

我认为以下代码适用于您的第一个条件(您可以轻松地将其调整为其他两个条件)

ind=apply(psid,1,function(x) return(which(x[columns] %in% 5 & all(as.numeric(x[columns2]) !=97:99))))
values2=rep("0",nrow(psid))
values2[which(ind>0)]=substr(columns[unlist(ind[which(ind>0)])], 7, 8)
values2
 [1] "1" "2" "2" "3" "4" "0" "0" "0" "1" "0" "3" "1" "3" "2" "3"
 [16] "0" "1" "3" "1" "1" "2" "2" "2" "1" "2" "3" "1" "2" "0" "1"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-24
    • 2011-09-05
    • 2020-05-02
    • 2011-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多