I was looking at the benchmarks in this answer, and wanted to compare them with diag
(used in a different answer). Unfortunately, it seems that diag
takes ages:
nc <- 1e4
set.seed(1)
m <- matrix(sample(letters,nc^2,replace=TRUE), ncol = nc)
microbenchmark(
diag = diag(m),
cond = m[row(m)==col(m)],
vec = m[(1:nc-1L)*nc+1:nc],
mat = m[cbind(1:nc,1:nc)],
times=10)
Comments: I tested these with identical
. I took "cond" from one of the answers to this homework question. Results are similar with a matrix of integers, 1:26
instead of letters
.
Results:
Unit: microseconds
expr min lq mean median uq max neval
diag 604343.469 629819.260 710371.3320 706842.3890 793144.019 837115.504 10
cond 3862039.512 3985784.025 4175724.0390 4186317.5260 4312493.742 4617117.706 10
vec 317.088 329.017 432.9099 350.1005 629.460 651.376 10
mat 272.147 292.953 441.7045 345.9400 637.506 706.860 10
It is just a matrix-subsetting operation, so I don't know why there's so much overhead. Looking inside the function, I see a few checks and then c(m)[v]
, where v
is the same vector used in the "vec" benchmark. Timing these two...
v <- (1:nc-1L)*nc+1:nc
microbenchmark(diaglike=c(m)[v],vec=m[v])
# Unit: microseconds
# expr min lq mean median uq max neval
# diaglike 579224.436 664853.7450 720372.8105 712649.706 767281.5070 931976.707 100
# vec 334.843 339.8365 568.7808 646.799 663.5825 1445.067 100
...it seems I have found my culprit. So, the new variation on my question is: Why is there a seemingly unnecessary and very time-consuming c
in diag
?
c()
forces the input into a vector. Could be to deal with varying input types by coercing to a vector so as to process all types the same way. Or as a quick and dirty means of checking the input type (a data frame input throws an error because ofc
). – Adinais.matrix
is true. It's a pretty small function if you want to have a look -- just typediag
. (Oh and vanilla data.frames are not matrices, it turns outis.matrix(data.frame(1)) # FALSE
.) – Afghanistanis.matrix
part. And as it turns out thatc
isn't the reason why data frame input throws an error;c
works on data frames. I know that data frames aren't matrices. I think a data frame input makes it all the way to.Internal
. – Adinac
because it removes all attributes. You could ask on the r-devel mailing list. – Renndiag
. Try.Internal(diag(1, 2, 2))
to see what it does. – Rennm[seq.int(1,nc^2,nc+1)]
is the fastest on my machine. – Nyx"["
method for a matrix-like object with a "class" attribute:xx = structure(1:9, dim = c(3, 3), class = "mymatrix"); "[.mymatrix" = function(x, i) "no '[' method"
. Then, maybe, the attribute loss fromc
could be helpful:v = (1:ncol(xx) - 1L) * ncol(xx) + 1:ncol(xx)
;xx[v]
vsc(xx)[v]
– Biracialxx
to get that far, it would have to haveclass=c("matrix","mymatrix")
(since there's anif(is.matrix(xx))
there). I don't know how to do it in base R, but data.table has a function that works here without making a copy:setattr(xx,"class","matrix")[v]
. A couple R core folks replied in that thread, but what Luke Tierney's saying is a little over my head. (I've never developed a package or made a class with dispatch methods.) – Afghanistanis.matrix(xx)
returnsTRUE
sincelength(dim(xx)) == 2
. I'm saying, that in such a casediag
outputs the correct result, although I highly doubt that such a situation will ever occur in an object that "inherits" from "matrix" anddiag
is not that crucial a function to have been built to forestall anything crazy. And, also,c
can still have uncommon class methods to even ruinc(xx)[v]
e.g. as in something likec.mymatrix = function(x) stop("no 'c' method")
;c(xx)[v]
. I'm interested, though, as to whyc
remains indiag
. Interesting thread! – Biracial