2013-02-25 14 views
21

używałem funkcji prcomp kiedy otrzymał ten błądUsuwanie stałych kolumn w R

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

wiem, że mogę skanować moich danych ręcznie, ale jest jakaś funkcja lub komenda w R, które mogą mi pomóc usunąć te stałe zmienne? Wiem, że jest to bardzo proste zadanie, ale nigdy nie byłem w żadnej funkcji, która to robi.

Dzięki,

+1

Przeczytaj wskazówki dotyczące publikowania i podaj małą, powtarzalną próbkę "x". W tej chwili nie wiemy nawet, czy twoje "x" jest numeryczne, nie mówiąc już o macierzy. Teraz, jeśli jest to macierz, wystarczy "y <- x [, sd (x)! = 0]". –

+1

Prawdopodobnie nie jest to konieczne, jeśli używasz prcomp na swoich danych, ale jeśli masz mieszane typy kolumn, prostym rozwiązaniem jest 'x [, zastosuj (x, 2, funkcja (col) {length (unique (col))> 1 })] ' –

Odpowiedz

35

Problem polega na tym, że wariancja kolumna jest równa zeru. Można sprawdzić, które kolumna ramki danych jest stała w ten sposób, na przykład:

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" 

Więc jeśli chcesz, aby wykluczyć tych kolumn, można użyć:

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

EDIT: W rzeczywistości jest prostsze w użyciu zamiast tego apply. Coś takiego:

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

Czy jest to szybszy (lub bardziej rozbudowany) niż mój minisolution w powyższym komentarzu? - poza tym, że używam oficjalnie przestarzałej operacji z 'sd' :-) –

+1

@CarlWitthoft No cóż, jako że porady przy korzystaniu z' sd (x) 'należy użyć' apply (x, 2, sd) ' , Myślę, że to całkiem to samo, jeśli postępujesz zgodnie z radą :) – juba

+0

świetna odpowiedź, dzięki – zach

9

Chyba to Q & A jest popularny wynik wyszukiwania Google, ale odpowiedź jest nieco powolny dla dużej matrycy, plus nie mam wystarczającej reputacji skomentowania pierwszej odpowiedzi. Dlatego zamieszczam nową odpowiedź na to pytanie.

Dla każdej kolumny dużej matrycy sprawdzanie, czy maksimum jest równe minimum, jest wystarczające.

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

To jest test. Ponad 90% czasu jest zmniejszone w porównaniu do pierwszej odpowiedzi. Jest także szybszy niż odpowiedź z drugiego komentarza na pytanie.

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

Wyobrażam sobie, że około 15% szybciej używać wszystkich (x == x [1], na.rm = PRAWDA) zamiast obliczać maksimum i min. – DavidR

+0

Pozycja (funkcja (x)! Is.na (x), x) daje pozycję indeksu pierwszego elementu innego niż na, i to spędza znacznie więcej czasu, jeśli x ma pewne wartości na. – raymkchow

1

Ponieważ Q & A jest popularny wynik wyszukiwania Google, ale odpowiedź jest nieco powolny dla dużej matrycy i wersja @raymkchow jest powolny z agencji krajowych i zaproponować nową wersję stosując wykładniczą wyszukiwanie i data.table moc. Jest to funkcja, którą zaimplementowałem w pakiecie dataPreparation.

Pierwszy zbudować data.table exemple, z więcej linii niż kolumn (które to zwykle bywa) i 10% NAS

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) 

Następnie benchmarku wszystkie podejścia:

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 

Te wyniki są następujące:

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 jest 10 razy większa niż O inne podejścia.

Ponadto im więcej rzędów, tym bardziej interesujące jest ich użycie.