Pergunta

Estou criando tabelas de proporções baseadas em um objeto xts.Como isso faz parte de um programa grande que (infelizmente) requer cerca de 10 ^ 6 loops, cria um grande gargalo e eu gostaria de acelerá-lo.

Este é um exemplo do que comecei:

library(quantmod)

test.xts <- xts(sample(seq(1,5, by=.5), 50, replace=T), as.Date(1:50))

system.time(for(i in 1:10000){

  prop.table(table(test.xts))

})

>user  system elapsed 
 19.86    0.00   18.58 

Já mudei o xts para uma matriz e isso resultou em um aumento significativo de velocidade.Menciono apenas que é originalmente um xts caso esteja faltando alguma coisa no xts que aceleraria isso além dos ganhos que já vi ao convertê-lo para uma matriz.

test.mat <- as.matrix(test.xts)

system.time(for(i in 1:10000){

  prop.table(table(test.mat))

})

>user  system elapsed 
 2.78    0.00    2.90 

Mas eu realmente gostaria que fosse o mais rápido possível, então espero que outras pessoas tenham sugestões para melhorias futuras.Espero que haja uma abordagem óbvia que estou ignorando.

Uma informação adicional é que a saída dessas tabelas é finalmente mesclada com uma saída semelhante de um período de tempo diferente, portanto, as dimensões precisam permanecer nomeadas.(Ou seja, preciso ser capaz de combinar a proporção de um valor '10' no tempo 1 com a proporção de '10' no tempo 2).

Qualquer ajuda é muito apreciada.

Foi útil?

Solução

table() cria implicitamente um fator que é caro.No seu caso você pode economizar muito (mais de 10x) usando tabulate() já que você já tem números inteiros:

a <- tabulate(test.mat)
names(a) <- seq_along(a)
a / sum(a)
   1    2    3    4    5    6    7    8    9   10 
0.16 0.14 0.08 0.14 0.08 0.16 0.02 0.06 0.10 0.06 

horários:

system.time(for(i in 1:10000){
  a <- tabulate(test.mat)
  names(a) <- seq_along(a)
  a/sum(a)
})

 user  system elapsed 
0.208   0.002   0.210 

seu tempo para comparação:

system.time(for(i in 1:10000) prop.table(table(test.mat)))
 user  system elapsed 
3.373   0.028   3.402 

Outras dicas

PARA desenvolver o comentário de Joran, usando tabulate() diretamente pode ser mais rápido.Ele tem três peculiaridades dignas de nota:

  1. Ele lida apenas com números inteiros e trunca decimais.
  2. Ele ignora silenciosamente todos os valores negativos e zeros.
  3. Ele cria um compartimento para todos os valores 1:n, mesmo se houver contagens zero

Ver ?tabulate para detalhes.

Com essa ressalva, aqui está uma função que proporciona uma aceleração de aproximadamente 9x:

prop2 <- function(x){
  x <- tabulate(x)
  out <- x/sum(x)
  names(out) <- seq_along(out)
  return(out)
}

Teste de velocidade:

library(rbenchmark)
test.mat <- as.matrix(test.xts)
f1 <- function() prop.table(table(test.mat))
benchmark(f1(), prop2(test.mat),
           replications = 1000,
           columns = c("test", "relative", "elapsed"),
           order = "relative")
#------
             test relative elapsed
2 prop2(test.mat)      1.0    0.10
1            f1()      9.1    0.91

Confirme que a saída é a mesma:

> prop.table(table(test.mat))
test.mat
   1    2    3    4    5    6    7    8    9   10 
0.04 0.02 0.20 0.12 0.08 0.10 0.06 0.14 0.12 0.12 
> prop2(test.mat)
   1    2    3    4    5    6    7    8    9   10 
0.04 0.02 0.20 0.12 0.08 0.10 0.06 0.14 0.12 0.12
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top