Pergunta

Devo admitir que sou uma loucura completa ao tentar entender como funções dentro de funções são definidas e passadas em R.Os exemplos sempre presumem que você entende todas as nuances e não fornecem descrições do processo.Ainda não encontrei um guia idiota em inglês simples que descreva o processo.Então a primeira pergunta é: você conhece algum?

Agora meu problema físico.
Eu tenho uma lista de data.frames:arquivoData.
Quero usar a função rollapply() em colunas específicas em cada data.frame.Quero então todos os resultados (listas) combinados.Então, começando com um dos data.frames usando os dataframes mtcars integrados como exemplo:

É claro que preciso dizer ao rollapply() para usar a função PPI() junto com os parâmetros associados que são as colunas.

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

Eu tentei isso:

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

e foi parado em

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

Acho que isso está relacionado ao uso de matrizes pelo Zoo, mas outras inúmeras tentativas não conseguiram resolver o problema do rollapply.Então, passando para o que acredito ser o próximo:

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

Parece a um quilômetro de distância.Algumas orientações e soluções seriam muito bem-vindas.
Obrigado.

Foi útil?

Solução 3

Eu suei muito e levei algum tempo para entender lentamente como quebrar o processo e o protocolo de chamada de uma função com argumentos de outra função.Um ótimo site que ajudou foi R avançado do único Hadley Wickham, de novo!As imagens que mostram a análise do processo são quase ideais.Embora eu ainda precisasse pensar em alguns detalhes.

Aqui está um exemplo completo com notas.Espero que alguém ache isso ú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

Outras dicas

Tentarei ajudá-lo e mostrar como você pode depurar o problema.Um truque que é muito útil em R é aprender como depurar.Gnerelly estou usando browser função.

problema :

Aqui estou eu mudando sua função f adicionando uma linha:

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

Agora, quando você executar:

rollapply(df, 1, f)

O depurador para e você pode inspecionar o valor do argumento x:

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

como você vê é um valor escalar, então você não pode aplicar o $ operador nele, daí você recebe o erro:

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

guias gerais

Agora vou explicar como você deve fazer isso.

  • Ou você altera sua função PPI, para ter um único parâmetro excees:então você faz a subtração fora dele (mais fácil)
  • Ou você usa mapply para obter uma solução generalizada.(Mais difícil, mas mais geral e muito útil)
  • Evite usar $ dentro das funções.Pessoalmente, eu uso apenas no console R.

solução completa:

Presumo que você data.frames (objetos zoológicos) tenha colunas changeFactor_A e changeFactor_B.

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

Ou de forma mais geral:

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

Onde

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

Consulte a seção "Uso" da página de ajuda para ?rollapply.Admito que as páginas de ajuda do R não são fáceis de analisar e vejo como você ficou confuso.

O problema é que rollapply pode lidar com ts, zoo ou geral numeric vetores, mas apenas uma única série.Você está alimentando-o com uma função que leva dois argumentos, asset e benchmark.Concedido, seu f e PPI pode ser trivialmente vetorizado, mas rollapply simplesmente não foi feito para isso.

Solução:calcule o seu excess fora rollapply (excess é facilmente calculado vetorialmente e não envolve nenhum cálculo contínuo), e só então rollapply sua função para ele:

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

Você pode estar interessado em mapply, que vetoriza uma função para múltiplo argumentos, da mesma forma que apply e amigos, que trabalham solteiro argumentos.No entanto, não conheço nenhum análogo de mapply com rolando janelas.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top