【问题标题】:R for skip to the next row if condition met and then another condition to checkR 如果条件满足则跳到下一行,然后检查另一个条件
【发布时间】:2016-12-04 09:41:32
【问题描述】:

我知道已经发布了很多问题,但我无法将解决方案应用于我的问题。

我有一个包含许多行和列的数据集。下面是一个示例:

V7  V8  V9
0   1   0
-1  1   -1
-1  1   -1
-1  0   -1
-1  0   -1
-1  0   -1
-1  0   -1
-1  1   -1
0   1   -1
0   1   -1
-1  0   0
0   0   0
0   0   0
0   0   0
0   0   0
0   -1  0
0   -1  -1
0   0   0
0   1   0
0   0   0

此数据保存在矩阵trboot3 我想做的是创建一个循环,检查两个条件并更改数据。

  1. 如果有零,跳到下一行。
  2. 如果连续有一个相同的数字,则保留第一个数字并将其余数字更改为零。

这是我上面循环的代码:

trboot4<-trboot3
valboot<-length(trboot3[,1])
for (k in 1:length(trboot3[1,])){
  for (i in 2:valboot-1){
    if (trboot3[k,i]==0) {i<-i+1}
    else{
      if(trboot3[k,i] == trboot3[k,i+1]){
        for (j in i+1:valboot){ if(trboot3[k,j] == trboot3[k,i]){trboot4[k,j]<-0}else{break}
          if(j==valboot){break}
        }
      }
    }
  }
}

我想将新矩阵保存在trboot4

基本上上面的示例应该变成:

V7  V8  V9
0   1   0
-1  0   -1
0   0   0
0   0   0
0   0   0
0   0   0
0   0   0
0   1   0
0   0   0
0   0   0
-1  0   0
0   0   0
0   0   0
0   0   0
0   0   0
0   -1  0
0   0   -1
0   0   0
0   1   0
0   0   0

【问题讨论】:

  • 当前循环是否有效?如果有效,是不是太慢了?
  • 嗨@digEmAll 没有错误除了subscript out of bounds 当前循环。但我的 trboot4 输出与 trboot3 相同。不,至少对我来说并不慢。
  • 我提供了一个不使用循环的解决方案,顺便说一句,您可以使用 nrow 和 ncol 函数来获取矩阵的列数和行数,您不需要这样做:length(m[,1]) 等...

标签: r loops if-statement


【解决方案1】:

您可以使用rleapply 函数:

# re-create your matrix
trboot3 <- structure(c(0,-1,-1,-1,-1,-1,-1,-1,0,0,-1,0,0,0,0,0,0,0,0,0,1,1,1,
0,0,0,0,1,1,1,0,0,0,0,0,-1,-1,0, 1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,
-1,0,0,0),.Dim = c(20L, 3L), .Dimnames = list(NULL, c("V7", "V8", "V9")))

keepFirstValueIfRepeated <- function(v){
  RLE <- rle(v)
  firstIndex <- (cumsum(RLE$lengths)- RLE$lengths + 1)
  v2 <- rep.int(0,length(v))
  v2[firstIndex] <- RLE$values
  return(v2)
}

trboot4 <- apply(trboot3,2,FUN=keepFirstValueIfRepeated)

结果:

 > trboot4
      V7 V8 V9
 [1,]  0  1  0
 [2,] -1  0 -1
 [3,]  0  0  0
 [4,]  0  0  0
 [5,]  0  0  0
 [6,]  0  0  0
 [7,]  0  0  0
 [8,]  0  1  0
 [9,]  0  0  0
[10,]  0  0  0
[11,] -1  0  0
[12,]  0  0  0
[13,]  0  0  0
[14,]  0  0  0
[15,]  0  0  0
[16,]  0 -1  0
[17,]  0  0 -1
[18,]  0  0  0
[19,]  0  1  0
[20,]  0  0  0

说明:

让我们从第一个自定义函数 keepFirstValueIfRepeated 开始,它获取一个向量 v,并且只保留连续相等值序列中的第一个值,将其他值强制为零。
它是如何实现的?

我们使用rle函数,它对于分析连续相等值的子序列非常有用,实际上它返回一个包含子序列长度和每个子序列重复值的列表。
这个想法是只保留重复值子序列的第一个元素;所以,首先,我们计算包含子序列第一个元素的所有索引的firstIndex,然后我们创建一个与v长度相同但全为零的向量v2,最后我们把v2 内的子序列的第一个值。

之后,我们需要将这个函数(keepFirstValueIfRepeated)“应用”到trboot3的每一列,而这正是apply(matrix,2,FUN)所做的

【讨论】:

  • 嗨@digEmAll 我能麻烦你解释一下 rle 函数在这种情况下是如何工作的吗?谢谢
  • 是的,我正在这样做;)
  • 谢谢,因为我必须进一步编写代码,并且可能最终会使用类似的代码,因为循环不起作用
  • @Ash:我已经简化了代码并写了解释……希望够清楚……
  • 非常感谢......通过解释很容易理解代码。
【解决方案2】:

另一种解决方案:

library(Hmisc)
trboot4 = apply(trboot3, 2, function(c) c * (c!=Lag(c)))
trboot4[1,] = trboot3[1,]

【讨论】:

  • 你好!你能解释一下 Lag() 函数是如何工作的吗?谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-05
  • 1970-01-01
相关资源
最近更新 更多