【问题标题】:Split dataset, apply different operation on each group, and then combine拆分数据集,对每组应用不同的操作,然后合并
【发布时间】:2015-02-05 19:46:00
【问题描述】:

我正在使用下面的代码将数据集分成两部分,并对每一部分执行类似的操作。然后将这两个结果重新合并在一起。我知道我可能在描述 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)

【问题讨论】:

  • 等等,你用 plyr 和 data.table 标记了这个,但还没有探索如何使用它们?
  • 我确实通过其他 SO 问题和答案探索了 plyr 和 data.table,以及一些我没有在这里重现的微弱尝试。但是,如果我有足够的资金与他们一起编写代码,我认为这两种方法似乎都是合适的。我可以发布非功能代码 sn-ps。谢谢。

标签: r data.table plyr dplyr


【解决方案1】:

R 中有许多用于拆分-应用-组合的工具。我倾向于使用 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)

【讨论】:

    【解决方案2】:

    像这样组合bydo.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)))
    

    也就是说,使用bydatadata$FF 分开。将每个块逐项乘以适当的矩阵(即匿名function)。最后,do.callrbind 函数将结果按行绑定在一起。

    如果需要,按FF 列对结果进行排序。

    【讨论】:

      【解决方案3】:

      您也可以使用withinFF 作为数字变量。它不像一些答案那么短,但它有点冗长。

      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 })
      

      【讨论】:

        【解决方案4】:

        可能有一种更简单的方法,但我认为这 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)
        

        【讨论】:

          【解决方案5】:

          试试这个:

          #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)))
          

          【讨论】:

            猜你喜欢
            • 2020-01-07
            • 1970-01-01
            • 2013-06-25
            • 2023-01-18
            • 2022-12-15
            • 2017-06-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多