0

我需要根据 OBJECTID 链接的几个字段进行分类/重新编码。如果您有兴趣:我的对象是河流,我需要总结/重新编码各种生态相关参数。

对于这个例子,我只是在做一个平均数,但实际上我需要实现更复杂的重新编码;fe 如果 OBJECTID 标识的河流段的 70% 为 OM < 2 或 80% 为 OM < 3,则 OBJECT i 属于第 1 类,如果 50% 的河流段为 OM < 4 或 60%,则 OBJECT i 属于第 2 类是 OM 4 还是 5 等...)

Input                              Output

OBJECTID  OM                       OBJECTID  OM     OM_mean  
1         3.1                      1         3.1    5.13                      
1         8.2                      1         8.2    5.13
1         4.1       ----->         1         4.1    5.13
2         2.3                      2         2.3    6.2
2         9.1                      2         9.1    6.2

(是的,我需要这种形式,聚合不能满足我的需要)

使用 for 循环相对容易实现,但是,我的表非常大,而且我的数据处理过程非常(在现代计算机上几天)

for(i in dat$OBJECTID) {
  a=dat[dat$OBJECTID == i,]
  dat$OM_mean[dat$OBJECTID == i]      = mean(a$OM)
  }

我想知道是否存在使用应用之类的更优雅/更快的方法,但我找不到解决方案。我希望我能够清楚地说明我的问题。

如果使用了不恰当的术语,或者您认为主题标题不是很清楚,请纠正我,我对 R 和一般编程比较陌生。

我用于重新编码的实际函数(而不是示例中给出的平均值)是:

for(i in ecol_risk$OBJECTID) {
  a=ecol_risk@data[ecol_risk$OBJECTID == i,] # subset one river stretch of interest

  if(min(a$OM) %in% c(1,2,3,4,5)){  # Filters out some unwanted values

    b=aggregate(a$SLengthM, by=list(a$OM), FUN=sum)
    names(b) = c("OM", "SLengthM")
    b$frac = b$SLengthM/(sum(a$SLengthM)) # Calculate the % of total river stretch length
    b$frac12 = 0
      if(1 %in% b$OM & 2 %in% b$OM) { # get % for combination of two OM values
        b$frac12 = b$frac[b$OM == 1] + b$frac[b$OM == 2] 
      }
    b$frac45 = 0
    if(4 %in% b$OM & 5 %in% b$OM) {
      b$frac12 = b$frac[b$OM == 4] + b$frac[b$OM == 5] 
    }

    b$OM_agg = 3  # do some weird recoding

    b$OM_agg[b$frac >= 0.8 & b$OM == 5] = 4
    b$OM_agg[b$frac >= 0.8 & b$OM == 4] = 4
    b$OM_agg[b$bfrac45 >= 0.7] = 4

    b$OM_agg[b$frac >= 0.5 & b$OM == 1] = 2
    b$OM_agg[b$frac >= 0.7 & b$OM == 2] = 2
    b$OM_agg[b$frac12 >= 0.7] = 2  

    b$OM_agg[b$frac >= 0.8 & b$OM == 1] = 1
    b$OM_agg[b$frac >= 0.9 & b$OM == 2] = 1
    b$OM_agg[b$bfrac12 >= 0.9] = 1

    x = min(b$OM_agg)

    ecol_risk@data$OM_agg[ecol_risk$OBJECTID == i] = x

    print(i)
  }
}
4

2 回答 2

2

为了最大限度地提高速度和语法的简单性,请使用data.table

library(data.table)
dt = data.table(your_data_frame)

dt[, OM_MEAN := mean(OM), by = OBJECTID]
于 2013-07-26T13:30:25.267 回答
1

如果您只想计算平均值,那么该?ave函数就是您要寻找的

dat[, "OM_mean"] <- ave(dat$OM, dat$OBJECTID, FUN=mean)

由于您显然想用您的data.frame而不只是一个计算许多汇总统计数据,因此我建议您改用该plyr软件包。如果您使用您提供的数据(连同权重),则 dput(dat) 给出:

dat <- structure(list(OBJECTID = c(1L, 1L, 1L, 2L, 2L), 
                      OM = c(3.1, 8.2, 4.1, 2.3, 9.1), 
                      weight = c(1, 1, 2, 1, 2)), 
                 .Names = c("OBJECTID", "OM", "weight"), 
                 row.names = c(NA, -5L), class = "data.frame")

然后您可以使用ddplyfromplyr来计算您的摘要。

# load package
require(plyr)
# split by OBJECTID and apply function
ddply(dat, "OBJECTID", function(x){
  x[,"OM_mean"] <- mean(x$OM) # mean
  x[,"OM_w.mean"] <- weighted.mean(x$OM, x$weight) # weighted mean
  return(x) # return the entire data.frame
})
于 2013-07-26T12:36:09.313 回答