【问题标题】:How to calculate the weighted value without loop?如何在没有循环的情况下计算加权值?
【发布时间】:2013-11-02 13:20:47
【问题描述】:

很抱歉问了些琐碎的问题。这是我的示例数据:

(x <- data.frame(period=c('20130101','20130102'),symbol=c('x1','x2'),V1=c(1,2),V2=c(3,4)))
(y <- data.frame(period=c('20130101','20130101','20130102','20130102'),
            symbol=rep(c('V1','V2'),2),w1=rep(c(0.5,0.5),2),w2=rep(c(0.3,0.7),2),
            w3=rep(c(0.2,0.8),2) ) )

对于给定的日期和符号,表“x”中有两个值(V1,V2)。

    period symbol V1   V2
1 20130101   x1    1   3
2 20130102   x2    2   4

对于给定的一天,每个值 (V1, V2) 具有三组权重 (w1, w2, w3)。

    period symbol  w1  w2  w3
1 20130101   V1   0.5 0.3 0.2
2 20130101   V2   0.5 0.7 0.8
3 20130102   V1   0.5 0.3 0.2
4 20130102   V2   0.5 0.7 0.8

如何通过两个表不循环计算加权值?**例如在'20130101'中,'x1'的V1和V2分别为1和3。然后在表'y'中搜索日期'20130101'和V1和V2,我们得到3组权重。加权值计算为:

    wv1=1*0.5 + 3*0.5=2
    wv2=1*0.3 + 3*0.7=2.4
    wv3=1*0.2 + 3*0.8=2.6

结果表如下:

    period symbol  wv1  wv2   wv3
1 20130101   x1    2    2.4   2.6
...

【问题讨论】:

    标签: r lapply sapply mapply


    【解决方案1】:

    这是一种方法:

    cbind(x[,1:2],Reduce(`+`,lapply(split(y,y$symbol),
      function(z) x[,as.character(z$symbol[1])]*z[,3:5])))
    ##     period symbol w1  w2  w3
    ## 1 20130101     x1  2 2.4 2.6
    ## 3 20130102     x2  3 3.4 3.6
    

    这可以根据您想要的解决方案的通用性进行扩展。例如,如果您不能假设x 和y 按句点排序并一对一匹配,那么您需要先调用match:

    ysplit<-lapply(split(y,y$symbol),function(z) z[match(x$period,z$period),])
    vals<-Reduce(`+`,lapply(ysplit,function(z) x[,as.character(z$symbol[1])]*z[,3:5]))
    cbind(x[,1:2],vals)
    

    如果您想正确获取行名和列名:

    cbind(x[,1:2],setNames(vals,c("wv1","wv2","wv3")),row.names=row.names(x))
    ##     period symbol wv1 wv2 wv3
    ## 1 20130101     x1   2 2.4 2.6
    ## 2 20130102     x2   3 3.4 3.6
    

    如果您想要一个采用任意数量权重的通用解决方案,您可以通过一些小的更改来适应它:

    y$w4<-c(0.1,0.9,0.1,0.9)
    ysplit<-lapply(split(y,y$symbol),function(z) z[match(x$period,z$period),])
    
    vals<-Reduce(`+`,lapply(ysplit,function(z)
          x[,as.character(z$symbol[1])]*z[,substring(names(z),1,1)=="w"]))
    cbind(x[,1:2],setNames(vals,paste0("wv",1:ncol(vals))),row.names=row.names(x))
    
    ##     period symbol wv1 wv2 wv3 wv4
    ## 1 20130101     x1   2 2.4 2.6 2.8
    ## 2 20130102     x2   3 3.4 3.6 3.8
    

    【讨论】:

    • 非常感谢。这非常有帮助。
    【解决方案2】:

    一种使用mapply的方式(假设你只有V1和V2和V1列是第一个):

    #function to apply multiple arguments
    fun <- function(period., symbol., V1., V2.) 
    {
     row1. <- y$period == as.numeric(as.character(period.)) & y$symbol == "V1"
     row2. <- y$period == as.numeric(as.character(period.)) & y$symbol == "V2"
    
     res <- y[row1.,c("w1", "w2", "w3")] * V1. + y[row2.,c("w1", "w2", "w3")] * V2.
    
     ret <- c(period = as.numeric(as.character(period.)), 
                symbol = as.character(symbol.), 
                   setNames(res, c("wv1", "wv2", "wv3")))
     return(ret)
    }
    
    do.call(rbind, mapply(fun, x$period, x$symbol, x$V1, x$V2, SIMPLIFY = F))
    #     period   symbol wv1 wv2 wv3
    #[1,] 20130101 "x1"   2   2.4 2.6
    #[2,] 20130102 "x2"   3   3.4 3.6
    

    【讨论】:

      【解决方案3】:
      One way: 
      l<-reshape(y,idvar="period",timevar="symbol",direction="wide")
      > l
          period w1.V1 w2.V1 w3.V1 w1.V2 w2.V2 w3.V2
      1 20130101   0.5   0.3   0.2   0.5   0.7   0.8
      3 20130102   0.5   0.3   0.2   0.5   0.7   0.8
      
      nn<-merge(l,x,by="period")
      > nn
          period w1.V1 w2.V1 w3.V1 w1.V2 w2.V2 w3.V2 symbol V1 V2
      1 20130101   0.5   0.3   0.2   0.5   0.7   0.8     x1  1  3
      2 20130102   0.5   0.3   0.2   0.5   0.7   0.8     x2  2  4
      
      
      nn$wv1<-with(nn,w1.V1*V1+w1.V2*V2)
      nn$wv2<-with(nn,w2.V1*V1+w2.V2*V2)
       nn$wv3<-with(nn,w3.V1*V1+w3.V2*V2)
      
       nn
          period w1.V1 w2.V1 w3.V1 w1.V2 w2.V2 w3.V2 symbol V1 V2 wv1 wv2 wv3
      1 20130101   0.5   0.3   0.2   0.5   0.7   0.8     x1  1  3   2 2.4 2.6
      2 20130102   0.5   0.3   0.2   0.5   0.7   0.8     x2  2  4   3 3.4 3.6
      
      
      
         nn[,c(1,8,11:13)]
          period symbol wv1 wv2 wv3
      1 20130101     x1   2 2.4 2.6
      2 20130102     x2   3 3.4 3.6
      

      【讨论】:

        猜你喜欢
        • 2021-01-29
        • 1970-01-01
        • 2013-02-07
        • 1970-01-01
        • 2019-02-21
        • 2016-10-31
        • 1970-01-01
        • 2015-12-02
        • 2020-07-25
        相关资源
        最近更新 更多