Maybe it's not possible to hold this line, and
maybe "outer" is not the right place to draw it, but I
respect the "x is a vector" mindset as much as possible in the base
package. As Tony notes, the documentation does try to be
what outer actually does, and how it can be used.
So I am not a fan of the VECTORIZED argument, and
of the VECTORIZED=FALSE default.
Jonathan.
Gabor Grothendieck wrote:
If the default were changed to VECTORIZED=FALSE then it would
still be functionally compatible with what we have now so
software would continue to run correctly yet would not cause
problems for the unwary. Existing software would not have
to add VECTORIZED=TRUE except for those, presumbly few, cases
where outer performance is critical. One optimization might be to
have the default be TRUE if the function is * or perhaps
as a single character and FALSE otherwise.
Having used APL I always regarded the original design of
permature performance optimization and this would be a
it right.
On 10/28/05, Tony Plate <tplate at acm.org> wrote:
[following on from a thread on R-help, but my post here seems more
appropriate to R-devel]
Would a patch to make outer() work with non-vectorized
considered? It seems to come up moderately often on the
probably indicates that many many people get bitten by the same
incorrect expectation, despite the documentation and the
looks pretty simple to modify outer() appropriately: one
argument and an if-then-else clause to call mapply(FUN,
calling FUN directly.
Here's a function demonstrating this:
outer2 <- function (X, Y, FUN = "*", ..., VECTORIZED=TRUE)
{
no.nx <- is.null(nx <- dimnames(X <- as.array(X)))
dX <- dim(X)
no.ny <- is.null(ny <- dimnames(Y <- as.array(Y)))
dY <- dim(Y)
if (is.character(FUN) && FUN == "*") {
robj <- as.vector(X) %*% t(as.vector(Y))
dim(robj) <- c(dX, dY)
}
else {
FUN <- match.fun(FUN)
Y <- rep(Y, rep.int(length(X), length(Y)))
if (length(X) > 0)
X <- rep(X, times = ceiling(length(Y)/length(X)))
if (VECTORIZED)
robj <- FUN(X, Y, ...)
else
robj <- mapply(FUN, X, Y, MoreArgs=list(...))
dim(robj) <- c(dX, dY)
}
if (no.nx)
nx <- vector("list", length(dX))
else if (no.ny)
ny <- vector("list", length(dY))
if (!(no.nx && no.ny))
dimnames(robj) <- c(nx, ny)
robj
}
# Some examples
f <- function(x, y, p=1) {cat("in f\n"); (x*y)^p}
outer2(1:2, 3:5, f, 2)
outer2(numeric(0), 3:5, f, 2)
outer2(1:2, numeric(0), f, 2)
outer2(1:2, 3:5, f, 2, VECTORIZED=F)
outer2(numeric(0), 3:5, f, 2, VECTORIZED=F)
outer2(1:2, numeric(0), f, 2, VECTORIZED=F)
# Output on examples
f <- function(x, y, p=1) {cat("in f\n"); (x*y)^p}
outer2(1:2, 3:5, f, 2)
in f
[,1] [,2] [,3]
[1,] 9 16 25
[2,] 36 64 100
outer2(numeric(0), 3:5, f, 2)
outer2(1:2, numeric(0), f, 2)
outer2(1:2, 3:5, f, 2, VECTORIZED=F)
in f
in f
in f
in f
in f
in f
[,1] [,2] [,3]
[1,] 9 16 25
[2,] 36 64 100
outer2(numeric(0), 3:5, f, 2, VECTORIZED=F)
outer2(1:2, numeric(0), f, 2, VECTORIZED=F)
[1,]
[2,]
If a patch to add this feature would be considered, I'd
submit one (including documentation). If so, and if there are any
potential traps I should bear in mind, please let me know!
-- Tony Plate
Rau, Roland wrote:
Dear all,
a big thanks to Thomas Lumley, James Holtman and Tony
answers. They all pointed in the same direction => I
function to be applied. Hence, I will try to work with a
function as described in the FAQ.
Thanks again,
Roland
-----Original Message-----
From: Thomas Lumley [mailto:tlumley at u.washington.edu]
Sent: Thursday, October 27, 2005 11:39 PM
To: Rau, Roland
Cc: r-help at stat.math.ethz.ch
Subject: Re: [R] outer-question
You want FAQ 7.17 Why does outer() behave strangely
-thomas
On Thu, 27 Oct 2005, Rau, Roland wrote:
Dear all,
This is a rather lengthy message, but I don't know what I
my real example since the simple code works.
I have two variables a, b and a function f for which I
calculate all possible combinations of the values of a and b.
If f is multiplication, I would simply do:
a <- 1:5
b <- 1:5
outer(a,b)
## A bit more complicated is this:
f <- function(a,b,d) {
return(a*b+(sum(d)))
}
additional <- runif(100)
outer(X=a, Y=b, FUN=f, d=additional)
## So far so good. But now my real example. I would
## log-likelihood surface for two parameters alpha and beta of
## a Gompertz distribution with given data
### I have a function to generate random-numbers from a
Gompertz-Distribution
### (using the 'inversion method')
random.gomp <- function(n, alpha, beta) {
return( (log(1-(beta/alpha*log(1-runif(n)))))/beta)
}
## Now I generate some 'lifetimes'
no.people <- 1000
al <- 0.1
bet <- 0.1
lifetimes <- random.gomp(n=no.people, alpha=al, beta=bet)
### Since I neither have censoring nor truncation in this
### the log-likelihood should be simply the sum of the
### the densities (following the parametrization of
### Survival Analysis, p. 38)
loggomp <- function(alphas, betas, timep) {
return(sum(log(alphas) + betas*timep + (alphas/betas *
(1-exp(betas*timep)))))
}
### Now I thought I could obtain a matrix of the
### by specifying possible values for alpha and beta
data.
### I was able to produce this matrix with two for-loops.
### I could use also 'outer' in this case.
### This is what I tried:
possible.alphas <- seq(from=0.05, to=0.15, length=30)
possible.betas <- seq(from=0.05, to=0.15, length=30)
outer(X=possible.alphas, Y=possible.betas, FUN=loggomp,
outer(X=possible.alphas, Y=possible.betas, FUN=loggomp,
timep=lifetimes)
Error in outer(X = possible.alphas, Y = possible.betas, FUN
:
dim<- : dims [product 900] do not match the length
In addition: Warning messages:
...
### Can somebody give me some hint where the problem is?
### I checked my definition of 'loggomp' but I thought this
loggomp(alphas=possible.alphas[1], betas=possible.betas[1],
timep=lifetimes)
loggomp(alphas=possible.alphas[4], betas=possible.betas[10],
timep=lifetimes)
loggomp(alphas=possible.alphas[3], betas=possible.betas[11],
timep=lifetimes)
### I'd appreciate any kind of advice.
### Thanks a lot in advance.
### Roland
+++++
This mail has been sent through the MPI for Demographic