Note that there are some explanatory texts on larger screens.

plurals
  1. POSweep warnings when using ggbiplot to plot FactoMineR's PCA object
    primarykey
    data
    text
    <p>I'm trying to adapt <a href="https://github.com/vqv/ggbiplot" rel="nofollow noreferrer">ggbiplot</a> to work with the <code>PCA</code> data object produced by the <code>FactoMineR</code> package but I'm getting warnings I don't understand.</p> <p>Here's what I've done so far, I've added the bit starting at <code>else if(inherits(pcobj, 'PCA'))</code> and ending at the next <code>}</code> using details I've found on the <code>FactoMineR</code> email list. I haven't changed anything elsewhere in the code, which is reproduced here entirely: </p> <pre><code> ggbiplot &lt;- function(pcobj, choices = 1:2, scale = 1, pc.biplot = TRUE, obs.scale = 1 - scale, var.scale = scale, groups = NULL, ellipse = FALSE, ellipse.prob = 0.68, labels = NULL, labels.size = 3, alpha = 1, var.axes = TRUE, circle = FALSE, circle.prob = 0.69, varname.size = 3, varname.adjust = 1.5, varname.abbrev = FALSE, ...) { library(ggplot2) library(plyr) library(scales) library(grid) stopifnot(length(choices) == 2) # Recover the SVD if(inherits(pcobj, 'prcomp')){ nobs.factor &lt;- sqrt(nrow(pcobj$x) - 1) d &lt;- pcobj$sdev u &lt;- sweep(pcobj$x, 2, 1 / (d * nobs.factor), FUN = '*') v &lt;- pcobj$rotation } else if(inherits(pcobj, 'princomp')) { nobs.factor &lt;- sqrt(pcobj$n.obs) d &lt;- pcobj$sdev u &lt;- sweep(pcobj$scores, 2, 1 / (d * nobs.factor), FUN = '*') v &lt;- pcobj$loadings } else if(inherits(pcobj, 'PCA')) { nobs.factor &lt;- sqrt(nrow(pcobj$call$X)) d &lt;- unlist(sqrt(pcobj$eig)[1]) u &lt;- sweep(pcobj$ind$coord, 2, 1 / (d * nobs.factor), FUN = '*') v &lt;- sweep(pcobj$var$coord,2,sqrt(pcobj$eig[1:ncol(pcobj$var$coord),1]),FUN="/") } else { stop('Expected a object of class prcomp, princomp or PCA') } # Scores df.u &lt;- as.data.frame(sweep(u[,choices], 2, d[choices]^obs.scale, FUN='*')) # Directions v &lt;- sweep(v, 2, d^var.scale, FUN='*') df.v &lt;- as.data.frame(v[, choices]) names(df.u) &lt;- c('xvar', 'yvar') names(df.v) &lt;- names(df.u) if(pc.biplot) { df.u &lt;- df.u * nobs.factor } # Scale the radius of the correlation circle so that it corresponds to # a data ellipse for the standardized PC scores r &lt;- sqrt(qchisq(circle.prob, df = 2)) * prod(colMeans(df.u^2))^(1/4) # Scale directions v.scale &lt;- rowSums(v^2) df.v &lt;- r * df.v / sqrt(max(v.scale)) # Change the labels for the axes if(obs.scale == 0) { u.axis.labs &lt;- paste('standardized PC', choices, sep='') } else { u.axis.labs &lt;- paste('PC', choices, sep='') } # Append the proportion of explained variance to the axis labels u.axis.labs &lt;- paste(u.axis.labs, sprintf('(%0.1f%% explained var.)', 100 * pcobj$sdev[choices]^2/sum(pcobj$sdev^2))) # Score Labels if(!is.null(labels)) { df.u$labels &lt;- labels } # Grouping variable if(!is.null(groups)) { df.u$groups &lt;- groups } # Variable Names if(varname.abbrev) { df.v$varname &lt;- abbreviate(rownames(v)) } else { df.v$varname &lt;- rownames(v) } # Variables for text label placement df.v$angle &lt;- with(df.v, (180/pi) * atan(yvar / xvar)) df.v$hjust = with(df.v, (1 - varname.adjust * sign(xvar)) / 2) # Base plot g &lt;- ggplot(data = df.u, aes(x = xvar, y = yvar)) + xlab(u.axis.labs[1]) + ylab(u.axis.labs[2]) + coord_equal() if(var.axes) { # Draw circle if(circle) { theta &lt;- c(seq(-pi, pi, length = 50), seq(pi, -pi, length = 50)) circle &lt;- data.frame(xvar = r * cos(theta), yvar = r * sin(theta)) g &lt;- g + geom_path(data = circle, color = muted('white'), size = 1/2, alpha = 1/3) } # Draw directions g &lt;- g + geom_segment(data = df.v, aes(x = 0, y = 0, xend = xvar, yend = yvar), arrow = arrow(length = unit(1/2, 'picas')), color = muted('red')) } # Draw either labels or points if(!is.null(df.u$labels)) { if(!is.null(df.u$groups)) { g &lt;- g + geom_text(aes(label = labels, color = groups), size = labels.size) } else { g &lt;- g + geom_text(aes(label = labels), size = labels.size) } } else { if(!is.null(df.u$groups)) { g &lt;- g + geom_point(aes(color = groups), alpha = alpha) } else { g &lt;- g + geom_point(alpha = alpha) } } # Overlay a concentration ellipse if there are groups if(!is.null(df.u$groups) &amp;&amp; ellipse) { theta &lt;- c(seq(-pi, pi, length = 50), seq(pi, -pi, length = 50)) circle &lt;- cbind(cos(theta), sin(theta)) ell &lt;- ddply(df.u, 'groups', function(x) { if(nrow(x) &lt; 2) { return(NULL) } else if(nrow(x) == 2) { sigma &lt;- var(cbind(x$xvar, x$yvar)) } else { sigma &lt;- diag(c(var(x$xvar), var(x$yvar))) } mu &lt;- c(mean(x$xvar), mean(x$yvar)) ed &lt;- sqrt(qchisq(ellipse.prob, df = 2)) data.frame(sweep(circle %*% chol(sigma) * ed, 2, mu, FUN = '+'), groups = x$groups[1]) }) names(ell)[1:2] &lt;- c('xvar', 'yvar') g &lt;- g + geom_path(data = ell, aes(color = groups, group = groups)) } # Label the variable axes if(var.axes) { g &lt;- g + geom_text(data = df.v, aes(label = varname, x = xvar, y = yvar, angle = angle, hjust = hjust), color = 'darkred', size = varname.size) } # Change the name of the legend for groups # if(!is.null(groups)) { # g &lt;- g + scale_color_brewer(name = deparse(substitute(groups)), # palette = 'Dark2') # } return(g) } </code></pre> <p>It produces a plot, like so:</p> <pre><code>library(FactoMineR) data(decathlon) res.pca &lt;- PCA(decathlon, quanti.sup = 11:12, quali.sup=13, graph=FALSE) ggbiplot(res.pca) </code></pre> <p><img src="https://i.stack.imgur.com/kfO3R.png" alt="enter image description here"></p> <p>But it also produces these warnings, which I don't understand (@baptiste's suggestion removed a bunch of other warnings):</p> <pre><code> Warning messages: 1: In sweep(pcobj$ind$coord, 2, 1/(d * nobs.factor), FUN = "*") : STATS is longer than the extent of 'dim(x)[MARGIN]' 2: In sweep(v, 2, d^var.scale, FUN = "*") : STATS is longer than the extent of 'dim(x)[MARGIN]' </code></pre> <p>How do I fix the <code>ggbiplot</code> code so it doesn't produce these warnings when plotting a <code>PCA</code> object? I'm worried they might be causing the output to be not what I'm expecting.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload