我使用下面的代码将数据集拆分为两个,并对每一半执行类似的操作。然后将这两个结果合并在一起。我知道我可能正在描述split-apply-combine框架,但我无法想到如何简化下面的代码。
数据集有4个要更新的变量。 4个变量中的每一个都有一个公式来计算新值,每半个公式不同,共有8个公式。
下面的代码可能会通过某种程度的矢量化来改进吗?它似乎比必要的更冗长。我不确定如何为每个分割半部执行不同的操作(即使用不同的公式),除了下面的方法。
data <- structure(list(site = c(1L, 1L, 1L, 1L, 1L, 1L), plot = 1:6,
C = c(40L, 30L, 10L, 5L, 0L, 0L), E = c(0L, 0L, 0L, 10L,
20L, 45L), M = c(0L, 0L, 0L, 0L, 0L, 10L), P = c(1000L, 900L,
800L, 500L, 200L, 50L), FF = c(1L, 1L, 1L, 0L, 0L, 0L)), .Names = c("site",
"plot", "C", "E", "M", "P", "FF"), class = "data.frame", row.names = c(NA,
-6L))
df1 <- data[data$FF == 1,]
df0 <- data[data$FF == 0,]
df1$C <- df1$C * 1.1
df1$E <- df1$E * 0.9
df1$M <- df1$M * 0.1
df1$P <- df1$P * 1.01
df0$C <- df0$C * 0.8
df0$E <- df0$E * 1.05
df0$M <- df0$M * 1.01
df0$P <- df0$P * 1.01
df.new <- rbind(df1, df0)
答案 0 :(得分:5)
R中有许多用于split-apply-combine的工具。我倾向于使用data.table包:
require(data.table)
mydt <- data.table(data)
mycols <- c('C','E','M','P')
newcols <- paste0(mycols,'new')
my1vec <- c(1.1,.9,1,1.01)
my0vec <- c(.8,1.05,1.01,1.01)
mydt[FF==1,(newcols):=mapply(`*`,my1vec,.SD,SIMPLIFY=FALSE),.SDcols=mycols]
mydt[FF==0,(newcols):=mapply(`*`,my0vec,.SD,SIMPLIFY=FALSE),.SDcols=mycols]
我将新值放在新列中。如果您想要覆盖旧值(如原始代码那样),请使用(mycols)
代替(newcols)
。
答案 1 :(得分:1)
将by
和do.call
组合在一起:
do.call(rbind,
by(data,data$FF,
function(data)data*matrix(c(1,1,.8,1.05,1.01,1.01,1),
ncol=ncol(data),nrow=nrow(data),byrow=TRUE)))
也就是说,使用data
将data$FF
与by
分开。将每个块按顺序乘以适当的矩阵(即匿名function
)。最后,do.call
rbind
函数将结果按行方式绑定在一起。
如果需要,可以按FF
列对结果进行排序。
答案 2 :(得分:1)
您也可以使用within
并使用FF
作为数字变量。它没有一些答案那么简短,但它有点冗长。
df.new <- within(data, {
C = C * (0.8 + 0.3 * FF)
E = E * (1.05 - 0.15 * FF)
M = M * (1.01 - 0.91 * FF)
P = P * 1.01 })
答案 3 :(得分:0)
可能有一种更简单的方法,但我认为这4行符合您的要求:
df.new = data
df.new$C = ifelse(data$FF==1,data$C*1.1,data$C*0.8)
df.new$E = ifelse(data$FF==1,data$E*0.9,data$E*1.05)
df.new$M = ifelse(data$FF==1,data$M*0.1,data$M*1.01)
df.new$P = ifelse(data$FF==1,data$P*1.01,data$P*1.01)
答案 4 :(得分:0)
试试这个:
#define the coefficients in the FF==1 case
FF1coeffs<-c(1.1,0.9,0.1,1.01)
#define the coefficients in the FF==0 case
FF0coeffs<-c(0.8,1.05,1.01,1.01)
#multiply
data[,3:6]*(rep(FF1coeffs,each=nrow(data))*data$FF+(1-data$FF)*rep(FF0coeffs,each=nrow(data)))