【问题标题】:R plyr applied on rowR plyr 应用于行
【发布时间】:2012-08-21 08:07:48
【问题描述】:

我有一个这样的数据框:

    mat.in=data.frame(site=c('A','A','A','B','B','B'),
    var=c('product.A','product.B','energy','product.A','product.B','energy'),
    year.2011=c(12,10,40,14,12,60),year.2012=c(13,11,45,25,13,65))

对于每个“站点”,我想除以“能量”[numcol wise],所以我会得到:

    mat.out=data.frame(site=c('A','A','A','B','B','B'),
    var=c('product.A','product.B','energy','product.A','product.B','energy'),
    year.2011=c(12,10,40,14,12,60),year.2012=c(13,11,45,25,13,65),
    quot.2011=c(0.30,0.25,1.00,0.23,0.20,1.00),quot.2012=c(0.29,0.24,1.00,0.38,0.20,1.00))

这将非常适合来自包 plyr 的 ddply 以及该包的 numcolwise。 但不知何故,我无法做到这一点 - 问题是要挑选出“能量”成分。

有人知道如何解决这个问题吗? [提前谢谢...]

【问题讨论】:

    标签: r plyr data.table


    【解决方案1】:

    @seancarmody 的酷回答。

    这是使用基函数的另一种方法:

    # Select and join frames
    mat.out<-merge(mat.in[grep("product", mat.in$var),], mat2 <- mat.in[mat.in$var=="energy",], "site")
    # Calculate the quot values
    mat.out$quot.2011=mat.out$year.2011.x/mat.out$year.2011.y
    mat.out$quot.2012=mat.out$year.2012.x/mat.out$year.2012.y
    
    # And if needs be you can remove the energy columns
    mat.out[,-c(5,6,7)]
    

    这是一种使用sqldf的方法:

    variable<-'p.site,p.var,p.year_2011,p.year_2012,
               p.year_2011/e.year_2011 AS quot_2011,
               p.year_2012/e.year_2012 AS quot_2012'
    tables<- '(SELECT *
               FROM    `mat.in`
               WHERE   var LIKE \"product%\"
               )
               AS p,
               (SELECT *
               FROM    `mat.in`
               WHERE   var LIKE \"energy\"
               )
               AS e'
    
    fn$sqldf("SELECT $variable FROM $tables WHERE  p.site=e.site")
    

    这是一种使用data.table的方法:

    dt <- data.table(mat.in, key="site")
    # Join
    mat.out <- dt[var %like% "product"][dt[var=="energy"]]
    # Calculate
    mat.out <- mat.out[,quot.2011:=year.2011/year.2011.1]
    mat.out <- mat.out[,quot.2012:=year.2012/year.2012.1]
    

    马修编辑:

    在此基础上,使用加入继承范围,一种更高级(更快)的data.table 方式:

    dt <- data.table(mat.in, key="site")
    dt[dt[var=="energy"],quot.2011:=year.2011/i.year.2011]
    dt[dt[var=="energy"],quot.2012:=year.2012/i.year.2012]
    

    注意i. 前缀,它告诉它从i 而不是x 获取该变量。类似于 SQL 表名前缀。这避免了大的merge 步骤; FAQ 1.12 中描述的技术。

    j中的多个:=被实现时,会变成:

    dt <- data.table(mat.in, key="site")
    dt[dt[var=="energy"], { quot.2011:=year.2011/i.year.2011
                            quot.2012:=year.2012/i.year.2012 } ]
    

    【讨论】:

    • 感谢肖恩和罗洛。我无法让融化版本工作 [var == "energy" 中的错误:比较 (1) 仅适用于原子和列表类型",但第一个选项有效。
    • 你在使用reshape2吗?哪个版本的 R?我刚刚又试了一遍代码,没有出错。
    • 嗨,肖恩和罗洛——我的错;它适用于此页面上的代码,但不适用于我的 [更大] 数据集。找不到它是什么。我仔细按照步骤操作,检查了 str(mydata) 等。
    • var 列中的值可能有误?大桌子上的summary(mat.in$var)class(mat.in$var) 告诉你什么?
    • 嗨,Rolo,摘要(mat.in$var 给出:长度类模式 211806 字符字符。类 mat.in$var 给出“字符”。我注意到每个“年”的值的 nr 是不一样,例如 2008 = 264709 和 2009 = 264701,这可能是原因吗?在 #!Linux 上使用 R 2.14 64 位,reshape2。
    【解决方案2】:

    这将在您的示例中完成工作:

    library(plyr)
    ddply(mat.in, .(site), transform, quote.2011 = year.2011/year.2011[var=="energy"],      
          quote.2012 = year.2012/year.2012[var=="energy"])
    

    为了更一般地执行此操作,我首先将数据melt 将年份转换为值而不是列名。

    这是melt 的工作方式

    library(reshape2)
    mat.m <- melt(mat.in, id.vars=1:2, variable.name="year")
    mat.m$year <- sub("year.", "", mat.m$year)
    mat.out <- ddply(mat.m, .(site, year), transform, quote = value/value[var=="energy"])
    

    【讨论】:

    • 谢谢肖恩,它有效!我也用你的融化建议试过了,但是得到'二进制运算符的非数字参数'。
    【解决方案3】:

    只使用基函数:

    mat.r <- reshape(mat.in, direction="long", varying=3:4)
     # Could not figure out how to get the divisor "lined up" unless db-normalized
    matd <- as.data.frame(lapply( split(mat.r, list(mat.r[,1], mat.r[,3]) ), 
                                  FUN=function(x) x$year/x$year[x$var=="energy"]) )
    
    #----------------
    matd
      A.2011    B.2011    A.2012    B.2012
    1   0.30 0.2333333 0.2888889 0.3846154
    2   0.25 0.2000000 0.2444444 0.2000000
    3   1.00 1.0000000 1.0000000 1.0000000
    
     reshape(matd, direction="long", varying=list(1:2, 3:4))[2:3]
           A.2011    A.2012
    1.1 0.3000000 0.2888889
    2.1 0.2500000 0.2444444
    3.1 1.0000000 1.0000000
    1.2 0.2333333 0.3846154
    2.2 0.2000000 0.2000000
    3.2 1.0000000 1.0000000
    
     mat.out <- cbind(mat.in, reshape(matd, direction="long", varying=list(1:2, 3:4))[2:3])
     mat.out
     #------------------    
        site       var year.2011 year.2012    A.2011    A.2012
    1.1    A product.A        12        13 0.3000000 0.2888889
    2.1    A product.B        10        11 0.2500000 0.2444444
    3.1    A    energy        40        45 1.0000000 1.0000000
    1.2    B product.A        14        25 0.2333333 0.3846154
    2.2    B product.B        12        13 0.2000000 0.2000000
    3.2    B    energy        60        65 1.0000000 1.0000000
    

    【讨论】:

    • 感谢 DWin。现在唯一缺少的解决方案是通过 [fast] data.table 包。
    • 添加了 data.table(虽然不一定是最佳的使用方式)。
    猜你喜欢
    • 2014-01-30
    • 2012-07-02
    • 1970-01-01
    • 2014-01-15
    • 2018-09-05
    • 1970-01-01
    • 2012-05-04
    • 2012-05-14
    • 1970-01-01
    相关资源
    最近更新 更多