我有一个相当大的数据集(约250k行和400个cols @ .5gb),其中许多列是单值的(即它们只有一个值)。要从数据集中删除这些列,我使用data[, apply(data, 2, function(x) length(unique(x)) != 1)]
,它可以正常工作。我想知道是否有更有效的方法可以做到这一点?这在我的电脑上需要:
> system.time(apply(data, 2, function(x) length(unique(x))))
# user system elapsed
# 34.37 0.71 35.15
对于一个数据集来说这不是很糟糕,但我想在不同的数据集上重复多次。
答案 0 :(得分:1)
您可以改为使用lapply
:
data[, unlist(lapply(data, function(x) length(unique(x)) > 1L))]
请注意,我添加了unlist
将结果列表转换为TRUE / FALSE值的向量,该值将用于子集化。
编辑:这是一个小基准:
library(benchmark)
a <- runif(1e4)
b <- 99
c <- sample(LETTERS, 1e4, TRUE)
df <- data.frame(a,b,c,a,b,c,a,b,c,a,b,c,a,b,c,a,b,c,a,b,c,a,b,c,a,b,c)
microbenchmark(
apply = {df[, apply(df, 2, function(x) length(unique(x)) != 1)]},
lapply = {df[, unlist(lapply(df, function(x) length(unique(x)) > 1L))]},
unit = "relative",
times = 100)
#Unit: relative
# expr min lq median uq max neval
#apply 41.29383 40.06719 39.72256 39.16569 28.54078 100
#lapply 1.00000 1.00000 1.00000 1.00000 1.00000 100
请注意,apply
将首先将data.frame转换为矩阵,然后执行效率较低的操作。因此,在您使用data.frame
的大多数情况下,您可以(并且应该)避免使用apply
并使用例如而是lapply
。
答案 1 :(得分:1)
您也可以尝试:
set.seed(40)
df <- as.data.frame(matrix(sample(letters[1:3], 3*10,replace=TRUE), ncol=10))
Filter(function(x) (length(unique(x))>1), df)
或者
df[,colSums(df[-1,]==df[-nrow(df),])!=(nrow(df)-1)] #still better than `apply`
还包括速度比较(@ beginneR的样本数据)
microbenchmark(
new ={Filter(function(x) (length(unique(x))>1), df)},
new1={df[,colSums(df[-1,]==df[-nrow(df),])!=(nrow(df)-1)]},
apply = {df[, apply(df, 2, function(x) length(unique(x)) != 1)]},
lapply = {df[, unlist(lapply(df, function(x) length(unique(x)) > 1L))]},
unit = "relative",
times = 100)
# Unit: relative
# expr min lq median uq max neval
# new 1.0000000 1.0000000 1.000000 1.0000000 1.000000 100
# new1 4.3741503 4.5144133 4.063634 3.9591345 1.713178 100
# apply 23.9635826 24.0895813 21.361140 20.7650416 5.757233 100
#lapply 0.9991514 0.9979483 1.002005 0.9958308 1.002603 100