2012-02-28 10 views
5

Primero, esta pregunta no se trata de tratar de resolver un problema específico. Como recién llegado a R, también estoy trabajando para crear códigos más eficientes y procedimientos de creación de códigos. Obtener perspectivas sobre diferentes métodos de programación e incluso estilos es la razón detrás de esta pregunta.Proceso de creación de código y funciones incrustadas

A continuación se presentan tres maneras de codificar algo:

primer Estos son los datos ejemplo:

stackexample <- c(52,50,45,49.5,50.5,12,10,14,11.5,12,110,108,106,101,104) 
dim(stackexample)<- c(5,3) 

Método uno: ¿Las matemáticas en la función sin definir ningún objeto

ertimesIVCV1 <- function (x) 
{ (solve(var(log((x[-nrow(x),])/(x[-1,])))))%*% 
    ((1+(log(x[1,]/(x)[nrow(x),])))^(1/nrow(x))-1)} 

ertimesIVCV1(stackexample) 

Método dos: defina objetos en la función y luego manipule esos objetos

ertimesIVCV2 <- function (x) 
{ IVCV <- solve(var(log((x[-nrow(x),])/(x[-1,])))); 
    retsexcess <- (1+(log(x[1,]/(x)[nrow(x),])))^(1/nrow(x))-1; 
    IVCV%*%retsexcess} 

ertimesIVCV2(stackexample) 

Método Tres: Definir varias funciones y llamar a esas funciones en el "Resumen como" función

IVCV <- function (x) {solve(var(log((x[-nrow(x),])/(x[-1,]))))} 
retsexcess <- function(x) (1+(log(x[1,]/(x)[nrow(x),])))^(1/nrow(x))-1 
ertimesIVCV3 <- function (x) {IVCV(x)%*%retsexcess(x)} 

ertimesIVCV3(stackexample) 

Así que producir la misma respuesta:

  [,1] 
[1,] 1.4430104 
[2,] -0.1365155 
[3,] 11.8088378 

pero como se puede ver tres enfoques diferentes.

¿Existe una cantidad óptima de funciones incrustadas o deberíamos siempre intentar enumerar explícitamente todas las operaciones matemáticas? ¿Cuántos niveles de funciones dentro de las funciones es óptimo? ¿Es el método superior en velocidad computacional? ¿Hay una regla general para esto? ¿Cómo te acercas a esto? ¡Cualquier comentario o sugerencia o enlace sería bienvenido y gracias!

Rye

+1

Consulte http://stackoverflow.com/q/4406873/210673, especialmente la respuesta de @GavinSimpson. – Aaron

Respuesta

6

En mi humilde opinión, la eficiencia de la velocidad debe ser el último de sus preocupaciones al escribir el código, especialmente si usted es un principiante. En cambio, su enfoque principal debe ser la simplicidad, la legibilidad y la modularidad.No me malinterprete, la eficiencia es una gran cosa, y encontrará muchas formas de hacer que su código sea más rápido cuando sea necesario, pero no debería ser una prioridad en sí mismo.

Así que voy a dar consejos sobre el estilo en su mayoría. Para ilustrar, aquí está cómo se vería mi versión de tu código. Tenga en cuenta que no sé cuál es su código de computación, así que hice todo lo posible para tratar de romperlo con nombres de variables significativos.

IVCV <- function(stack) { 

## This function computes [...] IVCV stands for [...] 
## Inputs: 
## - stack: a matrix where each column [...] 
## Output: a matrix [...] 

    n <- nrow(stack) # stack size 
    stack.ratios <- stack[-n, ]/stack[-1, ] 
    log.ratios <- log(stack.ratios) 
    ivcv   <- solve(var(log.ratios)) 

    return(ivcv) 
} 

ExcessReturn <- function(stack) { 

## This function computes [...] IVCV stands for [...] 
## Inputs: 
## - stack: a matrix where each column [...] 
## Output: a matrix [...] 

    n <- nrow(stack) # stack size 
    total.ratio <- stack[1, ]/stack[n, ] 
    excess.return <- (1 + log(total.ratio))^(1/n) - 1 

    return(excess.return) 
} 

ExcessReturnTimesIVCV <- function(stack) { 

## This function computes [...] IVCV stands for [...] 
## Inputs: 
## - stack: a matrix where each column [...] 
## Output: a vector [...] 

    return(IVCV(stack) %*% ExcessReturn(stack)) 
} 

