"Dims [Product Xx] Do Not Match the Length of Object [Xx]" Error in Using R Function 'Outer'

dims [product xx] do not match the length of object [xx] error in using R function `outer`

I often explain outer(x, y, FUN) when both x and y are vectors with the following:

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 fails because zz has length 1, while funNoError does not because "recycling rule" has been applied when you paste a (a vector with length > 1) and class(a) (a length-1 vector).

This is illustrative as you will see why outer(1:5, 1:5, "+") works but outer(1:5, 1:5, sum) fails. Basically, FUN must be able to process xx and yy element-wise. Otherwise, wrap FUN with a sugar function called Vectorize. More details are given later.

Note that "list" is also a valid mode of a vector. So outer could be used to some non-standard things like How to perform pairwise operation like `%in%` and set operations for a list of vectors.


You can pass matrices / arrays to outer, too. Given that they are just vectors with an "dim" attribute (optionally with "dimnames"), how outer works does not change.

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 explains the code above in plain words.

 ‘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).

The word "vectorized" is NOT the most discussed one in R on performance. It means "vectorizing the action of a function":

## 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) )

Some functions say "+", "*", paste behave like this, but many others don't, say class, sum, prod. The *apply family functions in R are there to help you to vectorize function action, or you can write your own loop to achieve the same effect.


Another worth reading good-quality Q & A: Why doesn't outer work the way I think it should (in R)?

R - cross validation error handling-- dims product do not match the length of object

If you want to "fix" this you will need to pull out the attributes of the pred object and then select matching values from the Hitters object based on its rownames().

> str(Hitters$Salary)
num [1:322] NA 475 480 500 91.5 750 70 100 75 1100 ...
> str(pred)
num [1:18, 1] 988 359 370 808 383 ...
- attr(*, "dimnames")=List of 2
..$ : chr [1:18] "-Andre Thornton" "-Bob Dernier" "-Chris Brown" "-Chet Lemon" ...
..$ : NULL
> names(Hitters)
[1] "AtBat" "Hits" "HmRun" "Runs" "RBI" "Walks" "Years" "CAtBat"
[9] "CHits" "CHmRun" "CRuns" "CRBI" "CWalks" "League" "Division" "PutOuts"
[17] "Assists" "Errors" "Salary" "NewLeague"
> rownames(Hitters)
[1] "-Andy Allanson" "-Alan Ashby" "-Alvin Davis" "-Andre Dawson"
[5] "-Andres Galarraga" "-Alfredo Griffin" "-Al Newman" "-Argenis Salazar"
[9] "-Andres Thomas" "-Andre Thornton" "-Alan Trammell" "-Alex Trevino"
[13] "-Andy VanSlyke" "-Alan Wiggins" "-Bill Almon" "-Billy Beane"
#omitted the rest of the 322-item column

R reshape package: Error in Dim(x)... dims [product 100] do not match the length of object [109]

I don't know what's causing the error, but here is how you should fix it:

  1. Use reshape2 - this is an updated version which is also faster.
  2. Use dcast - the cast function in reshape2 which explicitly returns a data.frame, as opposed to acast that returns an array.

The code:

library(reshape2)
castDf <- dcast( meltDf , DATE + CITY ~ variable)
castDf

The results:

        DATE   CITY DAILY_MAX_TEMP
1 1953-01-01 Anqing 9.1
2 1953-01-02 Anqing 5.1
3 1953-01-03 Anqing 5.2
4 1953-01-04 Anqing 4.6
5 1953-01-05 Anqing 7.9
6 1953-01-06 Anqing 9.9

dplyr, dunn test, Error in dim(robj) - c(dX, dY) : dims [product 0] do not match the length of object

First of all %>% pipe passes a data.frame to the pairw.kw function as a first argument. Secondly, pairw.kw function wants two vectors as an input. You can achive this with %$% pipe from magrittr package. It works similar to with function.

library(magrittr)

example.df %>%
filter(treated=="No") %$%
pairw.kw(var1, species, conf = 0.95)

Answer to question in comment:

library(tidyverse)
library(magrittr)
library(asbio)

example.df %>%
group_by(treated) %>%
nest() %>%
mutate(
kw = map(
data,
~ .x %$% pairw.kw(var1, species, conf = 0.95)
),
p_val = map_dbl(kw, ~ .x$summary$`Adj. P-value`)
)

R: Use outer() on user-defined function

To use outer, some basic "requirements":

  1. the function will take two vectors all at once (as shown below); whether it chooses to do vectorized work on them or work on them individually is up to you;

  2. it must return a vector of the same length as x (and y); and

  3. you must expect the output as a matrix of dimensions length(x),length(y).

Interpreting that these are not all true for you, we move on. "The right function" depends on how you want the model to be run. A companion function to outer is expand.grid (and tidyr::crossing, the tidyverse version), in that it creates the same combinations of the supplied vectors. For instance:

outer(c(30,60,90), c(30, 60, 100), function(x,y) {browser();1;})
# Called from: FUN(X, Y, ...)
# Browse[2]>
x
# [1] 30 60 90 30 60 90 30 60 90
# Browse[2]>
y
# [1] 30 30 30 60 60 60 100 100 100

and

eg <- expand.grid(x=c(30,60,90), y=c(30, 60, 100))
eg
# x y
# 1 30 30
# 2 60 30
# 3 90 30
# 4 30 60
# 5 60 60
# 6 90 60
# 7 30 100
# 8 60 100
# 9 90 100

(which you can then access as eg$x and eg$y).

Some options:

  1. if you want your function to be called once (as with outer) with two arguments, and it will figure out what to do:

    eg <- expand.grid(x=c(30,60,90), y=c(30, 60, 100))
    do.call("myfunc", eg)

    Note that if given character arguments, it will (similar to data.frame) create factors by default. It does accept the stringsAsFactors=FALSE argument.

  2. if you want your function to be called for each pair of the vectors (so 9 times in this example), then do one either

    myfunc(eg$x, eg$y)

    if the number of vectors is known. If not, then using eg from above, then

    do.call("mapply", c(myfunc, eg))

    should work. Depending on the output, you can preclude it from "simplifying" the output (i.e., force a list output) with

    do.call("mapply", c(myfunc, eg, SIMPLIFY=FALSE))

How to coerce a list object to type 'double'

If you want to convert all elements of a to a single numeric vector and length(a) is greater than 1 (OK, even if it is of length 1), you could unlist the object first and then convert.

as.numeric(unlist(a))
# [1] 10 38 66 101 129 185 283 374

Bear in mind that there aren't any quality controls here. Also, X$Days a mighty odd name.



Related Topics



Leave a reply



Submit