如何在R中对这个过程进行矢量化?

时间:2013-06-21 22:09:45

标签: r vectorization nested-loops

如何在不使用太多循环的情况下在R中对此过程进行矢量化?

我有这个功能:

HM=function(CO,CS,CD,CSD){
  if(CO-CS)>1){
    return(2^(CS)/(2^(CO)-2^(CSD)))
  }
  else if(CO-CD)>1){
    return(1-2^(CD)/(2^(CO)-2^(CSD)))
  }
return(0)
}

基本上我需要获得{CO,CS,CD,CSD}的每个组合的HM值超过thoses值:

CO  25.76031685 25.71126747 25.90163231
CS  24.40528297 24.09929848 23.51999092
CD  25.99405861 25.72906113 25.61374474
CSD 35.94195557 36.07263184 34.00024414

所以我需要获得这些价值观:

HM(25.76031685,24.40528297,25.99405861,35.94195557)
HM(25.71126747,24.40528297,25.99405861,35.94195557)
HM(25.90163231,24.40528297,25.99405861,35.94195557)
HM(25.76031685,24.09929848,25.99405861,35.94195557)
HM(25.71126747,24.09929848,25.99405861,35.94195557)
HM(25.90163231,24.09929848,25.99405861,35.94195557)
HM(25.76031685,23.51999092,25.99405861,35.94195557)
HM(25.71126747,23.51999092,25.99405861,35.94195557)
HM(25.90163231,23.51999092,25.99405861,35.94195557)
etc...

基本上它是4个元素的4个向量的所有组合:

Vectors :
a=c(1,2,3)
b=c(1,2,3)
c=c(1,2,3)
d=c(1,2,3)

Combinations :
1,1,1,1
2,1,1,1
1,2,1,1
1,1,2,1
1,1,1,2
3,1,1,1
1,3,1,1
etc...

我不确定如何计算组合数量。当然我可以使用4个嵌套循环,但我想学习如何使用矢量化,因为R对于循环来说太慢了。我想我们可以使用expand.grid但我不知道怎么做。此表也是excel,我可以将其导出为.csv,但我不确定实现这些内容的最佳方式,谢谢你的帮助!

2 个答案:

答案 0 :(得分:1)

在这种情况下,答案是无趣的,因为没有条件适用于这些值,并返回所有零:

> tdat  #  dataframe version of that data.
         CO       CS       CD      CSD
V2 25.76032 24.40528 25.99406 35.94196
V3 25.71127 24.09930 25.72906 36.07263
V4 25.90163 23.51999 25.61374 34.00024
> with( tdat, 
       ifelse( (CS-CO) > 1, 2^(CS)/(2^(CO)-2^(CSD)),  #1st consequent
                 ifelse ( (CD-CO) > 1, 1-2^(CD)/(2^(CO)-2^(CSD)), # 2nd
                                           0) ) )  # default
[1] 0 0 0

要在数据的矩阵版本上执行此操作,您需要首先更正代码中不匹配的parens,然后在引用单个传递x值并使用rownames时使用apply:

mdat <- 
structure(c(25.76032, 24.40528, 25.99406, 35.94196, 25.71127, 
24.0993, 25.72906, 36.07263, 25.90163, 23.51999, 25.61374, 34.00024
), .Dim = c(4L, 3L), .Dimnames = list(c("CO", "CS", "CD", "CSD"
), NULL))

> apply(mdat, 2, function(x){
+   if( (x['CS']-x['CO'])>1){
+     return(2^(x['CS'])/(2^(x['CO'])-2^(x['CSD'])))
+   }
+   else if( (x['CD']-x['CO'])>1){
+     return(1-2^(x['CD'])/(2^(x['CO'])-2^(x['CSD'])))
+   }
+ return(0)
+ })
[1] 0 0 0

答案 1 :(得分:1)

您可以使用expand.grid获取所有组合。但是,首先需要使用HM代替ifelse 向量化您的函数if

HM2 <- function(CO,CS,CD,CSD)
{
    den <- 2^CO-2^CSD

    ifelse(CO-CS>1, 2^CS/den,
        ifelse(CO-CD>1, 1-2^CD/den, 0))
}

请注意,den对两个结果都是通用的。

现在您的数据:

CO <- c(25.76031685, 25.71126747, 25.90163231)
CS <- c(24.40528297, 24.09929848, 23.51999092)
CD <- c(25.99405861, 25.72906113, 25.61374474)
CSD <- c(35.94195557, 36.07263184, 34.00024414)

组合:

cmbs <- expand.grid(CO, CS, CD, CSD)
names(cmbs) <- c("CO", "CS", "CD", "CSD")

示例:

> head(cmbs)
        CO       CS       CD      CSD
1 25.76032 24.40528 25.99406 35.94196
2 25.71127 24.40528 25.99406 35.94196
3 25.90163 24.40528 25.99406 35.94196
4 25.76032 24.09930 25.99406 35.94196
5 25.71127 24.09930 25.99406 35.94196
6 25.90163 24.09930 25.99406 35.94196

可以使用within获得最终结果,以在数据框内执行计算:

result <- within(cmbs, HM <- HM2(CO, CS, CD, CSD))

示例:

> head(result)
        CO       CS       CD      CSD            HM
1 25.76032 24.40528 25.99406 35.94196 -0.0003368911
2 25.71127 24.40528 25.99406 35.94196 -0.0003368814
3 25.90163 24.40528 25.99406 35.94196 -0.0003369210
4 25.76032 24.09930 25.99406 35.94196 -0.0002725079
5 25.71127 24.09930 25.99406 35.94196 -0.0002725000
6 25.90163 24.09930 25.99406 35.94196 -0.0002725321