How to simplify this programme? - r

The main function is like the following code:
#f is a function that has two parameters and returns one value:
f <- function(a, b) {
a * b
}
#x is a's value group
x <- c(1,2,3,4)
#y is b's value group
y <- c(4,5,6)
I want to get all the possible values of f(x, y), and the result should be a matrix to be clear. Now I am using the for loop:
m <- c(NULL)
for (a in x) {
for (b in y) {
m <- c(m, c(a, b))
}
}
m <- matrix(m, 3, 4)
But it seems really very very silly.Can any one provide a simpler way?
Thank you.

outer(x, y, f)
# [,1] [,2] [,3]
#[1,] 4 5 6
#[2,] 8 10 12
#[3,] 12 15 18
#[4,] 16 20 24
outer(y, x, f)
# [,1] [,2] [,3] [,4]
#[1,] 4 8 12 16
#[2,] 5 10 15 20
#[3,] 6 12 18 24

I guess expand.grid is what you are looking for.
getAllCombinations <- function(a,b,r=3,col = 4){
# this is the key
g <- expand.grid(a,b)
matrix(g$Var1*g$Var2,r,col)
}
# call the function
getAllCombinations(x,y)
EDIT:
Gotta be a sportsman here. My own solution is actually the slowest by far, though it might be easier to understand than a lot of lapply and anonymous functions. If you'd benchmark it: #ExperimenteR does not only win the easy-to-read competition but also the race...
# performance
library(rbenchmark)
benchmark(
outer(x, y, f),
getAllCombinations(x,y),
vrajs(),
replications = 10000
)
Note that, I turned #vrajs solution into a function to keep things fair.

I hope following will work for you
#x is a's value group
x <- c(1,2,3,4)
#y is b's value group
y <- c(4,5,6)
matrix(unlist(lapply(1:length(x),
function(a){
lapply(1:length(y),
function(b){x[a]*y[b]})})),
ncol = length(y), byrow = TRUE)
[,1] [,2] [,3]
[1,] 4 5 6
[2,] 8 10 12
[3,] 12 15 18
[4,] 16 20 24
Update: Explanation of Code
Outer lapply function run through index of x and call inner lapply
for each element of x
Inner lapply function run through index of y and call function which will then return multiplication of index variable of x and y
unlist function unlist return list of lapply
matrix will create returned array according to dimension of y (as
number of columns)

Related

How to calculate variance between observations, when observations are in matrix form each

