[英]R plyr applied on row
我有一個這樣的數據框:
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。 但不知怎的,我無法做到正確 - 問題在於挑選出“能量”成分。
誰知道怎么解決這個問題? [提前致謝...]
來自@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
執行此操作的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]
馬修編輯:
在此基礎上,使用join繼承范圍 ,稍微更高級(和更快)的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 } ]
這將在您的示例中完成:
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"])
只使用基本功能:
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.