R function returning no value

Viewed 73
x <- c(2.2, 7.8, -4.4, 0.0, -1.2, 3.9, 4.9, 2.0, -5.7, -7.9, -4.9,  28.7,  4.9)

quartiles<-function(x){
bound<-quantile(x)
MED<-median(x)
k<-c(). #put values of x less than median in vector K
S<-c(). #put values of x larger than median in vector S

for(i in 1:length(x)){
  if (x[i]<MED){
K<-x[i]}
else{S<-x[i]
}
i<i+1
}
  iqr1<-c(median(k)-median(S)) #calculate interquartile for x
return(list(bound[2],bound[4], iqr1))  
}

I would like to get the value in return for iqr1 but I am getting:

quartiles(x) [[1]] 25% -4.4

[[2]] 75% 4.9

[[3]] numeric(0)

3 Answers

The previous answer helps but isn't quite correct yet. One issue is that in your code, you're overwriting your k and S variables, not making a vector. Another is that you always add the median to S which gives you different types of IQR calculations depending on whether you have an even or odd number of items in your vector of numbers (x) and whether the median is in the vector or not.

This version addresses the coding issues, but not the statistical issues of how to calculate the IQR consistently.

quartiles <- function(x){
  bound <- quantile(x)
  MED <- median(x)
  k <- vector(mode="numeric") # empty vector for values of x less than median 
  S <- vector(mode="numeric") # empty vector for values of x larger than or equal to median 
  for(i in 1:length(x)){
    if(x[i]<MED){
      k <- append(k, x[i]) # append or add values to k
      }
    else if(x[i]>MED){
      S <- append(S, x[i]) # append or add values to S
      }
  }
  iqr1 <- c(median(S)-median(k)) # calculate interquartile range for x
  ## prints can be commented out once you know things are working 
  print(sort(k)) # sorted vector of values of x less than median
  print(median(k))
  print(sort(S)) # sorted vector of values of x larger than or equal to median
  print(median(S))
  print(iqr1)
  return(list(bound[2],bound[4], iqr1))  
  }

now to test it,

qx <- quartiles(x)

produces (due to the print statements):

[1] -7.9 -5.7 -4.9 -4.4 -1.2  0.0
[1] -4.65
[1]  2.2  3.9  4.9  4.9  7.8 28.7
[1] 4.9
[1] 9.55

and qx shows the returned object:

[[1]]
 25% 
-4.4 
[[2]]
75% 
4.9 
[[3]]
[1] 9.55

for comparison, using the functions in R:

> quantile(x)
  0%  25%  50%  75% 100% 
-7.9 -4.4  2.0  4.9 28.7 

which matches, but the IQR...

> IQR(x, type=7)
[1] 9.3
> IQR(x, type=6)
[1] 9.55
> IQR(x, type=5)
[1] 9.425

matches type=6 in this case, but what about another test case?

a <- c(1.1, 2.2, 7.8, -4.4, 0.0, -1.2, 3.9, 4.9, 2.0, -5.7, -7.9, -4.9,  28.7,  4.9)
> qa <- quartiles(a)
[1] -7.9 -5.7 -4.9 -4.4 -1.2  0.0  1.1
[1] -4.4
[1]  2.0  2.2  3.9  4.9  4.9  7.8 28.7
[1] 4.9
[1] 9.3
> qa
[[1]]
 25% 
-3.6 
[[2]]
 75% 
4.65 
[[3]]
[1] 9.3
> quantile(a)
   0%   25%   50%   75%  100% 
-7.90 -3.60  1.55  4.65 28.70 
> IQR(a, type=7)
[1] 8.25
> IQR(a, type=6)
[1] 9.425
> IQR(a, type=5)
[1] 9.3

so you get different types of IQR depending on the list...

Looks like small syntax errors. Just remove the . from k<-c(). and S<-c(). as well as use the correct K in your calculations. It's recommended to not differentiate variables solely by letter case.

x <- c(2.2, 7.8, -4.4, 0.0, -1.2, 3.9, 4.9, 2.0, -5.7, -7.9, -4.9,  28.7,  4.9)

quartiles<-function(x){
    bound<-quantile(x)
    MED<-median(x)
    k<-c() #put values of x less than median in vector K
    S<-c()#put values of x larger than median in vector S
    
    for(i in 1:length(x)){
        if (x[i]<MED){
            K<-x[i]}
        else{S<-x[i]
        }
        i<i+1
    }
    iqr1<-c(median(K)-median(S)) #calculate interquartile for x
    return(list(bound[2],bound[4], iqr1))  
}
quartiles(x)

[[1]]
 25% 
-4.4 

[[2]]
75% 
4.9 

[[3]]
[1] -9.8

To return a vector just use return(c(bound[2],bound[4], iqr1)) instead of return(list(bound[2],bound[4], iqr1))

x <- c(2.2, 7.8, -4.4, 0.0, -1.2, 3.9, 4.9, 2.0, -5.7, -7.9, -4.9,  28.7,  4.9)

quartiles<-function(x){
    bound<-quantile(x)
    MED<-median(x)
    k<-c() #put values of x less than median in vector K
    S<-c()#put values of x larger than median in vector S
    
    for(i in 1:length(x)){
        if (x[i]<MED){
            K<-x[i]}
        else{S<-x[i]
        }
        i<i+1
    }
    iqr1<-c(median(K)-median(S)) #calculate interquartile for x
    return(c(bound[2],bound[4], iqr1))  
}
 quartiles(x)
 25%  75%      
-4.4  4.9 -9.8 

So unless you need a function to do what you want- you can achieve your desired results in a few lines of code without a for loop or a function. You can utilize which to split the vector by the median and take the median of the lower and upper splits and take the difference.

x <- c(2.2, 7.8, -4.4, 0.0, -1.2, 3.9, 4.9, 2.0, -5.7, -7.9, -4.9,  28.7,  4.9)


y <- median(x[which(x>=median(x))])

z <- median(x[which(x<median(x))])

aa <- y-z

bb <- c(z,y,aa)

names(bb) <- c("25%", "75%", "Your IQR")
Related