I have a cluster of 250 observations. each observation is a 4 by 9 matrix.
4 is number of variable parameters observed and 9 is number of days, observations were collected.
I want to know the variance between 250 observations which are in matrix form. as I ve studied so far, variance is calculated among one dimension variables.
any suggestion for data in matrix form?
mat1 <- matrix(c(0:69),10,7)
mat2 <- matrix(c(3:72),10,7)
mat3 <- matrix(c(0:69),10,7)
...
var <- var(mat1,mat2, mat3,..)
for these three matrices, var() returns a 7 by 7 matrix of 9.166667 for all elements. I do not know what r is doing. or how to get to this.
I think this will reflect what you're hoping for.
First, I'll create a few matrices, very small:
set.seed(42)
mat1 <- matrix(sample(100,12),2,4)
mat2 <- matrix(sample(100,12),2,4)
mat3 <- matrix(sample(100,12),2,4)
From here, I think you want to get
var(c(mat1[1,1], mat2[1,1], mat3[1,1]))
# [1] 193
but for every set of cells in all matrices.
One way to do this is to abind all matrices into a 3D array and then use apply:
ary <- do.call(abind::abind, c(list(mat1, mat2, mat3), along = 3))
ary
# , , 1
# [,1] [,2] [,3] [,4]
# [1,] 49 25 18 47
# [2,] 65 74 100 24
# , , 2
# [,1] [,2] [,3] [,4]
# [1,] 26 41 27 5
# [2,] 3 89 36 84
# , , 3
# [,1] [,2] [,3] [,4]
# [1,] 24 43 22 8
# [2,] 30 15 58 36
apply(ary, 1:2, var)
# [,1] [,2] [,3] [,4]
# [1,] 193.0000 97.33333 20.33333 549
# [2,] 966.3333 1530.33333 1057.33333 1008
Where 193 is the variance of the [1,1] elements, 97.333 is the variance of the [1,2] elements, etc.
The arguments to var are:
> args(var)
function (x, y = NULL, na.rm = FALSE, use)
so mat1 is being passed to x and mat2 to y and mat3 to na.rm. Element i, j of the result is the covariance of x[, i] and y[, j].
The code in the question really all makes no sense and some reading of ?var would help. It is not clear what "I want to know the variance between 250 observations which are in matrix form" means. If it means that v[i, j] should be calculated as the variance of c(mat1[i,j], mat2[i, j], mat3[i, j]) then we can use one of several list comprehension packages or just iterated sapply. They all use the fact that these two are the same for fixed i and j except the first is more general.
var(sapply(L, `[`, i, j))
var(c(L[[1]][i, j], L[[2]][i,j], L[[3]][i,j]))
The syntax for the listcompr alternative seems particularly intuitive here.
L <- list(mat1, mat2, mat3)
nr <- nrow(L[[1]])
nc <- ncol(L[[1]])
library(listcompr)
v1 <- gen.matrix(var(sapply(L, `[`, i, j)), i = 1:nr, j = 1:nc)
# or
library(eList)
v2 <- Mat(for(j in 1:nc) for(i in 1:nr) var(sapply(L, `[`, i, j)))
# or (no packages):
v3 <- sapply(1:nc, \(j) sapply(1:nr, \(i) var(sapply(L, `[`, i, j))))
# checks
identical(v1, v2)
## [1] TRUE
identical(v1, v3)
## [1] TRUE
i <- 2; j <- 3
identical(v1[i, j], var(c(L[[1]][i, j], L[[2]][i,j], L[[3]][i,j])))
## [1] TRUE

Avoid the for loop

