Why subscript is out of bounds during for loops execution? - r

In my script is it possible to get d[[x]] "empty". I tried to do it with else, but it does not work.
How to write else so that it can give a result of checking zero?
for (x in 1:licznik3)
{
if(a[[x]] > d[[x]])
{
out3[[x]] <- wspolne3[[x]]
}
else (a[[x]] < d[[x]])
{
out3[[x]] <- NA
}
}
variables:
> a
[1] 0.1
> d
numeric(0)
> licznik3
[1] 16
Error in d[[x]] : subscript out of bounds
Example:
I have 3 loops.
If a[[x]] is greater than d[[x]]
this value goes to out3
and the next loop checks a similar condition.
My problem is that in the second loop (shown code) d[[x]] can be empty (in the previous loop no value was greater than a[[x]])
Then we have how
> a
  [1] 0.1
> d
numeric (0)

Just add additional check that your counter aka licznik3 ;) would not exceed length of vector d. If it exceeds break for-loop.
a <- 1:10
licznik3 <- 7
out3 <- rep_along(a, NA)
wspolne3 <- 2:12
d <- -c(1, 4, 2)
for (x in 1:licznik3) {
if (x > length(d)) {
break
}
if (a[[x]] > d[[x]]) {
out3[[x]] <- wspolne3[[x]]
} else {
out3[[x]] <- NA
}
}
out3

Related

Find Previous Prime Number using R

I am trying to find Previous Prime number of given value. The mentioned code works fine if I pass prime Number straight away as input lp(7) returns 7. But if I pass lp(6) none are displaying. I am expecting 5 to return.
How do I find the previous prime Number for given one.
Suggestions / Corrections are much appreciated
lp <- function(x){
temp <- x:2
while (x == 2L || all(x %% 2L:max(2,floor(sqrt(x))) != 0))
{
return(x)
}
}
If you run this function a lot of times, probably most efficient is to generate a list of primes once, and search where your value lies in that sequence
library(primes)
primes = generate_primes(2, 1e6)
find_lower_prime = function(x) {
primes[findInterval(x, primes)]
}
find_lower_prime(6)
# [1] 5
You can use the following
lp <- function(x){
previousNumbers <- 2:x
previousPrimes <- sapply(previousNumbers, function(num) {
divisorsToCheck <- 2:max(2,floor(sqrt(num)))
if(num == 2 | all(num %% divisorsToCheck != 0)) {
return(num)
} else {
return(NA)
}
})
previousPrimes[!is.na(previousPrimes)]
}
to get all previous primes.
lp(18) # 2 3 5 7 11 13 17
lp(5) #2 3 5
You can try the code lie below
lp <- function(x) {
p <- x - 1
repeat {
if (p %in% c(2, 3) | all(p %% ceiling(sqrt(2:p)) != 0)) {
return(p)
}
p <- p - 1
}
}
and you will see
> lp(5)
[1] 3
> lp(6)
[1] 5
> lp(7)
[1] 5
> lp(8)
[1] 7
> lp(11)
[1] 7
Hi All this worked for me ..
lp <- function(x){
for(i in x:2)
{
while (i == 2L || all(i %% 2L:max(2,floor(sqrt(i))) != 0))
{
return(i)
}
}
}

how to create function with input from dataframe and apply it over all rows?

