代码之家  ›  专栏  ›  技术社区  ›  nofunsally

拆分数据集,对每个组应用不同的操作,然后组合

  •  0
  • nofunsally  · 技术社区  · 10 年前

    我使用下面的代码将数据集一分为二,并对每一半执行类似的操作。然后将两个结果合并在一起。我知道我可能在描述拆分-应用-组合框架,但我想不出如何简化下面的代码。

    数据集有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)
    
    5 回复  |  直到 10 年前
        1
  •  5
  •   Frank    10 年前

    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
  •  2
  •   Stephan Kolassa    10 年前

    结合 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 使用 通过 。用适当的矩阵(即匿名 function ). 最后 打电话 这个 rbind 函数将结果按行绑定在一起。

    按排序结果 FF 列(如果需要)。

        3
  •  1
  •   shadow    10 年前

    您也可以使用 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 })
    
        4
  •  0
  •   xraynaud    10 年前

    可能有一种更简单的方法,但我认为这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
  •  0
  •   nicola    10 年前

    试试看:

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