I have just started learning R and I wrote this code to learn on functions and loops.
squared<-function(x){
m<-c()
for(i in 1:x){
y<-i*i
c(m,y)
}
return (m)
}
squared(5)
NULL
Why does this return NULL. I want i*i values to append to the end of mand return a vector. Can someone please point out whats wrong with this code.
You haven't put anything inside m <- c() in your loop since you did not use an assignment. You are getting the following -
m <- c()
m
# NULL
You can change the function to return the desired values by assigning m in the loop.
squared <- function(x) {
m <- c()
for(i in 1:x) {
y <- i * i
m <- c(m, y)
}
return(m)
}
squared(5)
# [1] 1 4 9 16 25
But this is inefficient because we know the length of the resulting vector will be 5 (or x). So we want to allocate the memory first before looping. This will be the better way to use the for() loop.
squared <- function(x) {
m <- vector("integer", x)
for(i in seq_len(x)) {
m[i] <- i * i
}
m
}
squared(5)
# [1] 1 4 9 16 25
Also notice that I have removed return() from the second function. It is not necessary there, so it can be removed. It's a matter of personal preference to leave it in this situation. Sometimes it will be necessary, like in if() statements for example.
I know the question is about looping, but I also must mention that this can be done more efficiently with seven characters using the primitive ^, like this
(1:5)^2
# [1] 1 4 9 16 25
^ is a primitive function, which means the code is written entirely in C and will be the most efficient of these three methods
`^`
# function (e1, e2) .Primitive("^")
Here's a general approach:
# Create empty vector
vec <- c()
for(i in 1:10){
# Inside the loop, make one or elements to add to vector
new_elements <- i * 3
# Use 'c' to combine the existing vector with the new_elements
vec <- c(vec, new_elements)
}
vec
# [1] 3 6 9 12 15 18 21 24 27 30
If you happen to run out of memory (e.g. if your loop has a lot of iterations or vectors are large), you can try vector preallocation which will be more efficient. That's not usually necessary unless your vectors are particularly large though.
Related
I was prompted a question and am ever so close to solving what I need. The question is as follows-
"Write a while loop that computes and stores as a new object, the factorial of any non-negative integer mynum by decrementing mynum by 1 at each repetition of the braced code."
Another factor was that if 0 or 1 was entered, the output would be 1.
The code that I wrote as follows-
factorialcalc <- function(i){
factorial <- 1
if(i==0 | i==1){
factorial <- 1
} else{
while(i >= 1){
factorial <- factorial * i
i <- i-1
}
}
return (factorial)
}
with inputs-
mynum <- 5
factorialcalc(mynum)
and output-
[1] 120
You may be wondering, "your code works perfect, so what's the issue?"
My issue lies in the part of the question that says "computes AND stores."
How can I modify my code to put the answers of factorialcalc into a vector?
Example-
I input
mynum <- 5
factorialcalc(mynum)
and
mynum <- 3
factorialcalc(mynum)
and
mynum <- 4
factorialcalc(mynum)
When I call this new vector, I would like to see a vector with all three of their outputs
(so almost like I made a vector c(120,6,24))
I'm thinking there's a way to add this vector somewhere in my function or while loop, but I'm not sure where. Also, please note that the answer must contain a loop like in my code.
Option 1.
"Vectorize" your function
# simply wrap the whole thing in Vectorize()
Factorialcalc = Vectorize(function(i){
factorial <- 1
if(i==0 | i==1){
factorial <- 1
} else{
while(i >= 1){
factorial <- factorial * i
i <- i-1
}
}
return (factorial)
})
# Now when you supply it a vector, it runs on each element
> Factorialcalc(c(5, 3, 4))
[1] 120 6 24
Option 2.
Use functions that are designed to apply a single function to multiple elements of a supplied vector.
Using map_dbl from the purrr package, you can call:
map_dbl(c(5, 3, 4), factorialcalc)
Which supplies to your function factorialcalc each element in vector and concatenates each result before returning a vector.
Using base R you can simply use the apply-family functions:
sapply(c(5, 3, 4), factorialcalc)
and get the same result.
Example
> map_dbl(c(5, 3, 4), factorialcalc)
[1] 120 6 24
> sapply(c(5, 3, 4), factorialcalc)
[1] 120 6 24
My professor has assigned a question for programming in R and I am stuck. He wants us to make a function that will take the exponential (e^(x[i]) of all the numbers in a vector and then sum them. the equation is:
the summation of e^x(i), n, and i=1.
I have made a function that will give me the exponential of the first value in my vector. But I want to get the exponential of all the values and sum them. Here is my code
#Vector for summing
x=c(2,1,3,0.4)
#Code for function
mysum = 0
myfun=function(x){
for (i in 1:length(x)){
mysum = mysum + exp(x[i])
return(mysum)
}
}
myfun(x)
#returns 7.389056
I have also tried using i = 1:1 because the equation specifies i=1, even though I knew that would only go through 1 number, and it gave me the same answer.... obviously.
myfun=function(x){
for (i in 1:1)
Does anyone have any suggestions to get it to sum?
You need to set the initial value of mysum to the accumulation afterwards, and also move the line return(mysum) outsides your for loop to return the result, i.e.,
myfun=function(x){
mysum <- 0
for (i in 1:length(x)){
mysum = mysum + exp(x[i])
}
return(mysum)
}
or just
myfun=function(x){
mysum <- 0
for (i in x){
mysum = mysum + exp(x)
}
return(mysum)
}
Since exp operation is vectoroized, you can also define your function myfun like below
myfun <- function(x) sum(exp(x))
You could also use the fact that most base functions are already vectorized :
1) create a dummy vector
1:10
#> [1] 1 2 3 4 5 6 7 8 9 10
2) apply your function on that vector, you get vectorized result
exp(1:10)
#> [1] 2.718282 7.389056 20.085537 54.598150 148.413159
#> [6] 403.428793 1096.633158 2980.957987 8103.083928 22026.465795
3) Sum that vector
sum(exp(1:10))
#> [1] 34843.77
4) Write your function to gain (a little) time
my_fun <- function(x){sum(exp(x))}
my_fun(1:10)
#> [1] 34843.77
I wrote a recursive binary search function in R which finds the smallest element in a vector that is greater than a given value:
binary_next_biggest <- function(x, vec){
if (length(vec) == 1){
if (x < vec[1]){
return(vec[1])
} else {
return(NA)
}
} else {
mid = ceiling(length(vec)/2)
if (x < vec[mid]){
return(binary_next_biggest(x, vec[1:mid]))
} else {
return(binary_next_biggest(x, vec[mid+1:length(vec)]))
}
}
}
I've written this exact same function in Python with no issues (code below), but in R it does not work.
import numpy as np
def binary_next_biggest(x, arr):
if len(arr)==1:
if x < arr[0]:
return arr[0]
else:
return None
else:
mid = int(np.ceil(len(arr)/2)-1)
if x < arr[mid]:
return binary_next_biggest(x, arr[:mid+1])
else:
return binary_next_biggest(x, arr[mid+1:])
Through debugging in RStudio I discovered the mechanics of why it's not working: indexing the vector in my above function is returning a vector of the same length, so that if
vec <- 1:10
and vec is indexed within the function,
vec[6:10]
the resulting vector passed to the new call of binary_next_biggest() is
6 7 8 9 10 NA NA NA NA NA
where I would expect
6 7 8 9 10
What's going on here? I know I can just rewrite it as a while loop iteratively changing indexes, but I don't understand why vector indexing is behaving this way in the code I've written. Within the interactive R console indexing behaves as expected and changes the vector length, so why would it behave differently within a function, and what would be the appropriate way to index for what I'm trying to do?
The cause of the strange behavior of the code is an error in indexing of the vector elements. The part mid+1:length(vec) should be (mid+1):length(vec) because the : operator is executed before addition.
Here is an illustration of the difference.
5 + 1:10
# [1] 6 7 8 9 10 11 12 13 14 15
(5+1):10
# [1] 6 7 8 9 10
There might be a reason why you're doing a binary search (simplified example of more complicated problem?), but there are easier ways to do this in R.
vec <- 1:1000
x <- 49
min(vec[which(vec > x)])
# [1] 50
Which works even if vec isn't ordered.
vec <- sample.int(1000)
min(vec[which(vec > x)])
# [1] 50
I have a list of lists, with each sub-list containing 3 values. My goal is to cycle through every value of this nested list in a systematic way (i.e. start with list 1, go through all 3 values, go to list 2, and so on), applying a function to each. But my function hits missing values and breaks and I've traced the problem to the indexing itself, which doesn't behave in the way I am expecting. The lists are constructed as:
pop <- 1:100
treat.temp <- NULL
treat <- NULL
## Generate 5 samples of pop
for (i in 1:5){
treat.temp <- sample(pop, 3)
treat[[i]] <- treat.temp
}
## Create a list with which to index mapply
iterations <- (1:5)
Illustrative function and results.
test.function <- function(j, k){
for (n in 1:3){
print(k[[n]][j])
}
}
results <- mapply(test.function, iterations, treat)
[1] 61
[1] 63
[1] 73
[1] NA
[1] NA
[1] NA
[1] NA
[1] NA
<snipped>
For the first cycle through 'j', this works. But after that it throws NAs. But if I do it manually, it returns the values I would expect.
> print(treat[[1]][1])
[1] 61
> print(treat[[1]][2])
[1] 63
> print(treat[[1]][3])
[1] 73
> print(treat[[2]][1])
[1] 59
> print(treat[[2]][2])
[1] 6
> print(treat[[2]][3])
[1] 75
<snipped>
I'm sure this is a basic question, but I can't seem to find the right search terms to find an answer here or on Google. Thanks in advance!
Edited to Add: MrFlick's answer works well for my problem. I have multiple list inputs (hence mapply) in my actual use. A more detailed example, with a few notes.
pop <- 1:100
years <- seq.int(2000, 2014, 1)
treat.temp <- NULL
treat <- NULL
year.temp <- NULL
year <- NULL
## Generate 5 samples of treated states, control states and treatment years
for (i in 1:5){
treat.temp <- sample(pop, 20)
treat[[i]] <- treat.temp
year.temp <- sample(years, 1)
year[[i]] <- year.temp
}
## Create a list with which to index mapply
iterations <- (1:5)
## Define function
test.function <- function(j, k, l){
for (n in 1:3){
## Cycles treat through each value of jXn
print(k[n])
## Holds treat (k) fixed for each 3 cycle set of n (using first value in each treat sub-list); cycles through sub-lists as j changes
print(k[1])
## Same as above, but with 2nd value in each sub-list of treat
print(k[2])
## Holds year (l) fixed for each 3 cycle set of n, cycling through values of year each time j changes
print(l[1])
## Functionally equivalent to
print(l)
}
}
results <- mapply(test.function, iterations, treat, year)
Well, you might be misunderstanding how mapply works. The function will loop through both of the iterations you pass as parameters, which means treat will also be subset each iteration. Essentially, the functions being called are
test.function(iterations[1], treat[[1]])
test.function(iterations[2], treat[[2]])
test.function(iterations[3], treat[[3]])
...
and you seem to treat the k variable as if it were the entire list. Also, you have your indexes backwards as well. But just to get your test working, you can do
test.function <- function(j, k){
for (n in 1:3) print(k[n])
}
results <- mapply(test.function, iterations, treat)
but this isn't really a super awesome way to iterate a list. What exactly are you trying to accomplish?
I would like to create a numeric vector with the results of a loop such as
> for (i in 1:5) print(i+1)
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
It seems strange that the same expression without 'print' returns nothing
> for (i in 1:5) i+1
>
Does anyone have an explanation/solution?
This is standard behaiviour -- when you say you want to create a numeric vector,
print will not do that
The expression in a for loop is an argument to the primitive function for
From ?`for` in the value section
for, while and repeat return NULL invisibly. for sets var to the last
used element of seq, or to NULL if it was of length zero.
print prints the results to the console.
for(i in 1:5) i + 1
merely calculates i + 1 for each iteration and returns nothing
If you want to assign something then assign it using <-, or less advisably assign
You can avoid an explicit loops by using sapply. This (should) avoid any pitfalls of growing vectors
results <- sapply(1:5, function(i) { i + 1})
Now frankly, there must be a better solution than this
loopee <- function(x){
res <- vector(mode = "numeric", length(x))
for (i in 1:x) {res[i] <- i+1}
return(res)}
> loopee(5)
[1] 2 3 4 5 6