2

我有一个这样的数据框:

    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 。但不知何故,我做错了——问题是要挑出“能量”成分。

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

4

3 回答 3

5

来自@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 中描述的技术。

当multiple :=inj被实现时,它会变成:

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 } ]
于 2012-08-21T09:20:00.900 回答
4

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

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"])
于 2012-08-21T08:57:50.010 回答
0

仅使用基本功能:

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
于 2012-08-21T09:05:04.347 回答