Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Reduce" adds unrequested attributes to result

Contrast the following two code snippets:

1.

> a <- cbind(1,2)
> a
     [,1] [,2]
[1,]    1    2
> str(a)
 num [1, 1:2] 1 2

2.

> b <- Reduce(cbind, list(1,2))
> b
     init  
[1,]    1 2
> str(b)
 num [1, 1:2] 1 2
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr [1:2] "init" ""

According to the Reduce help page, i would expect a and b to be the same, but they're obviously not quite. Why is it?

like image 276
Evan Aad Avatar asked Feb 14 '23 06:02

Evan Aad


2 Answers

It's because of how Reduce calls f and how cbind creates column names. Reduce determines the initial value based on the values of the init and right args and stores that value in an object named init, which it also happens to update iteratively.

In your example, the following code in Reduce is where the difference occurs:

init <- x[[1L]]
ind <- ind[-1L]
for (i in ind) init <- f(init, x[[i]])

The default cbind argument, deparse.level = 1 means that it tries to create dimnames via deparsing the object names passed to it (if they make sensible names). If you want the Reduce output to be identical to calling cbind on single numbers, then set deparse.level=0.

> str(Reduce(function(x,y) cbind(x,y,deparse.level=0), list(1,2)))
 num [1, 1:2] 1 2

As an aside, calling cbind in a for loop is a bad idea because it must re-allocate memory on each iteration, leading to very slow code. It's much better to allocate the full output object you expect (if you can) and then fill in the elements.

like image 195
Joshua Ulrich Avatar answered Feb 28 '23 12:02

Joshua Ulrich


The answer of Joshua explains why you have a difference. I just show how to get the same output. Indeed you should initialize the init parameter to NULL:

 identical(Reduce(cbind, list(1,2),init=NULL),
           cbind(1,2))
 TRUE

And as aside is more efficient here to call :

 do.call(cbind,list(1,2))
like image 25
agstudy Avatar answered Feb 28 '23 14:02

agstudy