gpt4 book ai didi

r - 优化列表函数以避免 R 中的循环

转载 作者:行者123 更新时间:2023-12-02 18:21:55 26 4
gpt4 key购买 nike

我正在使用 R 中的大量值。我需要对列表的每个元素应用一些函数。我使用的列表是 i1 并由以下代码生成:

i1=list(0)
i1[1:120000]=runif(120000,min = 10000,max = 100000)

i1中,我必须应用一些函数才能使用列表中的每个值作为输入来获取新的数据帧。接下来的函数是:f_1 通过使用某些条件,使用 i1 中的每个值作为输入来计算新值。在此函数中,我使用了一些条件来获取值。该功能如下:

f_1=function(x)
{
y=ifelse((x/18)>20,x-(x/18),ifelse(x>20,x-20,ifelse(x==0,0,x)))
return(y)
}

第二个函数是f_2。该函数使用 f_1 作为输入,它由一个 for 结构组成,其中有 160 次迭代。在此函数中创建一个空向量。然后,通过应用 f_1 函数来增长向量。 f_2 的最终结果是一个数据帧,其中包含 for 结构中生成的所有元素。该功能如下:

f_2=function(v)
{
x=c()
y=v
x[1]=y
for(i in 2:160)
{
x[i]=f_1(x[i-1])
}
x=x[!duplicated(x)]
x=c(x,0)
z=as.data.frame(t(abs(diff(x))))
return(z)
}

最后,要将 f_1f_2 应用于 i1,我使用包 plyr 来应用将功能添加到列表中。我为该事件构建了这个函数:

compute=function(x)
{
y=f_2(x)
return(y)
}

通过使用compute,我可以将函数应用于列表中的所有元素。我使用此代码:

L2=llply(i1,compute)

一切工作正常,但需要很长时间才能产生最终结果:

system.time(llply(i1,compute))
user system elapsed
436.71 0.92 447.70

我认为这个过程太慢的原因与函数f_2有关,因为它内部使用了循环。我已经寻找了一些想法来避免这种结构,但我不清楚如何更改 f_2 以提高效率。请问您能提供一些解决此问题的指导吗?我了解函数,但在本例中,我在函数内部使用了 for 来创建我想要的结果。

感谢您的帮助!

最佳答案

您的代码存在几个问题。例如,您犯了在循环中增长对象的经典错误。

但是,如果您对代码的性能不满意,则应该开始对其进行分析:

Rprof()
L2=llply(i1,compute)
Rprof(NULL)
summaryRprof()$by.self
# self.time self.pct total.time total.pct
#"ifelse" 3.38 35.58 4.06 42.74
#"f_2" 2.28 24.00 9.48 99.79
#"f_1" 1.46 15.37 5.52 58.11
#"as.vector" 0.86 9.05 0.86 9.05
#"as.data.frame.matrix" 0.32 3.37 1.44 15.16
#"paste0" 0.20 2.11 0.22 2.32
#"is.na" 0.20 2.11 0.20 2.11
#</snip>

您会看到大部分时间都花在 ifelseas.vectoras.data.frame.matrix 上。 as.vector 的调用位置不太明显[1],但其他两个很明显。

使用 ifelse 代替 ifelse 可以获得稍微更好的性能,但没有多大帮助。我会使用 Rcpp 将 f1f2 中的 for 循环转换为编译代码(使用 RStudio 非常简单)。显然你需要工具链,即安装 Rtools在 Windows 上。

#include <Rcpp.h>
using namespace Rcpp;

double f1 (const double x) {
if((x/18)>20) return x-(x/18);
if(x>20) return x-20;
if(x==0) return 0;
return x;
}

// [[Rcpp::export]]
NumericVector f2_1 (const double init, const int n){
NumericVector res(n);
res(0) = init;
for (int i=1; i<n; i++) res(i) = f1(res(i-1));
return res;
}

这比提出矢量化纯 R 解决方案(假设存在)要快。

我们可以将 f2 的其余部分定义为:

f_2a=function(v)
{
x = f2_1(v, 160)
x=x[!duplicated(x)]
x=c(x,0)
z=abs(diff(x))
return(z)
}

请注意我是如何省略 tas.data.frame 的,因为如果性能很重要,则应避免使用 data.frames。它们的设计更多的是为了方便而不是为了性能。向量可以存储单行全数字 data.frame 的等效信息,但我无法想象返回单行 data.frame 列表的好理由。

现在我们调用该函数:

L2a = lapply(i1, f_2a)

让我们测试一下结果是否相等:

all.equal(L2[[1]], as.data.frame(t(L2a[[1]])))
#[1] TRUE

现在比较时间:

system.time(llply(i1,compute))
# user system elapsed
#13.91 0.00 13.93

system.time(lapply(i1, f_2a))
#user system elapsed
#0.26 0.00 0.27
<小时/>

[1] 它在 as.data.frame.matrix 中的循环中调用,将矩阵拆分为列向量列表。

关于r - 优化列表函数以避免 R 中的循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36369123/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com