1) sí, divida su código en pequeñas funciones. Es mejor para legibilidad, flexibilidad y mantenimiento. También facilita las pruebas unitarias, donde puede diseñar pruebas para cada pieza de código elemental.

2) documentar una función incluyendo comentarios sobre su descripción/entradas/salida dentro del cuerpo de la función. De esta forma, después de crear la función, el usuario puede ver su descripción como parte de la impresión de la función (por ejemplo, simplemente escriba ExcessReturnTimesIVCV en la GUI).

3) separar la complejidad en varias declaraciones. En este momento, todas sus tres sugerencias son difíciles de entender, con demasiadas cosas sucediendo en cada línea. Una declaración debería hacer algo simple para que pueda leerse fácilmente. Es poco probable que la creación de más objetos ralentice el proceso y facilitará la depuración.

4) los nombres de sus objetos son clave para hacer que su código sea claro. Elija bien y use una sintaxis consistente. Uso UpperCamelCase para los nombres de mis propias funciones y palabras minúsculas separadas con puntos para la mayoría de los otros objetos.

5) poner comentarios, especialmente cuando 3) y 4) no son suficientes para aclarar el código. En mi ejemplo, elegí usar una variable n. Fui en contra de la recomendación de que los nombres de variables deberían ser descriptivos, pero era para hacer el código un poco más claro y darles a las expresiones como stack[-n, ]/stack[-1, ] una buena simetría. Dado que n es un nombre incorrecto, puse un comentario explicando su significado. También podría haber puesto más comentarios en el código si supiera lo que realmente están haciendo las funciones.

6) Use reglas de sintaxis consistentes, principalmente para mejorar la legibilidad. Escuchará opiniones diferentes sobre lo que se debe usar aquí. En general, no hay un mejor enfoque. Lo más importante es tomar una decisión y aferrarse a ella. Así que aquí están mis sugerencias:

a) una declaración por línea, no semi colons.

b) espaciado y sangría consistentes (sin pestañas). Pongo espacios después de comas, alrededor de operadores binarios. También uso espacio extra para alinear cosas si ayuda a la legibilidad.

c) refuerzo consistente: tenga cuidado de la forma en que está utilizando llaves para definir bloques, de lo contrario es probable que tenga problemas en el modo de secuencia de comandos. Consulte la Sección 8.1.43 del R Inferno (una gran referencia)

¡Buena suerte!

6

Si el objetivo es la eficiencia de tiempo, entonces la respuesta con los ejemplos que se ofrecen es "a quién le importa?". La sobrecarga de las llamadas a funciones no es lo que determina la eficiencia. Probablemente debería centrarse en otros problemas, como la comprensión del usuario y la capacidad de mantener el código.

require(rbenchmark) 
benchmark(replications=100, ver1= ertimesIVCV1(stackexample), 
ver2=ertimesIVCV2(stackexample), 
ver3 = ertimesIVCV3(stackexample)) 
# ------------------ 
    test replications elapsed relative user.self sys.self user.child sys.child 
1 ver1   100 0.030 1.000000  0.03  0   0   0 
2 ver2   100 0.030 1.000000  0.03  0   0   0 
3 ver3   100 0.031 1.033333  0.03  0   0   0 
4

No estoy de acuerdo con DWin (aunque en realidad no, solo estoy dando un giro diferente). Si el objetivo es su tiempo-eficiencia, entonces tenemos algunos casos. Si estás haciendo algo una vez, entonces estoy de acuerdo con "¿a quién le importa?". Haz lo que quieras/lo que pienses en el momento, probablemente el método 1 o 2.

La ventaja del Método 3 es la repetibilidad. Si está escribiendo el mismo código más de un par de veces, su eficiencia ha disminuido. Póngalo en una función y guárdese usted mismo escribiendo y especialmente la posibilidad de escribir mal. Veo que ya está hablando de poner cosas en una función, pero ¿su función IVCV sería útil como utilidad o para otras funciones? Si no, no te molestes con eso.

Cuanto más grande se vuelve un proyecto, mejor se convierte en romperlo en piezas que obtienen su propia función. Esto puede hacer que la organización, la depuración y la modificación funcionen mucho mejor.

Cuestiones relacionadas