I would like to compute the product between the each row of a matrix x with itself. And then sum the result of all these products. The result is a scalar. I make the following coda that works but is not efficient. Can someone help me to avoid the for loop?
for(i in 1:nrow(x){
resid2[i] <- t(x[i,])%*% x[i,]
}
V = sum(resid2)/
The solution is just the sum of squares of all elements of the matrix.
V = sum(x^2)
which can also be calculated via matrix multiplication as:
V = crossprod(as.vector(x))
The intermediate vector resid2 can be calculated as
resid2 = rowSums(x^2)
V = sum(resid2)
Here is an answer that swaps the for loop out for the apply family.
sum(apply(x, margin = 1, function(z) z%*%z))
The apply function takes the matrix x, margin = 1 means for each row (as opposed to margin = 2 which means each column). So, for each row in x run a function that multiplies that row by itself: function(z) z%*%z
If I understand you correctly, you don't need to loop at all. mat %*% mat should do it:
mat <- matrix(seq.int(9), nrow=3)
mat
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
mat %*% mat
## [,1] [,2] [,3]
## [1,] 30 66 102
## [2,] 36 81 126
## [3,] 42 96 150

Binding vectors in R [duplicate]

The main function is like the following code:
#f is a function that has two parameters and returns one value:
f <- function(a, b) {
a * b
}
#x is a's value group
x <- c(1,2,3,4)
#y is b's value group
y <- c(4,5,6)
I want to get all the possible values of f(x, y), and the result should be a matrix to be clear. Now I am using the for loop:
m <- c(NULL)
for (a in x) {
for (b in y) {
m <- c(m, c(a, b))
}
}
m <- matrix(m, 3, 4)
But it seems really very very silly.Can any one provide a simpler way?
Thank you.
outer(x, y, f)
# [,1] [,2] [,3]
#[1,] 4 5 6
#[2,] 8 10 12
#[3,] 12 15 18
#[4,] 16 20 24
outer(y, x, f)
# [,1] [,2] [,3] [,4]
#[1,] 4 8 12 16
#[2,] 5 10 15 20
#[3,] 6 12 18 24
I guess expand.grid is what you are looking for.
getAllCombinations <- function(a,b,r=3,col = 4){
# this is the key
g <- expand.grid(a,b)
matrix(g$Var1*g$Var2,r,col)
}
# call the function
getAllCombinations(x,y)
EDIT:
Gotta be a sportsman here. My own solution is actually the slowest by far, though it might be easier to understand than a lot of lapply and anonymous functions. If you'd benchmark it: #ExperimenteR does not only win the easy-to-read competition but also the race...
# performance
library(rbenchmark)
benchmark(
outer(x, y, f),
getAllCombinations(x,y),
vrajs(),
replications = 10000
)
Note that, I turned #vrajs solution into a function to keep things fair.
I hope following will work for you
#x is a's value group
x <- c(1,2,3,4)
#y is b's value group
y <- c(4,5,6)
matrix(unlist(lapply(1:length(x),
function(a){
lapply(1:length(y),
function(b){x[a]*y[b]})})),
ncol = length(y), byrow = TRUE)
[,1] [,2] [,3]
[1,] 4 5 6
[2,] 8 10 12
[3,] 12 15 18
[4,] 16 20 24
Update: Explanation of Code
Outer lapply function run through index of x and call inner lapply
for each element of x
Inner lapply function run through index of y and call function which will then return multiplication of index variable of x and y
unlist function unlist return list of lapply
matrix will create returned array according to dimension of y (as
number of columns)

Function "for" in R with two objectos or vectors

i'm developing a function to perform operations between two vectors (dataframes, for example), using the function "for":
> A <- c(1,2,3)
> B <- c(2)
> result <- c()
> for (i in 1:length(A))
+ {
+ for (j in 1:length(B))
+ {
+ result <- (A*B)
+ }
+ }
> result
[1] 2 4 6
However, when I increase the vector "B" to 2 values:
> A <- c(1,2,3)
> B <- c(2,4)
the function generates
Warning messages lost:
"Major object length is not a multiple of the length of a lower one."
> result
[1] 2 8 6
So, how i can create a loop that performs the operation against "A" for each row "B"?
Thnaks so much!
In your loop, you don't use the variables i and j but calculate the product A * B instead.
You can produce the desired result using sapply:
A=c(1,2,3); B=c(2,4)
sapply(A, "*", B)
# [,1] [,2] [,3]
# [1,] 2 4 6
# [2,] 4 8 12
or matrix multiplication:
A %*% t(B)
# [,1] [,2]
# [1,] 2 4
# [2,] 4 8
# [3,] 6 12
As the error says, A's length has to be a multiple of B's one : if they have the same length, A*Bwill return a vector of same length whose terms will the multiplications of corresponding elements of A and B (A[1]*B[1],...A[n]*B[n]).
If length(A)=k*length(B), k>1, you will get a vector with same length as A with (A[1]*B[1]...A[l]*B[l],A[l+1]*B[1],A[l+2]*B[2]...A[kl]*B[l]), where l is B length and therefore kl is A length.
Here, 3 is a multiple of 1 but not of 2, hence the error you get.
In general, you can use outer:
outer(A, B, FUN='*')
# [,1] [,2]
# [1,] 2 4
# [2,] 4 8
# [3,] 6 12

Constructing a matrix as function of row and column

The situation is pretty straightforward. I want to create a matrix A of n rows and m columns, where the value for each element is given by a predetermined function f(i, j). What is the most elegant way to achieve this?
You can use outer:
outer(1:3,1:3,function(i,j) i^2+j)
[,1] [,2] [,3]
[1,] 2 3 4
[2,] 5 6 7
[3,] 10 11 12
It would help if you provided a reproducible example, but you could do something like this:
f <- function(i,j) i*j
m <- 4
n <- 2
out <- apply(expand.grid(1:m, 1:n), 1, function(x) f(x[1],x[2]))
dim(out) <- c(m,n)

Resources