【问题标题】:rollapply function on specific column of dataframes within list列表中特定数据框列的rollapply函数
【发布时间】:2014-06-04 05:48:43
【问题描述】:

当我试图理解函数中的函数是如何在 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 ......

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

【问题讨论】:

  • 只是想让你知道你不是唯一一个认为 R 有(太)高学习曲线的人,如果你没有很多经验,很多事情是无法理解的编程,或者有大量经验的人来帮助你。
  • +1 @Soccerman 的评论。 R 很难学。也就是说,如果你能提供一个 reproducible 的例子会很有帮助,见这里:stackoverflow.com/questions/5963269/…
  • @StephanKolassa 我通常会尝试添加一个我现在已经完成的示例。帮助描述该过程也会有所帮助,而不仅仅是一个答案。干杯。

标签: r list dataframe lapply rollapply


【解决方案1】:

我会尽力帮助您并展示如何调试问题。在 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
     }

【讨论】:

  • 这看起来是正确的方向。我通过 Revolution R 拥有一个完整的 IDE 调试器,但调试肯定可以改进。感谢您的浏览提示。您的最后一项可能会回答我的第二部分,但我无法更改 PPI 函数(它比减法更复杂),所以我的第一个问题仍然存在;如何使用需要参数的函数调用 rollapply()。您会注意到我更改了问题以提供更好的示例,这就是数据框现在具有不同名称的原因。)
  • 谢谢@agstudy。我已经使用您的示例开始并混合了一些可以在不过多分解现有框架的情况下工作的东西。一个问题,如果你不在高级函数中使用 $,你如何告诉它在哪些元素上执行任务?
  • @LookLeft by element 你的意思是列?我不确定你的意思是什么,但dat$col1 等同于dat[,"col1"]
  • 是的,我的意思是专栏。啊,我看到你不使用 $ 的细微差别。使用更严格的列引用形式。这有助于我即将发布的最终答案。干杯。
【解决方案2】:

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

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

解决方案:在rollapply之外计算你的excessexcess很容易矢量计算,并且不涉及任何滚动计算),然后rollapply你的函数就可以了:

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

您可能对mapply 感兴趣,它对多个 参数的函数进行矢量化,类似于apply 和朋友,它们可以处理单个 参数。但是,我不知道带有 滚动 窗口的 mapply 的类似物。

【讨论】:

  • 感谢@StephanKolassa,但这仅有助于解释 rollapply() 的简单用法,我可以使用示例开始工作。如何在我概述的问题中使用它?即被一个函数“调用”和“调用”一个函数;所有参数都被传递。实际的 PPI 函数操作与此问题无关。这只是一个简单的示例函数来演示问题。
  • 请注意,rollapply 可以使用 by.column=FALSE 参数处理多变量系列。
  • @LookLeft:在一些 R 教科书中查看“匿名函数”的覆盖范围可能会有所帮助,例如R 编程的艺术 中的第 7.13 节。 R Inferno 只提到了两次,但它的第 5.1 节可能很有用(虽然不容易阅读)。
【解决方案3】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-28
    • 2021-09-06
    • 2017-03-01
    • 2020-11-14
    • 1970-01-01
    • 1970-01-01
    • 2013-09-01
    • 1970-01-01
    相关资源
    最近更新 更多