2

当我试图理解函数中的函数是如何在 R 中定义和传递时,我必须承认自己完全疯了。这些例子总是假设你理解每一个细微差别,并且没有提供过程的描述。我还没有遇到一个简单的英语,白痴指南分解过程。所以第一个问题是你知道一个吗?

现在我的身体问题。
我有一个 data.frames 列表:fileData。
我想在每个 data.frame 中的特定列上使用 rollapply() 函数。然后我希望将所有结果(列表)结合起来。因此,以使用内置 mtcars 数据帧为例的 data.frames 之一开始:

当然,我需要告诉 rollapply() 使用函数 PPI() 以及作为列的相关参数。

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

我试过这个:

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

并停在

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

我认为这与 Zoo 使用矩阵有关,但其他许多尝试都无法解决 rollapply 问题。所以继续我认为的下一步:

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

似乎有一英里远。一些指导和解决方案将非常受欢迎。
谢谢。

4

3 回答 3

2

我将尽力帮助您并展示如何调试问题。在 R 中非常有用的一个技巧是学习如何调试。我正在使用browser函数。

问题 :

在这里,我f通过添加一行来更改您的功能:

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

现在当你运行时:

rollapply(df, 1, f)

调试器停止,您可以检查参数 x 的值:

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

如您所见,这是一个标量值,因此您不能$在其上应用运算符,因此会出现错误:

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

一般指南

现在我将解释你应该如何做到这一点。

  • 要么你改变你的 PPI 函数,有一个参数excees:所以你做它之外的减法(更容易)
  • 或者你mapply用来得到一个通用的解决方案。(更难但更通用且非常有用)
  • 避免$在函数内使用。就个人而言,我只在 R 控制台上使用它。

完整的解决方案:

我假设你 data.frames(zoo objects) 有 changeFactor_A 和 changeFactor_B 列。

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

或更一般地说:

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

在哪里

   get_excess <- 
     function(data,colA,colB){
          ### do whatever you want here
          ### return a vector
          excess
     }
于 2014-06-04T06:56:53.930 回答
1

查看帮助页面的“使用”部分以?rollapply. 我承认 R 帮助页面不容易解析,我明白你是如何感到困惑的。

问题是rollapply可以处理ts,zoo或一般numeric向量,但只能处理单个系列。您正在为它提供一个带有两个参数的函数,asset并且benchmark. 当然,您的fPPI可以很容易地被矢量化,但rollapply根本不是为此而设计的。

解决方案:计算你的excess外部rollapplyexcess很容易矢量计算,它不涉及任何滚动计算),然后rollapply你的函数才对它:

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

您可能对 感兴趣,它为多个mapply参数向量化一个函数,类似于和朋友,它适用于单个参数。但是,我不知道滚动窗户的类似物。applymapply

于 2014-06-04T06:56:58.830 回答
1

我大汗淋漓,花了一些时间慢慢理解如何分解使用另一个函数的参数调用一个函数的过程和协议。一个很好的帮助网站是 来自唯一的 Hadley Wickham 的Advanced R ,再次!显示过程分解的图片接近理想。尽管我仍然需要考虑一些细节。

这是一个带注释的完整示例。希望其他人觉得它有用。

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)

结果:

> 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
于 2014-06-06T02:37:18.540 回答