Ошибка "dims [product xx] не соответствует длине объекта [xx]" при использовании функции R `external` - PullRequest
0 голосов
/ 13 сентября 2018
x <- 1:9
names(x) <- paste0("x",x)
y <- 2:5
names(y) <- paste0("y",y)

fun1      <-function(a, b) {paste(class(a),b, sep = "**")} #works
funError  <-function(a, b) {paste(class(a),class(b), sep = "**")} #does not work with outer
funNoError<-function(a, b) {paste(a,class(a),class(b),b, sep = "**")}  #works with outer  

funError(1,2) #is a valid function
outer(x, y, "funError") # fails
outer(x, y, "funNoError") # works

Q1 : почему outer(x, y, "funError") не работает?

Ошибка в dim (robj) <- c (dX, dY): dims [продукт 36] не соответствуют длине объекта [1] </p>

Q2 : Почему outer(x, y, "funNoError") работает?Это очень похоже.

  • Единственное различие, которое я вижу, состоит в том, что каждый "результат" funError идентичен ("numeric**numeric").

  • Если проблема имеет одно и то же значение все время: почему это здесь работает?

outer(rep(0,7), 1:10, "^")


Хорошо, я понял:

lol  <- function(a,b) {"lol"}
lol_v<- Vectorize(lol)

outer(x, y, "lol")   # fails with same Error
outer(x, y, "lol_v") # works as expected

Ответы [ 2 ]

0 голосов
/ 13 сентября 2018

Я часто объясняю 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)?

0 голосов
/ 13 сентября 2018

Я думаю, что это происходит из-за того, что полученная матрица из внешнего интерфейса будет иметь те же размеры, что и ваши входные данные, однако класс (a) имеет длину только 1, поэтому размеры матрицы не совпадают. Попробуйте

funError2 <- function(a,b){paste(rep(class(a), length(a)),rep(class(b), length(b)), sep = "**")}
outer(x,y, "funError2")
#>    y2                 y3                 y4                
#> x1 "integer**integer" "integer**integer" "integer**integer"
#> x2 "integer**integer" "integer**integer" "integer**integer"
#> x3 "integer**integer" "integer**integer" "integer**integer"
#> x4 "integer**integer" "integer**integer" "integer**integer"
#> x5 "integer**integer" "integer**integer" "integer**integer"
#> x6 "integer**integer" "integer**integer" "integer**integer"
#> x7 "integer**integer" "integer**integer" "integer**integer"
#> x8 "integer**integer" "integer**integer" "integer**integer"
#> x9 "integer**integer" "integer**integer" "integer**integer"
#>    y5                
#> x1 "integer**integer"
#> x2 "integer**integer"
#> x3 "integer**integer"
#> x4 "integer**integer"
#> x5 "integer**integer"
#> x6 "integer**integer"
#> x7 "integer**integer"
#> x8 "integer**integer"
#> x9 "integer**integer"

Создано в 2018-09-13 по представ пакет (v0.2.0).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...