2013-02-25 4 views
21

stavo usando la funzione prcomp quando ho ricevuto questo errorerimozione di colonne costanti in R

Error in prcomp.default(x, ...) : 
cannot rescale a constant/zero column to unit variance 

so che può eseguire la scansione dei miei dati manualmente ma c'è una funzione o un comando in R che può aiutarmi a rimuovere questi variabili costanti? So che questo è un compito molto semplice, ma non ho mai incontrato alcuna funzione che faccia questo.

Grazie,

+1

Leggere le linee guida per la pubblicazione e fornire un piccolo campione riproducibile 'x'. In questo momento non sappiamo nemmeno se il tuo 'x' è numerico, per non parlare di una matrice. Ora, se è una matrice, 'y <- x [, sd (x)! = 0]' sarà sufficiente. –

+1

Probabilmente non è necessario se stai usando prcomp sui tuoi dati, ma se hai tipi di colonne miste, una soluzione semplice è 'x [, applica (x, 2, function (col) {length (unique (col))> 1 })] ' –

risposta

35

Il problema qui è che la varianza colonna è uguale a zero. È possibile verificare quale colonna di un frame di dati è costante in questo modo, ad esempio:

df <- data.frame(x=1:5, y=rep(1,5)) 
df 
# x y 
# 1 1 1 
# 2 2 1 
# 3 3 1 
# 4 4 1 
# 5 5 1 

# Supply names of columns that have 0 variance 
names(df[, sapply(df, function(v) var(v, na.rm=TRUE)==0)]) 
# [1] "y" 

Quindi, se si desidera escludere queste colonne, è possibile utilizzare:

df[,sapply(df, function(v) var(v, na.rm=TRUE)!=0)] 

EDIT: Infatti è più semplice usare invece apply. Qualcosa di simile a questo:

df[,apply(df, 2, var, na.rm=TRUE) != 0] 
+0

È più veloce (o più robusto) della mia minisoluzione nel commento sopra? - a parte il fatto che sto usando un'operazione ufficialmente deprecata con 'sd' :-) –

+1

@CarlWitthoft Bene, dal momento che il consiglio quando si usa' sd (x) 'è quello di usare' apply (x, 2, sd) ' , Penso che sia lo stesso, se segui il consiglio :) – juba

+0

ottima risposta, grazie – zach

9

Credo che questo Q & A è un popolare risultato di ricerca di Google, ma la risposta è un po 'lento per una grande matrice, più non ho abbastanza fama di commentare la prima risposta. Pertanto invio una nuova risposta alla domanda.

Per ciascuna colonna di una matrice grande è sufficiente verificare se il massimo è uguale al minimo.

df[,!apply(df, MARGIN = 2, function(x) max(x, na.rm = TRUE) == min(x, na.rm = TRUE))] 

Questo è il test. Più del 90% del tempo è ridotto rispetto alla prima risposta. È anche più veloce della risposta del secondo commento sulla domanda.

ncol = 1000000 
nrow = 10 
df <- matrix(sample(1:(ncol*nrow),ncol*nrow,replace = FALSE), ncol = ncol) 
df[,sample(1:ncol,70,replace = FALSE)] <- rep(1,times = nrow) # df is a large matrix 

time1 <- system.time(df1 <- df[,apply(df, 2, var, na.rm=TRUE) != 0]) # the first method 
time2 <- system.time(df2 <- df[,!apply(df, MARGIN = 2, function(x) max(x, na.rm = TRUE) == min(x, na.rm = TRUE))]) # my method 
time3 <- system.time(df3 <- df[,apply(df, 2, function(col) { length(unique(col)) > 1 })]) # Keith's method 

time1 
# user system elapsed 
# 22.267 0.194 22.626 
time2 
# user system elapsed 
# 2.073 0.077 2.155 
time3 
# user system elapsed 
# 6.702 0.060 6.790 
all.equal(df1, df2) 
# [1] TRUE 
all.equal(df3, df2) 
# [1] TRUE 
+1

Ritrovo e ho trovato che è circa il 15% più veloce per usare tutto (x == x [1], na.rm = TRUE) piuttosto che calcolare il massimo e il minimo. – DavidR

+0

Position (function (x)! Is.na (x), x) fornisce la posizione dell'indice del primo elemento non na, e questo trascorre molto più tempo se x ha alcuni valori na. – raymkchow

1

Dal momento che questo Q & A è un popolare risultato di ricerca di Google, ma la risposta è un po 'lento per una grande matrice e la versione @raymkchow è lento con AN propongo una nuova versione utilizzando la ricerca esponenziale e data.table potere.

Questa è una funzione implementata nel pacchetto dataPreparation.

primo costruire un data.table Esempio, con più linee di colonne (che è normalmente il caso) e 10% di AN

ncol = 1000 
nrow = 100000 
df <- matrix(sample(1:(ncol*nrow),ncol*nrow,replace = FALSE), ncol = ncol) 
df <- apply (df, 2, function(x) {x[sample(c(1:nrow), floor(nrow/10))] <- NA; x}) # Add 10% of NAs 
df[,sample(1:ncol,70,replace = FALSE)] <- rep(1,times = nrow) # df is a large matrix 
df <- as.data.table(df) 

Poi benchmark tutti gli approcci:

time1 <- system.time(df1 <- df[,apply(df, 2, var, na.rm=TRUE) != 0, with = F]) # the first method 
time2 <- system.time(df2 <- df[,!apply(df, MARGIN = 2, function(x) max(x, na.rm = TRUE) == min(x, na.rm = TRUE)), with = F]) # raymkchow 
time3 <- system.time(df3 <- df[,apply(df, 2, function(col) { length(unique(col)) > 1 }), with = F]) # Keith's method 
time4 <- system.time(df4 <- df[,-whichAreConstant(df, verbose=FALSE)]) # My method 

I risultati sono i seguenti:

time1 # Variance approch 
# user system elapsed 
# 2.55 1.45 4.07 
time2 # Min = max approach 
# user system elapsed 
# 2.72  1.5 4.22 
time3 # length(unique()) approach 
# user system elapsed 
# 6.7 2.75 9.53 
time4 # Exponential search approach 
# user system elapsed 
# 0.39 0.07 0.45 
all.equal(df1, df2) 
# [1] TRUE 
all.equal(df3, df2) 
# [1] TRUE 
all.equal(df4, df2) 
# [1] TRUE 

dataPreparation:whichAreConstant è 10 volte più veloce rispetto al o altri approcci.

Inoltre, più file si hanno e più si interseca.