如何在R中构建二元变量?

5

目的是检查索引i处的值是否为1,然后将前六个条目设为1。

x <- c(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1)

## Required output 
y <- c(1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1)

## Attempt 
for(j in seq_along(x)){
if(x[j] == 1){
   for(i in (j-6):j)
   x[i] = 1
   }}

你能帮忙解决这个问题或提供更好的方案吗?

谢谢。

4个回答

5
你可以尝试以下选项(不要忘记在尝试每个选项时初始化x,因为我正在覆盖它)
indx <- mapply(function(x, y) x:y, which(x == 1) - 6 , which(x == 1))
x[indx[indx > 0]] <- 1
x
## [1] 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1

甚至更简单
indx <- sapply(which(x == 1) - 6, function(x) x:(x + 6))
x[indx[indx > 0]] <- 1
x
## [1] 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1

或者

indx <- apply(cbind(which(x == 1) - 6 , which(x == 1)), 1, function(x) x[1]:x[2])
x[indx[indx > 0]] <- 1
x
## [1] 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1

或者

indx <- seq_len(6)
indx <- sapply(which(x == 1), function(x) x - indx)
x[indx[indx > 0]] <- 1
x
## [1] 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1

我试图在索引上使用apply函数,但没有考虑使用apply提取索引,然后将所有这些分配为1。谢谢您提供的这个逻辑。 - Anusha

5

使用完全向量化的解决方案,使用 filter

as.integer( #turn logical value into numbers
  as.logical( #coerce to logical --> 0 becomes FALSE, everything else TRUE
   rev( #reverse order
    filter( #linear filtering
      c(rep(0, 6), #pad with zeros in the beginning to avoid NAs
        rev(x)), #revers order of input vector
          c(rep(1, 7)), sides=1 #y_i = x_i * 1 + x_(i-1) * 1 +...+ x_(i-6) * 1 
  )[-(1:6)]))) #remove NA values

#[1] 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1

(+1) 很好的向量化。 - David Arenburg
滤波器不是用于移动平均类型的计算吗?您能解释一下在这种情况下滤波器函数是如何工作的吗?谢谢。 - Anusha
“filter”计算移动总和(对于过去的值或两侧窗口)。如果移动总和不为零,则将其转换为1。 - Roland
+1 太棒了。我想到了 rollapply,但没有想到采取移动求和的方法。 - Anusha

3

使用'for'循环:

ddf = data.frame(x,y=0)
for(i in 1:nrow(ddf)){
    if(ddf[i,'x']==1){
        j = i-5
        if(j<1) j=1
        ddf[j:i,'y'] = 1
    }
}
ddf
   x y
1  0 1
2  0 1
3  0 1
4  1 1
5  0 0
6  0 0
7  0 0
8  0 0
9  0 0
10 0 0
11 0 0
12 0 1
13 0 1
14 0 1
15 0 1
16 0 1
17 1 1
18 0 1
19 1 1

y = ddf$y
y
 [1] 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1

谢谢您的回复。您能解释一下为什么我的循环返回的y向量全部都是1吗?我在这里为什么需要一个数据框架? - Anusha
您没有修正如果j-6小于1的话。同时,data.frame更易于处理。 - rnso
+1. 是否可以将此代码放入一个函数中,然后使用apply函数?只是好奇sapply或lapply如何定义这个for循环。 - Anusha
请查看David和CathG的回答。 - rnso
是的,但他们在使用apply提取索引,然后将其分配为1。我想知道如何将此处的for循环转换为lapply。 - Anusha

2
y<-x
y[unlist(sapply(which(x==1),
                function(val){
                   val:(max(val-6,1))
                 }
                )
        )
  ]<-1

> y
 [1] 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1

解释:

我首先使用 which(x==1) 查找x=1的索引。然后,对于每个索引,我使用sapply(...)获取从x=1到前6个的索引,然后将结果展开为只有y必须为1的索引向量。然后,我将相应的y值赋值为1。

另一种写法,分为2步:

y<-x
ind<-unlist(sapply(which(x==1),function(val){val:(max(val-6,1))}))
y[ind]<-1

> y
 [1] 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1

谢谢您的回复。您能解释一下如何定义这个函数吗?我正在寻找一个*apply方法。那个赋值<- 1是怎么工作的? - Anusha
@Anusha,我编辑了我的答案并添加了解释,请告诉我现在是否可以或者您需要我详细说明一下。 - Cath
我理解了那部分。我对 {val:(max(val-6,1))}))]<-1 的括号和逻辑很好奇。 - Anusha
@Anusha 我“重新组织”了我的答案,这样你就可以更清楚地看到哪些内容与哪些内容相关:应用于which(x==1)每个元素的函数计算了应该为一的y值的索引,但实际上是sapply函数的整个未列出结果(在这种情况下为4 3 2 1 17 16 15 14 13 12 11 19 18 17 16 15 14 13)真正放在括号之间。最后,这就像写y[c(4,3,2,1,17,16,15,14,13,12,11,19,18,17,16,15,14,13)]<-1。我希望我正确理解了你的评论,并且回答了它。 - Cath

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接