Similar questions have been asked before about summing elements of a list. But my problem is a little different than the other questions.
I have a list of vectors. I am trying to sum the 1st element of the 1st vector with each single element from the other vectors in my list. Then I want to sum the 2nd element in my 1st vector with every other individual element from the other vectors in my list... and so on.
Hopefully my example will explain what Im trying to do. For example, if my list looks like this:
l <- list(
a = c(1,2,3),
b = c(10,4),
c = c(8,5)
)
Writing out explicitly what im trying to do would look like:
1+10+8
1+10+5
1+4+8
1+4+5
2+10+8
2+10+5
2+4+8
2+4+5
3+10+8
3+10+5
3+4+8
3+4+5
In other words, take:
l[[1]][1] + l[[2]][1] + l[[3]][1]
l[[1]][1] + l[[2]][1] + l[[3]][2]
l[[1]][1] + l[[2]][2] + l[[3]][1]
l[[1]][1] + l[[2]][2] + l[[3]][2]
l[[1]][2] + l[[2]][1] + l[[3]][1]... and so on for each element
Consequently, my final desired output would look like:
[1] 19 16 13 10 20 17 14 11 21 18 15 12
Any suggestions as to how I could do this?
EDIT: Additionally, to complicate matters more, I need to return the values in the order that I show when I wrote out all the sums explicitly. So the result has to match my desired output.
So you aim to compute a[i] + b[j] + c[k]. To match your specific order, we can do
## the reason for using rev(l) instead of l is explained below
c(Reduce(function (u, v) outer(u, v, "+"), rev(l)))
# [1] 19 16 13 10 20 17 14 11 21 18 15 12
The difference between using l and rev(l) is how fast i, j and k vary.
if using l, the speed is i > j > k;
if using rev(l), the speed is k > j > i.
The magic (or convenience of outer), is that before we flattening the results using c(), the storage is an interpretable 3D array.
if using l, we have arr[i, j, k] = a[i] + b[j] + c[k];
if using rev(l), we have arr[k, j, i] = a[i] + b[j] + c[k].
The expand.grid solution by thelatemail is also brilliant. expand.grid produces a data frame, so the final rowSums will have to coerce the data frame to a matrix first. But as thelatemail commented, the performance penalty of expand.grid is unlikely to be noticeable unless we have long vectors. (Thanks to thelatemail for reminding me of this function.)
Another option, based on making the combinations of every value across l in three columns, and taking the sum across each row.
rowSums(expand.grid(rev(l)))
#[1] 19 16 13 10 20 17 14 11 21 18 15 12
rpois() takes two values (n, and lambda) to generate n random numbers according to Poisson distribution.
But, what is rpois() doing in the following case?
> n = c(0,1,2,3,4,5,6,7,8,9)
> lamda = 10
> rpois(n, lamda)
[1] 13 15 10 9 10 11 10 10 11 15
>
from the docs:
The length of the result is determined by ‘n’ for ‘rpois’, and is
the maximum of the lengths of the numerical arguments for the
other functions.
it's therefore the same as:
rpois(length(n), lambda)
a bit more digging, it ends up calling do_random1 in src/main/random.c. which basically says:
if (length(param1) == 1) {
n = as.integer(param1)
} else {
n = length(param1)
}
but in C, and with fiddling to make sure it works with "long" vectors, etc.
I have a vector 'participant' in R.
> participant
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
I am using a function 'modify' to change the contents of this vector.
modify <- function(x){
for (i in participant){
if (x[i] > 12)
(x[i]=x[i]-12)
print (x[i])
}}
When I run the function as modify(participant), it runs OK, but the elements of the vector participant remain unchanged.
Any suggestion, for where am I going wrong ?
Don't use a loop.
participant <- participant - (participant > 12) * 12
If you insist on using your function, loop over the indices, let you function return the modified vector and assign it:
modify <- function(x){
for (i in seq_along(participant)){
if (x[i] > 12) x[i]=x[i]-12
}
return(x)
}
participant <- modify(participant)
Of course, the loop is more difficult to write and also much slower.
Your problem is the function return. Use this solution, so the function returns the modified vector x:
modify <- function(x){
for (i in participant){
if (x[i] > 12)
(x[i] = x[i] - 12)
print (x[i])}
return(x)
}
participant <- modify(participant)
Another solution is the ifelse function:
participant <- ifelse(participant > 12, participant - 12, participant)
I am trying to write a program in R to sum n random number. However, when I try it for some numbers it won't work.
For example,
## rm(list=ls())
random.sum <- function(n) {
x[1:n] <- ceiling(10*runif(n))
cat("x:", x[1:n], "\n")
return(sum(x))
}
x <- rep(100, 10)
show(random.sum(10))
show(random.sum(5))
when I try to sum 10 random numbers it will give me the correct sum which is
show(random.sum(10))
x: 1 3 10 1 3 2 8 6 7 9
[1] 50
However, when I try it for the next one which is 5, it won't work,
show(random.sum(5))
x: 7 5 6 2 9
[1] 529
I am not sure what I am doing wrong
The easiest way would be something like this (updated as per #Axeman's comment):
sum(sample(1:10, 10, replace = TRUE))
where the first "10" is your n and min and max define the value range for runif.
Also keep x local to the function:
random.sum <- function(n) {
x <- sample(1:10, 10, replace = TRUE)
cat("x:", x, "\n")
return(sum(x))
}
The reason for your error is the variable scoping rules of R. Your variable x in global scope is copied upon modification, but maintains the dimension of the global declaration. If you sum over only the first n elements with sum(x[1:n]) you will get the correct answer.
Now, that begs the question, are you trying to modify the global object x inside the function? If that is your intent, the superassignment operator <<- can be used. See the R intro section 10.5 "Assignments within functions" for details.
I am filling a 10x10 martix (mat) randomly until sum(mat) == 100
I wrote the following.... (i = 2 for another reason not specified here but i kept it at 2 to be consistent with my actual code)
mat <- matrix(rep(0, 100), nrow = 10)
mat[1,] <- c(0,0,0,0,0,0,0,0,0,1)
mat[2,] <- c(0,0,0,0,0,0,0,0,1,0)
mat[3,] <- c(0,0,0,0,0,0,0,1,0,0)
mat[4,] <- c(0,0,0,0,0,0,1,0,0,0)
mat[5,] <- c(0,0,0,0,0,1,0,0,0,0)
mat[6,] <- c(0,0,0,0,1,0,0,0,0,0)
mat[7,] <- c(0,0,0,1,0,0,0,0,0,0)
mat[8,] <- c(0,0,1,0,0,0,0,0,0,0)
mat[9,] <- c(0,1,0,0,0,0,0,0,0,0)
mat[10,] <- c(1,0,0,0,0,0,0,0,0,0)
i <- 2
set.seed(129)
while( sum(mat) < 100 ) {
# pick random cell
rnum <- sample( which(mat < 1), 1 )
mat[rnum] <- 1
##
print(paste0("i =", i))
print(paste0("rnum =", rnum))
print(sum(mat))
i = i + 1
}
For some reason when sum(mat) == 99 there are several steps extra...I would assume that once i = 91 the while would stop but it continues past this. Can somone explain what I have done wrong...
If I change the while condition to
while( sum(mat) < 100 & length(which(mat < 1)) > 0 )
the issue remains..
Your problem is equivalent to randomly ordering the indices of a matrix that are equal to 0. You can do this in one line with sample(which(mat < 1)). I suppose if you wanted to get exactly the same sort of output, you might try something like:
set.seed(144)
idx <- sample(which(mat < 1))
for (i in seq_along(idx)) {
print(paste0("i =", i))
print(paste0("rnum =", idx[i]))
print(sum(mat)+i)
}
# [1] "i =1"
# [1] "rnum =5"
# [1] 11
# [1] "i =2"
# [1] "rnum =70"
# [1] 12
# ...
See ?sample
Arguments:
x: Either a vector of one or more elements from which to choose,
or a positive integer. See ‘Details.’
...
If ‘x’ has length 1, is numeric (in the sense of ‘is.numeric’) and
‘x >= 1’, sampling _via_ ‘sample’ takes place from ‘1:x’. _Note_
that this convenience feature may lead to undesired behaviour when
‘x’ is of varying length in calls such as ‘sample(x)’. See the
examples.
In other words, if x in sample(x) is of length 1, sample returns a random number from 1:x. This happens towards the end of your loop, where there is just one 0 left in your matrix and one index is returned by which(mat < 1).
The iteration repeats on level 99 because sample() behaves very differently when the first parameter is a vector of length 1 and when it is greater than 1. When it is length 1, it assumes you a random number from 1 to that number. When it has length >1, then you get a random number from that vector.
Compare
sample(c(99,100),1)
and
sample(c(100),1)
Of course, this is an inefficient way of filling your matrix. As #josilber pointed out, a single call to sample could do everything you need.
The issue comes from how sample and which do the sampling when you have only a single '0' value left.
For example, do this:
mat <- matrix(rep(1, 100), nrow = 10)
Now you have a matrix of all 1's. Now lets make two numbers 0:
mat[15]<-0
mat[18]<-0
and then sample
sample(which(mat<1))
[1] 18 15
by adding a size=1 argument you get one or the other
now lets try this:
mat[18]<-1
sample(which(mat<1))
[1] 3 13 8 2 4 14 11 9 10 5 15 7 1 12 6
Oops, you did not get [1] 15 . Instead what happens in only a single integer (15 in this case) is passed tosample. When you do sample(x) and x is an integer, it gives you a sample from 1:x with the integers in random order.