【问题标题】:In R, how to calculate the cumulative sum of an outflow/precipitation event?在R中,如何计算流出/降水事件的累积和?
【发布时间】:2019-09-18 18:44:23
【问题描述】:

这是我的数据集的一部分,它有 12 年的相似数据,我想计算流出量从 0 变为一个值的累积总和,并将其存储为一个事件。然后我想找到事件的最大值、最小值、平均值和标准差,并按年分组。

例如,在下面的数据集中,有两个事件。每个事件的总和是多少,两个事件的最大值、最小值、平均值和 SD 分别是多少?

Date           Outflow
2/2/2014    0
2/2/2014    0
2/2/2014    0.073
2/2/2014    0.096
2/2/2014    0.096
2/2/2014    0.096
2/2/2014    0.015
2/2/2014    0.007
2/2/2014    0.003
2/2/2014    0.002
2/2/2014    0.001
2/2/2014    0.001
2/3/2014    0
2/3/2014    0
2/3/2014    0
2/3/2014    0
2/3/2014    0.022
2/3/2014    0.031
2/3/2014    0.034
2/3/2014    0.036
2/3/2014    0.037
2/3/2014    0.038
2/3/2014    0.038
2/3/2014    0.038
2/3/2014    0.038
2/3/2014    0.104

我已经能够计算每年的事件数量,但我无法计算每个事件的总和。

我已包含用于计算每年事件数量的代码。 LID_yearly 是数据集按年份拆分并运行代码的时间。

    m=rep(0,12) ## intialize a counter
    x="no_value"

    for(k in 1:length(LID_yearly)){
    for(i in 1:length(LID_yearly[[k]]$`Surface Runoff`)){
      if(LID_yearly[[k]]$`Surface Runoff`[i]==0){
        m[k]=m[k]
        x="no_value"
      } 

      else if((LID_yearly[[k]]$`Surface Runoff`[i]!=0)&&(x=="no_value")){
        m[k]=m[k]+1
        x="value"
      } else if((LID_yearly[[k]]$`Surface Runoff`[i]!=0)&&(x=="value")){
        m[k]=m[k]
        x="value"
      }
    }
  }

我想为我正在寻找的每个统计数据(例如,最大值、最小值等)为每年的事件获取一列。

这是我当前的输出。

"Year   Sum Max     Min    Mean   SD    No.of inflow  No. of Outflow

"2007   0   0       NA     NA     NA    122           0"
"2008   0   0       NA     NA     NA    106           0"
"2009   0   0       NA     NA     NA    149           0"
"2010   0   0       NA     NA     NA    122           0"
"2011   0   0       NA     NA     NA    125           0"
"2012   0   0       NA     NA     NA    82            0"
"2013   10  0.226   0.001  0.092  0.077 125           5"
"2014   46  0.325   0.001  0.078  0.073 149           14"
"2015   56  0.26    0.001  0.087  0.069 153           15"
"2016   21  0.135   0.001  0.036  0.029 136           15"
"2017   11  0.22    0.002  0.086  0.068 148           4"
"2018   0   0       NA     NA     NA    138           0"

这里最后两列是计算事件的数量,但统计数据不是我要查找的,因为它计算的是每个单个值的平均值或最大值,而不是一个事件。

这是我使用 dplyr 使用的代码:

  LIDTDFNEW <- LIDnew %>% group_by(year) %>% summarise("Sum of Bypass 
  Volume"=sum(`Surface Runoff`), 
  "Maximum Bypass Volume"=max(`Surface Runoff`), 
  "Minimum Byass Volume"=(if (!all(`Surface Runoff`==0)) min(`Surface 
  Runoff`[`Surface Runoff`!=0])else NA),
  "Average Bypass Volume"= (if(!all(`Surface Runoff`==0)) mean(`Surface 
  Runoff`[`Surface Runoff`!=0])else NA),
  "SD of Byass Volume"=(if (!all(`Surface Runoff`==0)) sd(`Surface 
  Runoff`[`Surface Runoff`!=0])else NA))

【问题讨论】:

  • 感谢您编辑数据集:) @tmfmnk
  • 你能更新一下预期的输出吗
  • 我已经包含了我当前的输出。

标签: r


【解决方案1】:

首先,我们使用应用于== 0-binarized Outflowcut() 生成一个事件列。

df2$event <- 
  cut(1:nrow(df2), breaks=c(1, which(c(0, diff(df2$Outflow == 0)) != 0), nrow(df2)) - 1)

注意:这看起来比实际复杂;我们只需要将第一行 1 和最后一行 nrow(df2) 添加到中断处。)

