Pregunta

Debo admitir que estoy completamente loco cuando intento entender cómo se definen y pasan funciones dentro de funciones en R.Los ejemplos siempre suponen que comprende todos los matices y no proporcionan descripciones del proceso.Todavía tengo que encontrar una guía para idiotas en inglés sencillo que desglose el proceso.Entonces la primera pregunta es ¿conoces alguno?

Ahora mi problema físico.
Tengo una lista de marcos de datos:archivoDatos.
Quiero usar la función rollapply() en columnas específicas en cada marco de datos.Luego quiero que se combinen todos los resultados (listas).Entonces, comenzando con uno de los data.frames usando los dataframes mtcars integrados como ejemplo:

Por supuesto, necesito decirle a rollapply() que use la función PPI() junto con los parámetros asociados que son las columnas.

PPI <- function(a, b){  
    value = (a + b)  
    PPI = sum(value)  
    return(PPI)  
}

Probé esto:

f <- function(x) PPI(x$mpg, x$disp)
fileData<- list(mtcars, mtcars, mtcars)
df <- fileData[[1]]

y se detuvo en

rollapply(df, 20, f)
Error in x$mpg : $ operator is invalid for atomic vectors  

Creo que esto está relacionado con el uso de matrices por parte de Zoo, pero otros numerosos intentos no pudieron resolver el problema de rollapply.Entonces pasemos a lo que creo que es lo siguiente:

