汇总缺乏明确分组变量的每日数据(月份)

时间:2018-02-24 19:01:56

标签: r dplyr data.table

我的数据框有6000个位置。对于每个地点,我有36年的每日降雨量数据。

示例数据:

      set.seed(123)

      mat <- matrix(round(rnorm(6000*36*365), digits = 2),nrow = 6000*36, ncol = 365)
      dat <- data.table(mat)
      names(dat) <- rep(paste0("d_",1:365))

      dat$loc.id <- rep(1:6000, each = 36)
      dat$year <- rep(1980:2015, times = 6000)                     

我想要做的是为每个地点生成每个月的长期平均降雨量。对于例如对于loc.id = 1,平均降雨量在1月,2月,3月和12月。

让我们说这个数据叫做df,这是一个数据表

    library(dplyr)

这就是我的所作所为:

    loc.list <- unique(dat$loc.id)
      my.list <- list() # a list to store results 

      ptm <- proc.time()

      for(i in seq_along(loc.list)){

          n <- loc.list[i]
          df1 <- dat[dat$loc.id == n,]
          df2 <- gather(df1, day, rain, -year)   # this melts the data in long format

          df3 <- df2 %>% mutate(day = gsub("d_","", day)) %>% # since the day column was in "d_1" format, I converted into integer (1,2,3..365)
                         mutate(day = as.numeric(as.character(day))) %>%  # ensure that day column is numeric. For some reasonson, some NA.s appear.
                         arrange(year,day) %>% # ensure that they are arranged in order
                         mutate(month = strptime(paste(year, day), format = "%Y %j")$mon + 1) %>% # assing each day to a month
                         group_by(year,month) %>%  # group by year and month
                         summarise(month.rain = sum(rain)) %>% # calculate for each location, year and month, total rainfall
                         group_by(month) %>% # group by month
                         summarise(month.mean = round(mean(month.rain), digits = 2)) #  calculate for each month, the long term mean

          my.list[[i]] <- df3
          }
      proc.time() - ptm

      user  system elapsed 
      1036.17    0.20 1040.68

我想问一下是否有更有效,更快捷的方法来实现这项任务

2 个答案:

答案 0 :(得分:3)

另一个data.table替代方案:

# change column names to month, grabbed from 365 dates of a non-leap year
setnames(dat, c(format(as.Date("2017-01-01") + 0:364, "%b"),
                "loc.id", "year"))

# melt to long format
d <- melt(dat, id.vars = c("loc.id", "year"),
          variable.name = "month", value.name = "rain")

# calculate mean rain by location and month
d2 <- d[ , .(mean_rain = mean(rain)), by = .(loc, month)]

这似乎比caw5cs的答案快7倍。然而,马丁摩根的结果采用了不同的格式,这阻碍了对时间的直接比较。

如果您想在'dat'中使用唯一的列名称,则可以仅使用%b_%d(月 - 日)而不是%b。然后使用substr中的by来获取月份部分:

# change column names to month_day, using 365 dates of a non-leap year
setnames(dat, c(format(as.Date("2017-01-01") + 0:364, "%b_%d"),
                "loc.id", "year"))

# melt to long format
d <- melt(dat, id.vars = c("loc.id", "year"),
          variable.name = "month_day", value.name = "rain")

# calculate mean rain by location and month
d2 <- d[ , .(mean_rain = mean(rain)), by = .(loc.id, month = substr(month_day, 1, 3))]

答案 1 :(得分:2)

使用加密命名的rowsum()来汇总每个站点的日降雨量

loc.id = rep(1:6000, each = 36)
daily.by.loc = rowsum(mat, loc.id)

并在转置矩阵上使用相同的技巧按月求和(因为必须忽略365列闰年)。

month = factor(
    months(as.Date(0:364, origin="1970-01-01")),
    levels = month.name
)
loc.by.month = rowsum(t(daily.by.loc), month)

除以观察次数计算平均值; R的列主要矩阵表示和回收规则适用。移调使方向与数据相同。

days.per.month = tabulate(month)
ans = t(loc.by.month / (36 * days.per.month))

结果是6000 x 12矩阵

> dim(ans)
[1] 6000   12
> head(ans, 3)
      January     February       March       April         May         June
1  0.01554659  0.002043651 -0.02950717 -0.02700926 0.003521505 -0.011268519
2  0.04953405  0.032926587 -0.04959677  0.02808333 0.022051971  0.009768519
3 -0.01125448 -0.023343254 -0.02672939  0.04012963 0.018530466  0.035583333
          July       August   September     October    November    December
1  0.009874552 -0.030824373 -0.04958333 -0.03366487 -0.07390741 -0.07899642
2 -0.011630824 -0.003369176 -0.00100000 -0.00594086 -0.02817593 -0.01161290
3  0.031810036  0.059641577 -0.01109259  0.04646953 -0.01601852  0.03103943

不到一秒钟。