web-dev-qa-db-fra.com

Comment résoudre prcomp.default (): impossible de redimensionner une variance constante/zéro en unité

J'ai un ensemble de données de 9 échantillons (lignes) avec 51608 variables (colonnes) et je reçois toujours l'erreur chaque fois que j'essaie de la redimensionner:

Cela fonctionne bien

pca = prcomp(pca_data)

Cependant,

pca = prcomp(pca_data, scale = T)

donne

> Error in prcomp.default(pca_data, center = T, scale = T) : 
  cannot rescale a constant/zero column to unit variance

De toute évidence, il est un peu difficile de publier un exemple reproductible. Des idées ce que l'accord pourrait être?

Vous recherchez des colonnes constantes:

    sapply(1:ncol(pca_data), function(x){
               length = unique(pca_data[, x]) %>% length
             }) %>% table

Sortie:

    .
        2     3     4     5     6     7     8     9 
     3892  4189  2124  1783  1622  2078  5179 30741 

Donc pas de colonnes constantes. Même avec les NA - 

    is.na(pca_data) %>% sum

    >[1] 0

Cela fonctionne bien:

    pca_data = scale(pca_data)

Mais ensuite, les deux donnent toujours exactement la même erreur:

    pca = prcomp(pca_data)
    pca = prcomp(pca_data, center = F, scale = F)

Alors, pourquoi ne puis-je pas obtenir une pca mise à l'échelle sur ces données? Ok, assurons-nous à 100% que ce n'est pas constant.

    pca_data = pca_data + rnorm(nrow(pca_data) * ncol(pca_data))

Les mêmes erreurs. Données numériques?

    sapply( 1:nrow(pca_data), function(row){
      sapply(1:ncol(pca_data), function(column){
         !is.numeric(pca_data[row, column])
       })
     } ) %>% sum

Toujours les mêmes erreurs. Je suis à court d'idées. 

Edit: plus et un bidouillage au moins pour le résoudre.

Plus tard, il est toujours difficile de regrouper ces données, par exemple:

    Error in hclust(d, method = "ward.D") : 
      NaN dissimilarity value in intermediate results. 

Réduire les valeurs sous un certain seuil, par exemple <1 à zéro n'a aucun effet. Ce qui a finalement fonctionné a été de supprimer toutes les colonnes contenant plus de x zéros dans la colonne. A travaillé pour # zéros <= 6, mais 7+ ont généré des erreurs. Aucune idée si cela signifie qu'il s'agit d'un problème en général ou si cela vient de capturer une colonne problématique. Je serais toujours heureux de savoir si quelqu'un a des idées, car cela devrait fonctionner correctement tant qu'aucune variable n'est composée de zéros (ou de constantes d'une autre manière).

10
Brian Jackson

Je ne pense pas que vous recherchiez des colonnes à variance nulle Essayons avec des données factices. Tout d'abord, une matrice acceptable: de 10x100:

mat <- matrix(rnorm(1000, 0), nrow = 10)

Et un avec une colonne zéro-variance. Appelons cela oopsmat.

const <- rep(0.1,100)
oopsmat <- cbind(const, mat)

Les premiers éléments de oopsmat ressemblent à ceci:

      const                                                                                               
 [1,]   0.1  0.75048899  0.5997527 -0.151815650  0.01002536  0.6736613 -0.225324647 -0.64374844 -0.7879052
 [2,]   0.1  0.09143491 -0.8732389 -1.844355560  0.23682805  0.4353462 -0.148243210  0.61859245  0.5691021
 [3,]   0.1 -0.80649512  1.3929716 -1.438738923 -0.09881381  0.2504555 -0.857300053 -0.98528008  0.9816383
 [4,]   0.1  0.49174471 -0.8110623 -0.941413109 -0.70916436  1.3332522  0.003040624  0.29067871 -0.3752594
 [5,]   0.1  1.20068447 -0.9811222  0.928731706 -1.97469637 -1.1374734  0.661594937  2.96029102  0.6040814

Essayons des PCA mis à l'échelle et non mis à l'échelle sur oopsmat:

PCs <- prcomp(oopsmat) #works
PCs <- prcomp(oopsmat, scale. = T) #not forgetting the dot
#Error in prcomp.default(oopsmat, scale. = T) : 
   #cannot rescale a constant/zero column to unit variance

Parce que vous ne pouvez pas diviser par l'écart type si c'est l'infini. Pour identifier la colonne à variance nulle, nous pouvons utiliser which comme suit pour obtenir le nom de la variable.

which(apply(oopsmat, 2, var)==0)
#const 
#1 

Et pour supprimer les colonnes à variance nulle de l'ensemble de données, vous pouvez utiliser la même expression apply, en définissant la variance différente de zéro.

oopsmat[ , apply(oopsmat, 2, var) != 0]

Espérons que cela aide à rendre les choses plus claires!

13
Joe

En plus de la réponse de Joe, vérifiez que les classes des colonnes de votre cadre de données sont des méthodes numériques.

S'il existe des entiers, vous obtiendrez des variances de 0, ce qui entraînera l'échec de la mise à l'échelle.

Donc si, 

class(my_df$some_column)

est un entier64, par exemple, puis procédez comme suit

my_df$some_column <- as.numeric(my_df$some_column)

J'espère que ça aide quelqu'un.

0
orrymr