lapply(fileData, function(x) rollapply ......

Parece a una milla de distancia.Serían bienvenidas algunas orientaciones y soluciones.
Gracias.

¿Fue útil?

Solución 3

Me sudé y me tomé un tiempo para entender lentamente cómo romper el proceso y el protocolo de llamar a una función con argumentos de otra función.Un gran sitio que ayudó fue avanzado r de¡El único y único Hadley Wickham, de nuevo!Las imágenes que muestran el desglose del proceso están cerca de Ideal.Aunque todavía necesitaba mi gorra de pensamiento para algunos detalles.

Aquí hay un ejemplo completo con notas.Esperemos que alguien más lo encuentre útil.

library(zoo)

#Create a list of dataframes for the example.
listOfDataFrames<- list(mtcars, mtcars, mtcars)
#Give each element a name.
names(listOfDataFrames) <- c("A", "B", "C")

#This is a simple function just for the example!
#I want to perform this function on column 'col' of matrix 'm'.
#Of course to make the whole task worthwhile, this function is usually something more complex.
fApplyFunction <- function(m,col){
    mean(m[,col])
}

#This function is called from lapply() and does 'something' to the dataframe that is passed.
#I created this function to keep lapply() very simply.
#The something is to apply the function fApplyFunction(), wich requires an argument 'thisCol'. 
fOnEachElement <- function(thisDF, thisCol){
    #Convert to matrix for zoo library.
    thisMatrix <- as.matrix(thisDF)
    rollapply(thisMatrix, 5, fApplyFunction, thisCol, partial = FALSE, by.column = FALSE)
}

#This is where the program really starts!
#
#Apply a function to each element of list.
#The list is 'fileData', with each element being a dataframe.
#The function to apply to each element is 'fOnEachElement'
#The additional argument for 'fOnEachElement' is "vs", which is the name of the column I want the function performed on.
#lapply() returns each result as an element of a list.
listResults <- lapply(listOfDataFrames, fOnEachElement, "vs")


#Combine all elements of the list into one dataframe.
combinedResults <- do.call(cbind, listResults)

#Now that I understand the argument passing, I could call rollapply() directly from lapply()...
#Note that ONLY the additional arguments of rollapply() are passed. The primary argurment is passed automatically by lapply().
listResults2 <- lapply(listOfDataFrames, rollapply, 5, fApplyFunction, "vs", partial = FALSE, by.column = FALSE)

Resultados:

> combinedResults
        A   B   C
 [1,] 0.4 0.4 0.4
 [2,] 0.6 0.6 0.6
 [3,] 0.6 0.6 0.6
 [4,] 0.6 0.6 0.6
 [5,] 0.6 0.6 0.6
 [6,] 0.8 0.8 0.8
 [7,] 0.8 0.8 0.8
 [8,] 0.8 0.8 0.8
 [9,] 0.6 0.6 0.6
[10,] 0.4 0.4 0.4
[11,] 0.2 0.2 0.2
[12,] 0.0 0.0 0.0
[13,] 0.0 0.0 0.0
[14,] 0.2 0.2 0.2
[15,] 0.4 0.4 0.4
[16,] 0.6 0.6 0.6
[17,] 0.8 0.8 0.8
[18,] 0.8 0.8 0.8
[19,] 0.6 0.6 0.6
[20,] 0.4 0.4 0.4
[21,] 0.2 0.2 0.2
[22,] 0.2 0.2 0.2
[23,] 0.2 0.2 0.2
[24,] 0.4 0.4 0.4
[25,] 0.4 0.4 0.4
[26,] 0.4 0.4 0.4
[27,] 0.2 0.2 0.2
[28,] 0.4 0.4 0.4
> listResults
$A
 [1] 0.4 0.6 0.6 0.6 0.6 0.8 0.8 0.8 0.6 0.4 0.2 0.0 0.0 0.2 0.4 0.6 0.8 0.8 0.6
[20] 0.4 0.2 0.2 0.2 0.4 0.4 0.4 0.2 0.4

$B
 [1] 0.4 0.6 0.6 0.6 0.6 0.8 0.8 0.8 0.6 0.4 0.2 0.0 0.0 0.2 0.4 0.6 0.8 0.8 0.6
[20] 0.4 0.2 0.2 0.2 0.4 0.4 0.4 0.2 0.4

$C
 [1] 0.4 0.6 0.6 0.6 0.6 0.8 0.8 0.8 0.6 0.4 0.2 0.0 0.0 0.2 0.4 0.6 0.8 0.8 0.6
[20] 0.4 0.2 0.2 0.2 0.4 0.4 0.4 0.2 0.4

> listResults2
$A
 [1] 0.4 0.6 0.6 0.6 0.6 0.8 0.8 0.8 0.6 0.4 0.2 0.0 0.0 0.2 0.4 0.6 0.8 0.8 0.6
[20] 0.4 0.2 0.2 0.2 0.4 0.4 0.4 0.2 0.4

$B
 [1] 0.4 0.6 0.6 0.6 0.6 0.8 0.8 0.8 0.6 0.4 0.2 0.0 0.0 0.2 0.4 0.6 0.8 0.8 0.6
[20] 0.4 0.2 0.2 0.2 0.4 0.4 0.4 0.2 0.4

$C
 [1] 0.4 0.6 0.6 0.6 0.6 0.8 0.8 0.8 0.6 0.4 0.2 0.0 0.0 0.2 0.4 0.6 0.8 0.8 0.6
[20] 0.4 0.2 0.2 0.2 0.4 0.4 0.4 0.2 0.4

Otros consejos

Intentaré ayudarte y mostrarte cómo puedes solucionar el problema.Un truco que resulta muy útil en R es aprender a depurar.Generalmente estoy usando browser función.

problema :

Aquí estoy cambiando tu función. f agregando una línea:

f <- function(x) {
  browser()
  PPI(x$changeFactor_A, x$changeFactor_B)
}

Ahora cuando ejecutas:

rollapply(df, 1, f)

El depurador se detiene y puedes inspeccionar el valor del argumento x:

Browse[1]> x
 [1,] 
1e+05 

como ves es un valor escalar, por lo que no puedes aplicar el $ operador en él, por lo tanto obtienes el error:

Error in x$changeFactor_A : $ operator is invalid for atomic vectors 

guías generales

Ahora te explicaré cómo debes hacer esto.

  • O cambia su función PPI para tener un solo parámetro excees:entonces haces la resta fuera de él (más fácil)
  • O usas mapply para obtener una solución generalizada.(Más difícil pero más general y muy útil)
  • Evitar el uso de $ dentro de las funciones.Personalmente, lo uso sólo en la consola R.

solución completa:

Supongo que sus data.frames (objetos del zoológico) tienen columnas changeFactor_A y changeFactor_B.

sapply(fileData,function(dat){
  dat <- transform(dat,excess= changeFactor_A-changeFactor_B)
  rollapply(dat[,'excess'],2,sum)
}

O más generalmente:

sapply(fileData,function(dat){
  excess <- get_excess(dat,'changeFactor_A','changeFactor_B')
  rollapply(excess,2,sum)
}

Dónde

   get_excess <- 
     function(data,colA,colB){
          ### do whatever you want here
          ### return a vector
          excess
     }

Mire la sección "Uso" de la página de ayuda para ?rollapply.Admito que las páginas de ayuda de R no son fáciles de analizar y veo que te confundiste.

El problema es ese rollapply puede lidiar con ts, zoo o generales numeric vectores, pero solo una serie.Le estás alimentando con una función que toma dos argumentos, asset y benchmark.De acuerdo, tu f y PPI puede trivialmente ser vectorizado, pero rollapply simplemente no está hecho para eso.

Solución:calcula tu excess afuera rollapply (excess se calcula fácilmente vectorialmente y no implica ningún cálculo continuo), y sólo entonces rollapply tu función para ello:

> mtcars$excess <- mtcars$mpg-mtcars$disp
> rollapply(mtcars$excess, 3, sum)
 [1]  -363.2  -460.8  -663.1  -784.8  -893.9 ...

Posiblemente te interese mapply, que vectoriza una función para múltiple argumentos, al igual que apply y amigos, que trabajan en soltero argumentos.Sin embargo, no conozco ningún análogo de mapply con laminación ventanas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top