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