Simple for Loop in R Producing "Replacement Has Length Zero" in R

for Loop - Replacement has length zero

This error indicates that your input id is either NULL or a length 0 vector: make sure the indices are correct.

Additionally, in R it is usually best to avoid for loops as they tend to be pretty slow: see Why are loops slow in R?. There's almost always a way to avoid using a for loop and using a vectorised function instead, although the example as it stands doesn't provide enough detail to actually suggest a function.

R Error: replacement has length zero

You are getting that error, because you are trying to assign a value of length zero. Put this line of code print(which(cP[c((i):(length(indicator.Trade)-1))]==-1)) inside else if() block and see the error comes from there. It is because : is used to get sequence between two numbers. Here you are trying to get the sequence with null value, which is invalid operation. It occurs for column 12 in the else if block. I added the print statement in the code below as well.

Try this small exercise to see what is happening

a1 <- NULL   # create a null variable
1:a1 # generate sequence using `:`
# Error in 1:a1 : argument of length 0

This is why I used seq_len function in the for loop. Read ?seq_len and ?seq_along man pages.

Modified code

indicator.Trade=c(1,1,0,0,-1,0,0,0,1,1,0,-1,-1)
cP=c(NA,NA,1,1,NA,-1,NA,NA,1,NA,NA,1,NA)
len_ind_tr <- length(indicator.Trade)

order.book <- matrix(0,nrow=2,ncol=len_ind_tr-1))

for(i in seq_len(len_ind_tr-1)){
if(indicator.Trade[i] == 1){
order.book[1,i] <- i
order.book[2,i] <- which(cP[i:(len_ind_tr-1)] == 1)[1]
} else if(indicator.Trade[i] == -1){
order.book[1,i] <- i
order.book[2,i] <- which(cP[i:(len_ind_tr-1)] == -1)[1]
print(which(cP[i:(len_ind_tr-1)] == -1))
} else {
order.book[1,i] <- i
order.book[2,i] <- 0
}
}

order.book
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
# [1,] 1 2 3 4 5 6 7 8 9 10 11 12
# [2,] 3 2 0 0 2 0 0 0 1 3 0 NA

How can I avoid replacement has length zero error

It depends on your needs, but bottom line you need to add some if statement. How you use it depends on whether you want the default value of the vector to persist. In your code, while feature starts as a logical vector, it is likely coerced to integer or numeric once you overwrite its first value with a number. In that case, the default value in all positions of the vector will be 0 (or 0L, if integer). That's going to influence your decision on how to use the if statement.

if (length(x)) feature[i] <- x

This will only attempt to overwrite the ith value of feature if the x objects has length (that's equivalent to if (length(x) > 0)). In this case, since the default value in the vector will be zero, this means when you are done that you will not be able to distinguish between an element known to be 0 and an element that failed to find anything.

The alternative (and my preference/recommendation):

feature[i] <- if (length(x)) x else NA

In this case, when you are done, you can clearly distinguish between known-zero (0) and uncertain/unknown values (NA). When doing math operations on that vector, you might want/need na.rm=TRUE ... but it all depends on your use.

BTW, as MartinGal noted, your use of reduce(totalfreq, '+') is a little flawed: 'x' may not be (is not?) recognized as a known function. The first fix to this is to use backticks around the function, so

totalfreq <- 5:7
reduce(totalfreq, '+')
# NULL
reduce(totalfreq, `+`)
# [1] 18
sum(totalfreq)
# [1] 18

There the last is the much-more-preferred method. Why? With a vector of length 4, for instance, it takes the first two and adds them, then takes that result and adds it to the third, then takes that result and adds to the fourth. Three operations. When you have 100 elements, it will make 99 individual additions. sum does it once, and this does have an effect on performance (asymptotically).

However, if totalfreq is instead a list, then this changes slightly:

totalfreq <- as.list(5:7)
reduce(totalfreq, `+`)
# [1] 18
sum(totalfreq)
# Error in sum(totalfreq) : invalid 'type' (list) of argument
# x
sum(unlist(totalfreq))
# [1] 18

The reduce code still works, and the sum by itself fails, but we can unlist the list first, effectively creating a vector, and then call sum on that. Much much faster asymptotically. And perhaps clearer, more declarative.

(I'm assuming purrr::reduce, btw ...)

Loop - Replacement has length zero

Here, else (i > 1) should be else if (i > 1)

if (i == 1) {
val[i] = Put[i]*(1+ret1[i]) # statement 1
} else (i > 1)
val[i] = ((val[i-1])+Put[i])*(1+ret1[i]) # statement 2

Basically, as of now, # statement 2 is executed for all i. The else statement doesn't take any argument.

if (...) {
# do this 1
else if (...) {
# do this 2
else {
# do this 3
}

So, here i > 1 is # do this 3. So, # statement 2 is outside the if-else condition. And i will be run for all i. But the error happens at the first run, for i = 1 because val[i-1] = val[0] = numeric(0). And numeric(0) + Put[i])*(1+ret1[i]) = numeric(0) again. And you're assigning this numeric(0) (element of length 0) to an element of length 1 which is not possible.

ifelse function - replacement has length zero R

You may want to try this structure for your ifelse statement

SSS<-rep(NA,length(Xx))

for(i in 2:length(Xx)){

SSS[i] <- ifelse(length(which(Xx[B[i,]:S[i,],] >= .004)) > 0,
# If there are any values GTE .004, then return the first result GTE .004
Xx[head(which(Xx[B[i,]:S[i,],] >= .004), n=1),],
# If there are no values GTE .004, then return the last value of subset
tail(Xx[B[i,]:S[i,],]),n=1))
}


Related Topics



Leave a reply



Submit