This question already has answers here:
Trying to pass more than 2 vectors to a function in R
(2 answers)
Closed 5 years ago.
I want to compute e^(ax+b) over a=-1:1 and b=-1:1 for various values of X. I want the output in the form a list of 5 elements. Each element in the list is 3X3 Matrix.
I did achieve this using Outer and Vectorize.
sigm = function(a=0,b=0,x){
return(exp(x*a+b))
}
sigm1 = Vectorize(function(a=-1:1,b=-1:1,x){
outer(a,b,sigm,x)
},SIMPLIFY = FALSE)
Now, sigm1(x=1:3) gives the required output
[[1]]
[,1] [,2] [,3]
[1,] 0.1353353 0.3678794 1.000000
[2,] 0.3678794 1.0000000 2.718282
[3,] 1.0000000 2.7182818 7.389056
[[2]]
[,1] [,2] [,3]
[1,] 0.04978707 0.1353353 0.3678794
[2,] 0.36787944 1.0000000 2.7182818
[3,] 2.71828183 7.3890561 20.0855369
[[3]]
[,1] [,2] [,3]
[1,] 0.01831564 0.04978707 0.1353353
[2,] 0.36787944 1.00000000 2.7182818
[3,] 7.38905610 20.08553692 54.5981500
The only draw back with this code snippet is I am using the default values of a=-1:1 and b=-1:1. When I try to pass the same during function calling, it goes haywire. E.g.
sigm1(-1:1,-1:1,1:3)
[[1]]
[,1]
[1,] 0.1353353
[[2]]
[,1]
[1,] 1
[[3]]
[,1]
[1,] 54.59815
I am unable to figure out why passing the arguments is making this difference in output.
You could use sapply to create your vectorized function
sigm = function(a, b, x){
return(lapply(x, function(xx) sapply(b, function(bb)
sapply(a, function(aa) exp(xx*aa+bb)))))
}
sigm(a = -1:1, b = -1:1, x = 1:3)
#[[1]]
# [,1] [,2] [,3]
#[1,] 0.1353353 0.3678794 1.000000
#[2,] 0.3678794 1.0000000 2.718282
#[3,] 1.0000000 2.7182818 7.389056
#[[2]]
# [,1] [,2] [,3]
#[1,] 0.04978707 0.1353353 0.3678794
#[2,] 0.36787944 1.0000000 2.7182818
#[3,] 2.71828183 7.3890561 20.0855369
#[[3]]
# [,1] [,2] [,3]
#[1,] 0.01831564 0.04978707 0.1353353
#[2,] 0.36787944 1.00000000 2.7182818
#[3,] 7.38905610 20.08553692 54.5981500
Related
I have an (5x4) matrix in R, namely data defined as follows:
data <- matrix(rnorm(5*4,mean=0,sd=1), 5, 4)
and I want to create 4 different matrices that follows this formula: Assume that data[,1] = [A1,A2,A3,A4,A5]. I want to create the following matrix:
A1*A1 A1*A2 A1*A3 A1*A4 A1*A5
A2*A1 A2*A2 A2*A3 A2*A4 A2*A5
G1 = A3*A1 A3*A2 A3*A3 A3*A4 A3*A5
A4*A1 A4*A2 A4*A3 A4*A4 A4*A5
A5*A1 A5*A2 A5*A3 A5*A4 A5*A5
Similarly for the other columns i want to calculate at once all the G matrices (G1,G2,G3,G4). How can i achieve that?
results <- lapply(1:ncol(data), function(i) outer(data[, i], data[, i]))
results
[[1]]
[,1] [,2] [,3] [,4] [,5]
[1,] 0.37164 0.37582 0.33424 -0.105387 0.120936
[2,] 0.37582 0.38006 0.33800 -0.106574 0.122298
[3,] 0.33424 0.33800 0.30060 -0.094780 0.108765
[4,] -0.10539 -0.10657 -0.09478 0.029885 -0.034294
[5,] 0.12094 0.12230 0.10876 -0.034294 0.039354
[[2]]
[,1] [,2] [,3] [,4] [,5]
[1,] 0.94684 0.117862 -1.01368 2.01456 0.719629
[2,] 0.11786 0.014671 -0.12618 0.25077 0.089579
[3,] -1.01368 -0.126183 1.08525 -2.15679 -0.770432
[4,] 2.01456 0.250772 -2.15679 4.28633 1.531132
[5,] 0.71963 0.089579 -0.77043 1.53113 0.546941
[[3]]
[,1] [,2] [,3] [,4] [,5]
[1,] 1.61048 0.344159 -0.453466 2.68019 -0.57121
[2,] 0.34416 0.073547 -0.096906 0.57276 -0.12207
[3,] -0.45347 -0.096906 0.127684 -0.75467 0.16084
[4,] 2.68019 0.572758 -0.754669 4.46044 -0.95062
[5,] -0.57121 -0.122068 0.160837 -0.95062 0.20260
[[4]]
[,1] [,2] [,3] [,4] [,5]
[1,] 0.559341 0.859297 0.451096 -0.0522063 -1.027929
[2,] 0.859297 1.320109 0.693004 -0.0802028 -1.579172
[3,] 0.451096 0.693004 0.363799 -0.0421032 -0.829002
[4,] -0.052206 -0.080203 -0.042103 0.0048727 0.095942
[5,] -1.027929 -1.579172 -0.829002 0.0959421 1.889075
I have a square matrix as follows.
> ex_mat
[,1] [,2] [,3] [,4]
[1,] 0.4270634 2.1920890 0.5647472 1.7149861
[2,] 2.0556220 1.1157322 2.6723637 0.3155507
[3,] 1.2252602 0.1063053 0.6396099 0.7903348
[4,] 0.3614062 1.1118661 0.5000143 0.2491543
I've ranked the upper off-diagonal part of the matrix in row order (from largest to smallest) with this.
> rank(-(t(ex_mat)[lower.tri(ex_mat)]))
[1] 2 5 3 1 6 4
I want to replace the upper off-diagonal elements of "ex_mat" with the ranks obtained above. I'm using https://statisticsglobe.com/modify-diagonal-lower-upper-triangular-part-matrix-r as example code. While my ranks are correct, the code seems to be inserting the ranks in column order.
> ex_mat_new <- ex_mat
> ex_mat_new[upper.tri(ex_mat_new)] <- rank(-(t(ex_mat)[lower.tri(ex_mat)]))
> ex_mat_new
[,1] [,2] [,3] [,4]
[1,] 0.4270634 2.0000000 5.0000000 1.0000000
[2,] 2.0556220 1.1157322 3.0000000 6.0000000
[3,] 1.2252602 0.1063053 0.6396099 4.0000000
[4,] 0.3614062 1.1118661 0.5000143 0.2491543
How can I fix this? [1,4] and [2,3] are off. Thank you.
The value insertions are in column order (in matrix, data.frame). We may assign on the lower.tri and then get the transpose
ex_mat_new[lower.tri(ex_mat_new)] <- rank(-(t(ex_mat)[lower.tri(ex_mat)]))
ex_mat_new <- t(ex_mat_new)
ex_mat_new[lower.tri(ex_mat_new)] <- ex_mat[lower.tri(ex_mat)]
-output
> ex_mat_new
[,1] [,2] [,3] [,4]
[1,] 0.4270634 2.0000000 5.0000000 3.0000000
[2,] 2.0556220 1.1157322 1.0000000 6.0000000
[3,] 1.2252602 0.1063053 0.6396099 4.0000000
[4,] 0.3614062 1.1118661 0.5000143 0.2491543
or this can be done in a single line with replace
t(replace(t(ex_mat), lower.tri(ex_mat), rank(-(t(ex_mat)[lower.tri(ex_mat)]))))
-output
[,1] [,2] [,3] [,4]
[1,] 0.4270634 2.0000000 5.0000000 3.0000000
[2,] 2.0556220 1.1157322 1.0000000 6.0000000
[3,] 1.2252602 0.1063053 0.6396099 4.0000000
[4,] 0.3614062 1.1118661 0.5000143 0.2491543
data
ex_mat <- structure(c(0.4270634, 2.055622, 1.2252602, 0.3614062, 2.192089,
1.1157322, 0.1063053, 1.1118661, 0.5647472, 2.6723637, 0.6396099,
0.5000143, 1.7149861, 0.3155507, 0.7903348, 0.2491543), .Dim = c(4L,
4L), .Dimnames = list(NULL, NULL))
I want to compute e^(ax+b) over a=-1:1 and b=-1:1 for various values of X. I want the output in the form a list of 5 elements. Each element in the list is 3X3 Matrix.
I did achieve this using Outer and Vectorize.
sigm = function(a=0,b=0,x){
return(exp(x*a+b))
}
sigm1 = Vectorize(function(a=-1:1,b=-1:1,x){
outer(a,b,sigm,x)
},SIMPLIFY = FALSE)
Now, sigm1(x=1:3) gives the required output
[[1]]
[,1] [,2] [,3]
[1,] 0.1353353 0.3678794 1.000000
[2,] 0.3678794 1.0000000 2.718282
[3,] 1.0000000 2.7182818 7.389056
[[2]]
[,1] [,2] [,3]
[1,] 0.04978707 0.1353353 0.3678794
[2,] 0.36787944 1.0000000 2.7182818
[3,] 2.71828183 7.3890561 20.0855369
[[3]]
[,1] [,2] [,3]
[1,] 0.01831564 0.04978707 0.1353353
[2,] 0.36787944 1.00000000 2.7182818
[3,] 7.38905610 20.08553692 54.5981500
The only draw back with this code snippet is I am using the default values of a=-1:1 and b=-1:1. When I try to pass the same during function calling, it goes haywire. E.g.
sigm1(-1:1,-1:1,1:3)
[[1]]
[,1]
[1,] 0.1353353
[[2]]
[,1]
[1,] 1
[[3]]
[,1]
[1,] 54.59815
I am unable to figure out why passing the arguments is making this difference in output.
In this case, you should only vectorize the variable x.
sigm1 = Vectorize(function(a=-1:1,b=-1:1,x){
outer(a,b,sigm,x)}, vectorize.args = "x" ,SIMPLIFY = FALSE)
Then running sigm1(-1:1,-1:1,1:3) will gives the result you want.
We can just use lapply and don't need Vectorize at all:
lapply(x, function(x) outer(a, b, sigm, x = x))
giving:
[[1]]
[,1] [,2] [,3]
[1,] 0.1353353 0.3678794 1.000000
[2,] 0.3678794 1.0000000 2.718282
[3,] 1.0000000 2.7182818 7.389056
[[2]]
[,1] [,2] [,3]
[1,] 0.04978707 0.1353353 0.3678794
[2,] 0.36787944 1.0000000 2.7182818
[3,] 2.71828183 7.3890561 20.0855369
[[3]]
[,1] [,2] [,3]
[1,] 0.01831564 0.04978707 0.1353353
[2,] 0.36787944 1.00000000 2.7182818
[3,] 7.38905610 20.08553692 54.5981500
n the matrix example below (Stocks Return) :
IBOV PETR4 VALE5 ITUB4 BBDC4 PETR3
[1,] -0.03981646 -0.027412907 -0.051282051 -0.05208333 -0.047300526 -0.059805285
[2,] -0.03000415 -0.030534351 -0.046332046 -0.03943116 -0.030090271 -0.010355030
[3,] -0.02241318 -0.026650515 0.000000000 -0.04912517 -0.077559462 0.005231689
[4,] -0.05584830 -0.072184194 -0.066126856 -0.04317056 -0.066704036 0.000000000
[5,] 0.01196833 -0.004694836 0.036127168 -0.00591716 -0.006006006 Inf
[6,] 0.02039587 0.039083558 0.009762901 0.01488095 0.024169184 0.011783189
I would like to replace the 0 (Zeros) and Inf values for the values of the same row in the first column.
Here's a sample matrix
set.seed(15)
stocks<-matrix(rnorm(3*5), nrow=3)
stocks[cbind(c(2,3,1),c(4,4,2))] <- 0
stocks[2,2] <- Inf
stocks
# [,1] [,2] [,3] [,4] [,5]
# [1,] 0.2588229 0.000000 0.0227882 -1.075001 0.1655543
# [2,] 1.8311207 Inf 1.0907732 0.000000 -1.2427850
# [3,] -0.3396186 -1.255386 -0.1321224 0.000000 1.45928777
Now we can find the bad values, and then replace them with the values in the first column of the same row by using matrix indexing and the row() function to find the correct row.
bad <- stocks==0 | is.infinite(stocks)
stocks[bad] <- stocks[row(bad)[bad], 1]
stocks
# [,1] [,2] [,3] [,4] [,5]
# [1,] 0.2588229 0.2588229 0.0227882 -1.0750013 0.1655543
# [2,] 1.8311207 1.8311207 1.0907732 1.8311207 -1.2427850
# [3,] -0.3396186 -1.2553858 -0.1321224 -0.3396186 1.4592877
Let's say I have a 5 by 7 matrix and a function f :
a <- matrix(rnorm(7*5),5,7)
f <- function(x,y) sum(x+y)
I would like to compute the matrix b whose element b[i,j] is equal to f(a[i,],a[j,]) without for loops. How could I do ?
You can use outer to apply a function to all possible combinations:
rowNums <- seq(nrow(a)) # vector with all row numbers
outer(rowNums, rowNums, Vectorize(function(x, y) sum(a[x, ] + a[y, ])))
[,1] [,2] [,3] [,4] [,5]
[1,] 6.319860 10.978305 6.911812 2.4609471 4.7021136
[2,] 10.978305 15.636751 11.570257 7.1193924 9.3605589
[3,] 6.911812 11.570257 7.503764 3.0528993 5.2940659
[4,] 2.460947 7.119392 3.052899 -1.3979658 0.8432008
[5,] 4.702114 9.360559 5.294066 0.8432008 3.0843673
Edit:
The calculations are more efficient if you calculate the rowSums before using outer. This code is shorter and faster:
rs <- rowSums(a)
outer(rs, rs, "+")
[,1] [,2] [,3] [,4] [,5]
[1,] 6.319860 10.978305 6.911812 2.4609471 4.7021136
[2,] 10.978305 15.636751 11.570257 7.1193924 9.3605589
[3,] 6.911812 11.570257 7.503764 3.0528993 5.2940659
[4,] 2.460947 7.119392 3.052899 -1.3979658 0.8432008
[5,] 4.702114 9.360559 5.294066 0.8432008 3.0843673
Edit 2:
A solution to your actual problem (see comments):
ta <- t(a) # transpose
apply(a, 1, function(x) colSums(abs(ta - x)))
[,1] [,2] [,3] [,4] [,5]
[1,] 0.000000 10.687579 10.933269 9.306339 7.763612
[2,] 10.687579 0.000000 7.465742 8.517358 7.847622
[3,] 10.933269 7.465742 0.000000 5.768676 6.851272
[4,] 9.306339 8.517358 5.768676 0.000000 6.687477
[5,] 7.763612 7.847622 6.851272 6.687477 0.000000
One way is to use expand.grid to create to subsetting indicies and use on this apply on this:
matrix(apply(expand.grid(seq(nrow(a)),seq(nrow(a))),1,
function(x) f(a[x[1],],a[x[2],])),nrow(a))
[,1] [,2] [,3] [,4] [,5]
[1,] 8.9116431 4.1067161 0.6589584 3.681561 3.207056
[2,] 4.1067161 -0.6982109 -4.1459686 -1.123366 -1.597871
[3,] 0.6589584 -4.1459686 -7.5937263 -4.571123 -5.045629
[4,] 3.6815615 -1.1233656 -4.5711232 -1.548520 -2.023026
[5,] 3.2070558 -1.5978712 -5.0456289 -2.023026 -2.497531