I try to write a function in R which takes several variables from a dataframe as input and gives a vector with results as output.
Based on this post below I did write the function below.
How can create a function using variables in a dataframe
Although I receive this warning message:
the condition has length > 1 and only the first element will be used
I have tried to solve it by the post below using sapply in the function although I do not succeed.
https://datascience.stackexchange.com/questions/33351/what-is-the-problem-with-the-condition-has-length-1-and-only-the-first-elemen
# a data frame with columns a, x, y and z:
myData <- data.frame(a=1:5,
x=(2:6),
y=(11:15),
z=3:7)
myFun3 <- function(df, col1 = "x", col2 = "y", col3 = "z"){
result <- 0
if(df[,col1] == 2){result <- result + 10
}
if(df[,col2] == 11){result <- result + 100
}
return(result)
}
myFun3(myData)
> Warning messages:
> 1: In if (df[, col1] == 2) { :
> the condition has length > 1 and only the first element will be used
> 2: In if (df[, col2] == 11) { :
> the condition has length > 1 and only the first element will be used
Can someone explain me how I can apply the function over all rows of the dataframe?
Thanks a lot!
We need ifelse instead of if/else as if/else is not vectorized
myFun3 <- function(df, col1 = "x", col2 = "y", col3 = "z"){
result <- numeric(nrow(df))
ifelse(df[[col1]] == 2, result + 10,
ifelse(df[[col2]] == 11, result + 100, result))
}
myFun3(myData)
#[1] 10 0 0 0 0
Or the OP's code can be Vectorized after making some changes i.e. remove the second if with an else if ladder
myFun3 <- Vectorize(function(x, y){
result <- 0
if(x == 2) {
result <- result + 10
} else if(y == 11){
result <- result + 100
} else result <- 0
return(result)
})
myFun3(myData$x, myData$y)
#[1] 10 0 0 0 0
Regarding the OP's doubts about when multiple conditions are TRUE, then want only the first to be executed, the ifelse (nested - if more than two) or if/else if/else (else if ladder or if/else nested) both works because it is executed in that same order we specified the condition and it stops as soon as a TRUE condition occurred i.e. suppose we have multiple conditions
if(expr1) {
1
} else if(expr2) {
2
} else if(expr3) {
3
} else if(expr4) {
4
} else {
5}
checks the first expression ('expr1') first, followed by second, and so on. The moment it return TRUE, it exit i.e. it is a nested condition
if(expr1) {
1
} else {
if(expr2) {
2
} else {
if(expr3) {
3
} else {
if(expr4) {
4
} else 5
}
}
}
There is a cost for this i.e.. whereever we have the more values that matches the 1, only the expr1 is executed and thus saves time, but if there are more 5 values, then all those conditions are checked

Error argument is of length zero occurs when creating my own sorting function

*> csort <- function(c){
i<-1
for (i in 1:length(c)-1) {
j <- i+1
for (j in 2:length(c)) {
if(c[i] >= c[j])c[c(i,j)] <- c[c(j,i)]
j = j + 1
}
i = i + 1
}
}
> csort(a)
Error in if (c[i] >= c[j]) c[c(i, j)] <- c[c(j, i)] :
argument is of length zero*
This is what RStudio do when I run it. I do not know what cause the zero here.
csort <- function(c){
p <- 1
povit <- c[1]
c <- c[-1]
left <- c()
right <- c()
left <- c[which(c <= povit)]
right <- c[which(c > povit)]
if(length(left) > 1){
left <- csort(left)
}
if(length(right) > 1){
right <- csort(right)
}
return(c(left ,povit,right))
}
I viewed more about sorting online and this is a pivot sort way.
your mistake is in this line
for (i in 1:length(c)-1)
and should be
for (i in 1:(length(c)-1))
since $:$ operator precedes $-$.
an example is
1:(5-1)
#[1] 1 2 3 4
1:5-1
#[1] 0 1 2 3 4
so error happen in index with Zero value.
csort <- function(d){
for (i in 1:(length(d)-1)) {
for (j in (i+1):length(d)) {
if(d[i] >= d[j])d[c(i,j)] <- d[c(j,i)]
}
}
return(d)
}
d<-c(5:1,-1:3,-9,-3,10,9,-20,1,20,-6,5)
any((csort(d)==sort(d))==F)
#[1] FALSE
you can improve this function.

About missing value where TRUE/FALSE needed in R

I want to return the number of times in string vector v that the element at the next successive index has more characters than the current index.
Here's my code
BiggerPairs <- function (v) {
numberOfTimes <- 0
for (i in 1:length(v)) {
if((nchar(v[i+1])) > (nchar(v[i]))) {
numberOfTimes <- numberOfTimes + 1
}
}
return(numberOfTimes)
}
}
missing value where TRUE/FALSE needed.
I do not know why this happens.
The error you are getting is saying that your code is trying to evaluate a missing value (NA) where it expects a number. There are likely one of two reasons for this.
You have NA's in your vector v (I suspect this is not the actual issue)
The loop you wrote is from 1:length(v), however, on the last iteration, this will try the loop to try to compare v[n+1] > v[n]. There is no v[n+1], thus this is a missing value and you get an error.
To remove NAs, try the following code:
v <- na.omit(v)
To improve your loop, try the following code:
for(i in 1:(length(v) -1)) {
if(nchar(v[i + 1]) > nchar(v[i])) {
numberOfTimes <- numberOfTimes + 1
}
}
Here is some example dummy code.
# create random 15 numbers
set.seed(1)
v <- rnorm(15)
# accessing the 16th element produces an NA
v[16]
#[1] NA
# if we add an NA and try to do a comparison, we get an error
v[10] <- NA
v[10] > v[9]
#[1] NA
# if we remove NAs and limit our loop to N-1, we should get a fair comparison
v <- na.omit(v)
numberOfTimes <- 0
for(i in 1:(length(v) -1)) {
if(nchar(v[i + 1]) > nchar(v[i])) {
numberOfTimes <- numberOfTimes + 1
}
}
numberOfTimes
#[1] 5
Is this what you're after? I don't think there is any need for a for loop.
I'm generating some sample data, since you don't provide any.
# Generate some sample data
set.seed(2017);
v <- sapply(sample(30, 10), function(x)
paste(sample(letters, x, replace = T), collapse = ""))
v;
#[1] "raalmkksyvqjytfxqibgwaifxqdc" "enopfcznbrutnwjq"
#[3] "thfzoxgjptsmec" "qrzrdwzj"
#[5] "knkydwnxgfdejcwqnovdv" "fxexzbfpampbadbyeypk"
#[7] "c" "jiukokceniv"
#[9] "qpfifsftlflxwgfhfbzzszl" "foltth"
The following vector marks the positions with 1 in v where entries have more characters than the previous entry.
# The following vector has the same length as v and
# returns 1 at the index position i where
# nchar(v[i]) > nchar(v[i-1])
idx <- c(0, diff(nchar(v)) > 0);
idx;
# [1] 0 0 0 0 1 0 0 1 1 0
If you're just interested in whether there is any entry with more characters than the previous entry, you can do this:
# If you just want to test if there is any position where
# nchar(v[i+1]) > nchar(v[i]) you can do
any(idx == 1);
#[1] TRUE
Or count the number of occurrences:
sum(idx);
#[1] 3

lapply needs boolean after if-statement condition

I'm new to R. I wrote a function that applies to numbers and want to apply it to a numeric of length 400. It goes
EGIDS.to.IUCN <- function(x){
if(x==10){return(NA)} # 10 (Extinct)
if(x==9){return(NA)} # 9 (Dormant)
if(x==8.5){return(4)} # 8.5 (Nearly Extinct) → 4 (Critically endangered)
# 10 more similar lines here (no more NAs)
else{stop}
}
I tried using lapply but then I get
> austroIUCN <- lapply(austroEGIDS, EGIDS.to.IUCN)
Error in if (x == 10) { : missing value where TRUE/FALSE needed
Where austroEGIDS is a list of 400 numbers from 0 to 10. I'm totally lost here. Why does it expect a boolean after closing the if condition?
It would be more efficient if you use a numeric vector and work with vectorized statements:
austroIUCN <- unlist(austroEGIDS)
austroIUCN[austroIUCN==10 | austroIUCN==9] <- NA
austroIUCN[austroIUCN==8.5] <- 4
...
Each statements sets all entries with the given level.
Without the stop this should work,
EGIDS.to.IUCN <- function(x) {
if (is.na(x)){ NA } else
if (x == 10) { NA } else
if (x == 9) { NA } else
if(x == 8.5) { 4 } else
NA
}
or, more readable and faster,
EGIDS.to.IUCN <- function(x){
switch (x, 'NA'=NA, '10'=NA, '9'=NA, '8.5'=4, NA)
}
austroEGIDS <- sample(seq(1, 10, .5), 400, replace = TRUE)
austroIUCN <- sapply(austroEGIDS, EGIDS.to.IUCN)
table(unlist(austroIUCN), useNA = "ifany")
austroIUCN
4 <NA>
23 377
Or if you want it to stop and throw an error if not a match,
EGIDS.to.IUCN <- function(x){
switch (x, 'NA'=NA, '10'=NA, '9'=NA, '8.5'=4, stop("Not a match!"))
}

Resources