funzione rollapply su una colonna specifica di dataframe all'interno dell'elenco
Domanda
Devo ammettere di essere completamente pazzo quando cerco di capire come le funzioni all'interno delle funzioni vengono definite e passate in R.Gli esempi presuppongono sempre che tu comprenda ogni sfumatura e non forniscono descrizioni del processo.Devo ancora imbattermi in una guida in inglese semplice e idiota che spiega il processo.Quindi la prima domanda è: ne conosci uno?
Adesso il mio problema fisico.
Ho un elenco di data.frames:fileData.
Voglio utilizzare la funzione rollapply() su colonne specifiche in ciascun data.frame.Voglio quindi che tutti i risultati (elenchi) siano combinati.Quindi, iniziando con uno dei data.frames utilizzando i dataframe mtcars integrati come esempio:
Ovviamente devo dire a rollapply() di utilizzare la funzione PPI() insieme ai parametri associati che sono le colonne.
PPI <- function(a, b){
value = (a + b)
PPI = sum(value)
return(PPI)
}
Ho provato questo:
f <- function(x) PPI(x$mpg, x$disp)
fileData<- list(mtcars, mtcars, mtcars)
df <- fileData[[1]]
e mi sono fermato
rollapply(df, 20, f)
Error in x$mpg : $ operator is invalid for atomic vectors
Penso che questo sia correlato allo Zoo che utilizza le matrici, ma altri numerosi tentativi non sono riusciti a risolvere il problema del rollapply.Quindi passiamo a ciò che credo sia il prossimo:
lapply(fileData, function(x) rollapply ......
Sembra un miglio di distanza.Alcune indicazioni e soluzioni sarebbero molto gradite.
Grazie.
Soluzione 3
Ho sudato via e ho impiegato un po 'di tempo per capire lentamente come abbattere il processo e il protocollo di chiamare una funzione con argomenti da un'altra funzione.Un ottimo sito che ha aiutato era avanzato r daL'unico e unico Hadley Wickham, di nuovo!Le immagini che mostrano la rottura del processo sono vicine all'ideale.Anche se avevo ancora bisogno del mio tappo di pensiero per alcuni dettagli.
Ecco un esempio completo con le note.Speriamo che qualcun altro lo trovi utile.
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)
.
Risultati:
> 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
. Altri suggerimenti
Proverò ad aiutarti e mostrare come puoi eseguire il debug del problema. Un trucco che è molto utile in r è quello di imparare come eseguire il debug. Greelly sto usando la funzione browser
.
Problema:
Qui sto cambiando per funzionare f
aggiungendo una riga:
f <- function(x) {
browser()
PPI(x$changeFactor_A, x$changeFactor_B)
}
.
Ora quando corri:
rollapply(df, 1, f)
.
Il debugger si arresta e puoi ispezionare il valore dell'argomento X:
Browse[1]> x
[1,]
1e+05
.
Come vedi è un valore scalare, quindi non è possibile applicare l'operatore $
su di esso, quindi ottieni l'errore:
Error in x$changeFactor_A : $ operator is invalid for atomic vectors
.
Guide generali
Ora spiegherò come dovresti farlo.
- .
- O si modifica la funzione PPI, per avere un singolo parametro
excees
: in modo da fare la sottrazione al di fuori di esso (più facile) - o si utilizza
mapply
per ottenere una soluzione generalizzata. (Più difficile ma più generale e molto utile) - Evita di utilizzare
$
all'interno delle funzioni. Personalmente, lo uso solo sulla console r.
Soluzione completa:
Suppongo che tu sia dati. I fotogrammi (Zoo Objects) hanno ChangeFactor_A e ChangeFactor_b colonne.
sapply(fileData,function(dat){
dat <- transform(dat,excess= changeFactor_A-changeFactor_B)
rollapply(dat[,'excess'],2,sum)
}
.
o più Generalmente:
sapply(fileData,function(dat){
excess <- get_excess(dat,'changeFactor_A','changeFactor_B')
rollapply(excess,2,sum)
}
.
dove
get_excess <-
function(data,colA,colB){
### do whatever you want here
### return a vector
excess
}
. Consulta la sezione "Utilizzo" della pagina della guida ?rollapply
.Devo ammettere che le pagine della guida di R non sono facili da analizzare e vedo come ti sei confuso.
Il problema è che rollapply
può affrontare ts
, zoo
o generale numeric
vettori, ma solo una singola serie.Gli stai alimentando una funzione che richiede due argomenti, asset
E benchmark
.Certo, il tuo f
E PPI
può essere banalmente vettorizzato, ma rollapply
semplicemente non è fatto per quello.
Soluzione:calcola il tuo excess
al di fuori rollapply
(excess
è facilmente calcolato vettorialmente e non comporta alcun calcolo rolling), e solo allora rollapply
la tua funzione:
> mtcars$excess <- mtcars$mpg-mtcars$disp
> rollapply(mtcars$excess, 3, sum)
[1] -363.2 -460.8 -663.1 -784.8 -893.9 ...
Potrebbe interessarti mapply
, che vettorizza una funzione per multiplo argomenti, in modo simile a apply
e amici, su cui lavorare separare argomenti.Tuttavia, non conosco alcun analogo di mapply
con rotolamento finestre.