Я часто объясняю outer(x, y, FUN)
, когда x
и y
являются векторами со следующим:
xx <- rep(x, times = length(y))
yy <- rep(y, each = length(x))
zz <- FUN(xx, yy)
stopifnot(length(zz) == length(x) * length(y)) ## length = product?
z <- matrix(zz, length(x), length(y))
funError
терпит неудачу, потому что zz
имеет длину 1, а funNoError
делаетне потому, что «правило утилизации» было применено при вставке a
(вектор с длиной> 1) и class(a)
(вектор с длиной 1).
Это показательно, поскольку вы поймете, почему outer(1:5, 1:5, "+")
работает, но outer(1:5, 1:5, sum)
не работает.По сути, FUN
должен уметь обрабатывать xx
и yy
поэлементно .В противном случае, оберните FUN
функцией сахара под названием Vectorize
.Более подробная информация приведена позже.
Обратите внимание, что «список» также является допустимым режимом вектора.Так что outer
может быть использовано для некоторых нестандартных вещей, таких как Как выполнить парную операцию, такую как `% in%`, и установить операции для списка векторов .
Youтакже может передавать матрицы / массивы в outer
.Учитывая, что это просто векторы с атрибутом "dim" (необязательно с "dimnames"), принцип работы outer
не меняется.
x <- matrix(1:4, 2, 2) ## has "dim"
y <- matrix(1:9, 3, 3) ## has "dim"
xx <- rep(x, times = length(y)) ## xx <- rep(c(x), times = length(y))
yy <- rep(y, each = length(x)) ## yy <- rep(c(y), each = length(x))
zz <- "*"(xx, yy)
stopifnot(length(zz) == length(x) * length(y)) ## length = product?
z <- "dim<-"( zz, c(dim(x), dim(y)) )
z0 <- outer(x, y, "*")
all.equal(z, z0)
#[1] TRUE
?outer
объясняет приведенный выше код в простых словах.
‘X’ and ‘Y’ must be suitable arguments for ‘FUN’. Each will be
extended by ‘rep’ to length the products of the lengths of ‘X’ and
‘Y’ before ‘FUN’ is called.
‘FUN’ is called with these two extended vectors as arguments (plus
any arguments in ‘...’). It must be a vectorized function (or the
name of one) expecting at least two arguments and returning a
value with the same length as the first (and the second).
Where they exist, the [dim]names of ‘X’ and ‘Y’ will be copied to
the answer, and a dimension assigned which is the concatenation of
the dimensions of ‘X’ and ‘Y’ (or lengths if dimensions do not
exist).
Слово "векторизация" является НЕ наиболее обсуждаемым в R по производительности .Это означает «векторизацию действия функции»:
## for FUN with a single argument
FUN( c(x1, x2, x3, x4) ) = c( FUN(x1), FUN(x2), FUN(x3), FUN(x4) )
## for FUN with two arguments
FUN( c(x1, x2, x3, x4), c(y1, y2, y3, y4) )
= c( FUN(x1, y1), FUN(x2, y2), FUN(x3, y3), FUN(x4, y4) )
Некоторые функции говорят, что "+"
, "*"
, paste
ведут себя так, но многие другие не говорят, например, class
,sum
, prod
.Семейные функции *apply
в R предназначены для того, чтобы помочь вам векторизовать действие функции, или вы можете написать свой собственный цикл для достижения того же эффекта.
Еще одна полезная статья для хорошего качества: Почему внешний не работает так, как я думаю (в R)?