0-values 我们可以设置为NA:

df2$event[df2$Outflow == 0] <- NA

现在我们稍微重新调整一下,以便稍后获得一个漂亮的event 列。

df2$event <- as.numeric(droplevels(df2$event))

最后——为了获得事件汇总——我们使用aggregate() 来应用所有的汇总函数。

res1 <- do.call(data.frame, 
        aggregate(Outflow ~ event + Date, df2, function(x) 
  c(sum=sum(x), max=max(x), min=min(x), mean=mean(x), sd=sd(x)))
  )
res1
#   event     Date Outflow.sum Outflow.max Outflow.min Outflow.mean  Outflow.sd
# 1     1 2/2/2014       0.390       0.096       0.001   0.03900000 0.044790872
# 2     2 2/3/2014       0.312       0.038       0.022   0.03466667 0.005315073

编辑

如果您想要年度总结year 列可能会很方便,我们可以通过 strptime() 获得。

df2$year <- substr(strptime(df2$Date, format="%d/%m/%Y"), 1, 4)

现在,首先计算总和,然后将minmax 绑定到aggregate() 上的years。

sums <- aggregate(Outflow ~ event + Date + year, df2, sum)$Outflow
res2 <- cbind(max=max(sums), min=min(sums),
              do.call(data.frame, aggregate(Outflow ~ year, df2, function(x) 
                c(sum=sum(x), mean=mean(x), sd=sd(x)))))

res2
#    max   min year Outflow.sum Outflow.mean Outflow.sd
# 1 0.39 0.312 2014       0.806        0.031  0.0347206

这也应该扩展到几年。

注意:我在aggregates 到get a "data.frame" object with clean columns 周围包裹了一个do.call(data.frame, .)(即向量而不是矩阵)。

数据

df2 <- structure(list(Date = c("2/2/2014", "2/2/2014", "2/2/2014", "2/2/2014", 
"2/2/2014", "2/2/2014", "2/2/2014", "2/2/2014", "2/2/2014", "2/2/2014", 
"2/2/2014", "2/2/2014", "2/3/2014", "2/3/2014", "2/3/2014", "2/3/2014", 
"2/3/2014", "2/3/2014", "2/3/2014", "2/3/2014", "2/3/2014", "2/3/2014", 
"2/3/2014", "2/3/2014", "2/3/2014", "2/3/2014"), Outflow = c(0, 
0, 0.073, 0.096, 0.096, 0.096, 0.015, 0.007, 0.003, 0.002, 0.001, 
0.001, 0, 0, 0, 0, 0.022, 0.031, 0.034, 0.036, 0.037, 0.038, 
0.038, 0.038, 0.038, 0.104)), row.names = c(NA, -26L), class = "data.frame")

【讨论】:

  • 只有在每个日期只有一个事件(从 0 开始增加)时才会起作用。
  • @tmfmnk 感谢您的叫醒,终于比预期更具挑战性了:) 查看更新。
  • 在您的聚合数据框中,我期望的是两个事件之间的最大值;因此,在上述情况下,2014 年的最大值为 0.390,最小值为 0.312。
  • @AlfyJoseph 好的,请参阅更新。如果您将来在问题中添加详细的预期输出,将更容易获得您想要的结果。
  • 当然谢谢。你的回答效果很好。我使用 group_by 代替 cbind 从计算的总和中进行汇总。谢谢。
【解决方案2】:

这是dplyr 解决方案:

df %>%
  mutate(events = case_when(outflow != 0 ~ 1, TRUE ~ NA_real_)) %>% # identify events
  mutate(events = rank(events, ties.method = "first")) %>% # add sequence
  mutate(events = case_when(outflow == 0 ~ NA_integer_, lag(outflow) == 0 ~ as.integer(events), TRUE ~ as.integer(lag(events))) # same event, same number
group_by(events) %>% # Group by event
summarise(sum_outflow = sum(outflow, na.rm = TRUE), min_outflow = min(outflow, na.rm = TRUE), #etc.)

这是一个有点老套的版本,您当然可以整理它以获得更多合乎逻辑的名称,为事件排序。

不过,之后的 group_by 应该没问题。

编辑:

这不适用于如果事件超过 3 行,我必须想出一个更好的解决方案。

【讨论】:

  • 我尝试用我的数据框的名称来调整它,它对事件进行排名,但没有为同一个事件分配相同的数字。
  • 现在关于三行是有道理的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-16
  • 1970-01-01
  • 2021-10-24
  • 2019-08-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多