2013-02-25 28 views
21

我用的是prcomp功能時,我收到此錯誤去除R中恆列

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

我知道我可以手動掃描我的數據,但有R中的任何功能或命令,可以幫助我消除這些常量變量? 我知道這是一個非常簡單的任務,但我從來沒有遇到任何這樣做的功能。

謝謝,

+1

請閱讀發佈指南,並提供一個小的,可重現的樣本'x'。現在我們甚至不知道你的'x'是數字,更不用說矩陣。現在,如果它是一個矩陣,'y < - x [,sd(x)!= 0]'就足夠了。 – 2013-02-25 14:19:43

+1

如果你在你的數據上使用prcomp,可能沒有必要,但是如果你確實有混合列類型,一個簡單的解決方案是'x [,apply(x,2,function(col){length(unique(col))> 1 })]' – 2015-07-26 11:40:07

回答

35

這裏的問題是,你的列方差等於零。您可以檢查該數據幀的列是恆定的這種方式,例如:

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" 

所以,如果你想排除這些欄,您可以使用:

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

編輯:其實取而代之的是使用apply更簡單。事情是這樣的:

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

在上面的評論中,這是否比我的minisolution更快(或更強大)? - 除此之外,我正在使用'sd'正式棄用的操作:-) – 2013-02-25 15:40:41

+1

@CarlWitthoft嗯,因爲使用'sd(x)'時的建議是使用'apply(x,2,sd)' ,我認爲它是完全一樣的,如果你按照建議:) – juba 2013-02-25 15:45:47

+0

偉大的答案,謝謝 – zach 2014-03-10 16:05:57

9

我想這個問答& A是一個受歡迎的谷歌的搜索結果,但答案是一個大的矩陣有點慢,再加上我沒有足夠的信譽第一的回答進行評論。因此我發佈了一個新的問題答案。

對於大矩陣的每一列,檢查最大值是否等於最小值就足夠了。

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

這是測試。與第一個答案相比,超過90%的時間減少了。它也比第二個評論對這個問題的答案還要快。

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

我reran,發現它使用全部(x == x [1],na.rm = TRUE)快15%左右,而不是計算最大和最小值。 – DavidR 2017-05-23 14:09:50

+0

位置(函數(x)!is.na(x),x)給出第一個非na元素的索引位置,如果x有一些na值,則花費更多的時間。 – raymkchow 2017-05-23 14:38:21

1

由於這種問答& A是一個受歡迎的谷歌的搜索結果,但答案是一個大的矩陣有點慢,@raymkchow版本與港定居慢我使用指數搜索和data.table功率提出了一個新的版本。

這是我在dataPreparation包中實現的一個函數。

首先建立一個爲例data.table,具有比列多行(這通常是這種情況)和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) 

然後基準的10%的所有的方法:

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 

結果如下:

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比o快10倍其他方法。

加上更多的行,你有更多的使用intersting。