user9292
user9292

Reputation: 1145

Creating a new variable with For loop in R

I have a data set in R. Variable x is binary (0 or 1), and I need to create a new variable, y, such that if x[i] is 0 then y[i] is 0, but if x[i] is 1, then y[i]=1, y[i+1]=1, and y[i+2]=1. This is what I have done, but it's not working for some reason. Any help is appreciated.

for (i in 1:length(mydata$x) ) {    
  if(mydata$x==1) {
    mydata$y[i] <- 1
    mydata$y[i+1] <- 1
    mydata$y[i+2] <- 1
  } else {
    mydata$y[i] <- 0
  }    
}

Here is an example of the data:

x   y
0   0
0   0
0   0
1   1
0   1
0   1
0   0
0   0
1   1 # this is the last row, so '1' should only be added once.

Upvotes: 1

Views: 2092

Answers (2)

Juli&#225;n Urbano
Juli&#225;n Urbano

Reputation: 8488

Answer to edited question:

First, initialize y to all zeros, and then check x only for ones (do nothing if you find a zero):

mydata$y <- 0
for (i in 1:nrow(mydata))
  if(mydata$x[i] == 1)
    mydata$y[i:min((i+2),nrow(mydata))] <- 1

Answer to old question:

You are not indexing mydata$x in the if condition. Change to this:

for (i in 1:length(mydata$x) ) {
  if(mydata$x[i] == 1) { # here
    mydata$y[i] <- 1
    mydata$y[i+1] <- 1
    mydata$y[i+2] <- 1
  } else {
    mydata$y[i] <- 0
  }
}

Note that if x[i]==1 and x[i+1]==0, then you'll do y[i+1]<-1 and then y[i+1]<-0, changing what you did when checking x[i]==1. Also, if the last or second to last value in x is 1, you'll be trying to set a value in y beyond its limits when doing y[i+1]<-1 and y[i+2]<-1, which will give you an error. I doubt this is what you really want.

Example:

mydata <- structure(list(x = c(0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 1L), 
            y = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA)), .Names = c("x", 
            "y"), row.names = c(NA, -10L), class = "data.frame")

You'll get:

Error in $<-.data.frame(*tmp*, "y", value = c(0, 0, 0, 0, 0, 1, 1, : replacement has 11 rows, data has 10

You can try fixing with:

for (i in 1:length(mydata$x) ) {
  if(mydata$x[i] == 1) {
    mydata$y[i:min((i+2),nrow(mydata))] <- 1
  } else {
    mydata$y[i] <- 0
  }
}

Upvotes: 2

Ricardo Saporta
Ricardo Saporta

Reputation: 55350

Vectorized approach

Here it is as a one-liner. Below is a breakdown of the approach

y <- as.numeric(seq_along(x) %in% outer(which(!!x), 0:2, "+"))


if you have an index of the values of x which are 1, you simply add 0:2 to each element of those index and you get the index to y which should be 1

y <- rep(0, length(x))

inds <- which(x==1)

## add c(0, 1, 2) to each element of inds
inds <- outer(inds, 0:2, "+")

## make it into a vector
inds <- unique(as.vector(inds))

y[inds] <- 1

Upvotes: 2

Related Questions