从data.frame中快速删除零方差变量

Zac*_*ach 23 r data-management

我有一个由我的控制之外的进程生成的大型data.frame,它可能包含也可能不包含方差为零的变量(即所有观察结果都相同).我想基于这些数据建立一个预测模型,显然这些变量是没用的.

这是我目前用来从data.frame中删除这些变量的函数.它目前基于apply,我想知道是否有任何明显的方法来加速这个功能,以便它可以在非常大的数据集上快速工作,具有大量(400或500)变量?

set.seed(1)
dat <- data.frame(
    A=factor(rep("X",10),levels=c('X','Y')),
    B=round(runif(10)*10),
    C=rep(10,10),
    D=c(rep(10,9),1),
    E=factor(rep("A",10)),
    F=factor(rep(c("I","J"),5)),
    G=c(rep(10,9),NA)
)
zeroVar <- function(data, useNA = 'ifany') {
    out <- apply(data, 2, function(x) {length(table(x, useNA = useNA))})
    which(out==1)
}
Run Code Online (Sandbox Code Playgroud)

以下是该过程的结果:

> dat
   A B  C  D E F  G
1  X 3 10 10 A I 10
2  X 4 10 10 A J 10
3  X 6 10 10 A I 10
4  X 9 10 10 A J 10
5  X 2 10 10 A I 10
6  X 9 10 10 A J 10
7  X 9 10 10 A I 10
8  X 7 10 10 A J 10
9  X 6 10 10 A I 10
10 X 1 10  1 A J NA

> dat[,-zeroVar(dat)]
   B  D F  G
1  3 10 I 10
2  4 10 J 10
3  6 10 I 10
4  9 10 J 10
5  2 10 I 10
6  9 10 J 10
7  9 10 I 10
8  7 10 J 10
9  6 10 I 10
10 1  1 J NA

> dat[,-zeroVar(dat, useNA = 'no')]
   B  D F
1  3 10 I
2  4 10 J
3  6 10 I
4  9 10 J
5  2 10 I
6  9 10 J
7  9 10 I
8  7 10 J
9  6 10 I
10 1  1 J
Run Code Online (Sandbox Code Playgroud)

top*_*epo 23

您可能还想查看nearZeroVar()插入符包中的函数.

如果您有1000个中的一个事件,则丢弃这些数据可能是个好主意(但这取决于模型).nearZeroVar()可以做到这一点.


Rei*_*son 18

不要使用table()- 这类事情很慢.一种选择是length(unique(x)):

foo <- function(dat) {
    out <- lapply(dat, function(x) length(unique(x)))
    want <- which(!out > 1)
    unlist(want)
}

system.time(replicate(1000, zeroVar(dat)))
system.time(replicate(1000, foo(dat)))
Run Code Online (Sandbox Code Playgroud)

在给出类似输出的同时,这比示例数据集上的数量级更快:

> system.time(replicate(1000, zeroVar(dat)))
   user  system elapsed 
  3.334   0.000   3.335 
> system.time(replicate(1000, foo(dat)))
   user  system elapsed 
  0.324   0.000   0.324
Run Code Online (Sandbox Code Playgroud)

在这个例子中,Simon的解决方案同样很快:

> system.time(replicate(1000, which(!unlist(lapply(dat, 
+             function(x) 0 == var(if (is.factor(x)) as.integer(x) else x))))))
   user  system elapsed 
  0.392   0.000   0.395
Run Code Online (Sandbox Code Playgroud)

但你必须看看它们是否与实际问题规模相似.


Sim*_*nek 11

简单地不使用table- 它在数字向量上非常慢,因为它将它们转换为字符串.我可能会使用类似的东西

var0 <- unlist(lapply(df, function(x) 0 == var(if (is.factor(x)) as.integer(x) else x)))
Run Code Online (Sandbox Code Playgroud)

对于具有NA和非零方差的列,它将是TRUE0- 方差NAFALSE


小智 5

使用Caret包和函数nearZeroVar

require(caret)
NZV<- nearZeroVar(dataset, saveMetrics = TRUE)
NZV[NZV[,"zeroVar"] > 0, ] 
NZV[NZV[,"zeroVar"] + NZV[,"nzv"] > 0, ]
Run Code Online (Sandbox Code Playgroud)