2014-02-14 32 views
1

我读过这篇文章http://www.r-bloggers.com/comparing-hist-and-cut-r-functions/和测试hist()要比我的电脑上的cut()快4倍。我的脚本通过cut()多次循环,因此节省时间非常重要。因此,我尝试切换到更快的功能,但难以获得按照cut()的确切输出。使用speedier hist()或findInterval()获取与cut()相同的输出?

从以下示例代码:

data <- rnorm(10, mean=0, sd=1) #generate data 
my_breaks <- seq(-6, 6, by=1) #create a vector that specifies my break points 
cut(data, breaks=my_breaks) 

我希望得到包含数据的每个元素被分配给使用我的断点水平的矢量,即cut确切输出:

[1] (1,2] (-1,0] (0,1] (1,2] (0,1] (-1,0] (-1,0] (0,1] (-2,-1] (0,1] 
Levels: (-6,-5] (-5,-4] (-4,-3] (-3,-2] (-2,-1] (-1,0] (0,1] (1,2] (2,3] (3,4] (4,5] (5,6] 
> 

我的问题:如何使用hist()输出的元素(即中断,计数,密度,中等等)或findInterval达到我的目的?

另外,我发现https://stackoverflow.com/questions/12379128/r-switch-statement-on-comparisons使用findInterval的例子,但这需要我事先创建间隔标签,这不是我想要的。

任何帮助,将不胜感激。提前致谢!

+3

我很抱歉,但我不明白的前提。 'hist'和'cut'做了完全不同的事情。 'hist'计算每个bin中的频率,并且“cut”将相应的bin分配给每个值。前者比后者快,这并不奇怪。 – Roland

+0

投票搁置,因为这个问题目前毫无意义。 –

+0

Hi @Roland,在'cut()'的R帮助中,hist()被认为更有效率:_var(table,cut(x,br)),hist(x,br,plot = FALSE)高效率和更少的内存饥饿。所以我想:因为他们在'相同的呼吸'中被提及,'hist()'真的可以作为'cut()'的替代品,这可以加速我的代码。 – NoviceProg

回答

5

这是基于你findInterval建议的实现比传统cut快5-6倍:

cut2 <- function(x, breaks) { 
    labels <- paste0("(", breaks[-length(breaks)], ",", breaks[-1L], "]") 
    return(factor(labels[findInterval(x, breaks)], levels=labels)) 
} 

library(microbenchmark) 

set.seed(1) 
data <- rnorm(1e4, mean=0, sd=1) 

microbenchmark(cut.default(data, my_breaks), cut2(data, my_breaks)) 

# Unit: microseconds 
#       expr  min  lq median  uq  max neval 
# cut.default(data, my_breaks) 3011.932 3031.1705 3046.5245 3075.3085 4119.147 100 
#  cut2(data, my_breaks) 453.761 459.8045 464.0755 469.4605 1462.020 100 

identical(cut(data, my_breaks), cut2(data, my_breaks)) 
# TRUE 
+0

+1您应该对'cut.default'进行基准测试。 – Roland

+0

@罗兰你是对的,编辑。 – sgibb

+0

虽然S3方法的调度时间只对较短的向量很重要。 – Roland

4

hist函数以与tablecut的组合类似的方式创建按分箱计数。例如,

set.seed(1) 
x <- rnorm(100) 

hist(x, plot = FALSE) 
## $breaks 
## [1] -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 
## 
## $counts 
## [1] 1 3 7 14 21 20 19 9 4 2 

table(cut(x, seq.int(-2.5, 2.5, 0.5))) 
## (-2.5,-2] (-2,-1.5] (-1.5,-1] (-1,-0.5] (-0.5,0] (0,0.5] (0.5,1] 
##   1   3   7  14  21  20  19 
## (1,1.5] (1.5,2] (2,2.5] 
##   9   4   2 

如果你想从cut原始输出的,你不能使用hist。但是,如果cut的速度是一个问题(并且您可能要仔细检查确实是分析的缓慢部分;请参阅premature optimization is the root of all evil),那么您可以使用较低级别的.bincode。这忽略了cut的输入检查和标签创建功能。

.bincode(x, seq.int(-2.5, 2.5, 0.5)) 
## [1] 4 6 4 9 6 4 6 7 7 5 9 6 ... 
+0

感谢您的建议。在执行sgibb中更快的'cut'之后,速度的提高并没有我希望的那么大。看起来像瓶颈不是'剪切'毕竟(叹息...现在回到绘图板...) – NoviceProg

+1

@NoviceProg你应该剖析你的代码。见'help(“Rprof”)'。 – Roland

+2

用于'.bincode'和链接! – A5C1D2H2I1M1N2O1R2T1

相关问题