Funções de tempo em R [fechado]


36
  1. Eu gostaria de medir o tempo que leva para repetir a execução de uma função. São replicate()e usando loops for equivalentes? Por exemplo:

    system.time(replicate(1000, f()));
    system.time(for(i in 1:1000){f()});
    

    Qual é o método preferido?

  2. Na saída de system.time(), é sys+usero tempo real da CPU para executar o programa? É elapseduma boa medida do desempenho do tempo do programa?


3
Apenas para constar, já que estou claramente muito atrasado para mudar o curso dessa pergunta: esse é o tipo de problema que eu acho mais adequado para o StackOverflow.
Matt Parker

2
@ Matt Concordo que as perguntas sobre como um programa é adequado para SO. Concordo também que uma interpretação literal desta questão (conforme tomada por várias das respostas) a colocaria fora do tópico aqui no CV. Parece haver algum interesse estatístico em projetar um experimento de tempo e em analisar os resultados de tal experimento.
whuber

Respostas:


19

Para um cronograma eficaz dos programas, especialmente quando você estiver interessado em comparar soluções alternativas, você precisa de um controle! Uma boa maneira é colocar o procedimento que você está cronometrando em uma função. Chame a função dentro de um loop de temporização. Escreva um procedimento stub, basicamente retirando todo o código da sua função e retornando (mas deixe todos os argumentos). Coloque o esboço no seu loop de tempo e volte a cronometrar. Isso mede toda a sobrecarga associada ao tempo. Subtraia o tempo do stub do tempo do procedimento para obter a rede: essa deve ser uma medida precisa do tempo real necessário.

Como a maioria dos sistemas hoje em dia pode ser interrompida peremptoriamente, é importante executar várias execuções de tempo para verificar a variabilidade. Em vez de executar uma longa execução de segundos, faça m execuções de cerca de N / mNmN/m segundos cada. Isso ajuda a fazer isso em um loop duplo de uma só vez. Não só é mais fácil de manusear, como também introduz um pouco de correlação negativa em cada série temporal, o que realmente melhora as estimativas.

Ao usar esses princípios básicos do design experimental, você controla essencialmente quaisquer diferenças devido à maneira como implanta o código (por exemplo, a diferença entre um loop for e replicate ()). Isso faz o seu problema desaparecer.


25

Em relação aos seus dois pontos:

  1. É estilístico. Eu gosto replicate(), pois é funcional.
  2. Eu tendem a me concentrar elapsed, ou seja, o terceiro número.

O que costumo fazer é

N <- someNumber
mean(replicate( N, system.time( f(...) )[3], trimmed=0.05) )

para obter uma média aparada de 90% de N repetições de chamada f().

(Editado, com agradecimentos a Hadley por pegar um thinko.)


2
Você não quer dizer mean(replicate(N, system.time(f(...))[3]), trim = 0.05)?
Hadley

2
Se a chamada f () for longa, tudo bem. No entanto, se a chamada f () for curta, qualquer sobrecarga de chamada de tempo provavelmente aumentará a medição de erros. Com uma única chamada para system.time () ao longo de muitas repetições de f (), é possível dividir o erro da chamada até que ele tenha algum valor infinitesimal (e ele retorna mais rápido).
John

@ John: Obrigado, mas eu não entendo o que você disse. Ainda estou me perguntando o que é melhor, repetindo f () dentro ou fora system.time ()?
Tim

Toda chamada para o comando system.time () possui um tempo variável necessário para causar uma certa quantidade de erro de medição. Esta é uma pequena quantidade. Mas e se f () for uma ligação muito breve? Em seguida, esse erro pode ser confundido com o tempo necessário para chamar f (). Portanto, quando você chama f () 1e5 vezes em um único system.time (), o erro é dividido em partes 1e5. Quando você chama system.time () para cada f (), seu impacto pode ser significativo se o tempo para f () for pequeno. Obviamente, se tudo o que você precisa é de tempo relativo, não importa muito.
John

Ah, e a segunda parte é que seria mais rápido chamar system.call () uma vez.
John

10

Você também pode cronometrar com timesteps retornados por Sys.time; é claro que isso mede o tempo da parede, então o tempo de computação em tempo real. Código de exemplo:

Sys.time()->start;
replicate(N,doMeasuredComputation());
print(Sys.time()-start);

3

Quanto à métrica de tempo a ser usada, não posso adicionar aos outros respondedores.

Em relação à função a ser usada, eu gosto de usar o benchmark? Do pacote rbenchmark .


1

Eles fazem coisas diferentes. Cronometre o que você deseja fazer. replicate () retorna um vetor de resultados de cada execução da função. O loop for não. Portanto, não são declarações equivalentes.

Além disso, cronometre várias maneiras pelas quais você deseja que algo seja feito. Então você pode encontrar o método mais eficiente.


mod-tip: poste a segunda parte como um comentário na resposta do Dirk.
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.