【问题标题】:How to vectorize this process in R?如何在 R 中向量化这个过程?
【发布时间】:2013-06-21 22:09:44
【问题描述】:

如何在不使用太多循环的情况下在 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 值:

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...

基本上都是3个元素的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,但我不确定实现这些东西的最佳方法,所以感谢您的帮助!

【问题讨论】:

    标签: r vectorization nested-loops


    【解决方案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可以得到最终结果,在dataframe内部进行计算:

    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
    

    【讨论】:

    • 太棒了,我在这个晚上得出了同样的结论。谢谢 !但是,当我向 HM() 添加第三个 ifelse() 时,它不再起作用了,你知道为什么吗? stackoverflow.com/questions/17252466/…
    • @Wicelo,看起来你已经明白了。问题是&amp;&amp;。 Roland 的回答非常好,采用完全矢量化的方法。再见!
    【解决方案2】:

    在这种情况下,答案相当无趣,因为这些值的条件都不成立,并且返回全零:

    > 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
    

    要在该数据的矩阵版本上执行此操作,您需要首先更正代码中不匹配的括号,然后在引用带有行名的单个传递的 x 值时使用 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
    

    【讨论】:

    • 感谢您的回复!但是我不明白这个列表 {3,3,3,3} 可能有 3^4 组合,那么为什么只有 3 个返回?顺便说一句,你是对的,我犯了一个错误,条件是 CO-CS|CD 而不是相反。
    • 实际上不是 3^4,我不知道如何计算,但我添加了一些我需要的 HM 值示例。
    • 叹息。它可能会涉及expand grid,但如果没有示例,我认为继续这个猜谜游戏没有多大意义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-04
    • 1970-01-01
    • 2018-12-08
    • 2021-09-02
    • 2013-03-12
    • 2020-01-10
    相关资源
    最近更新 更多