【问题标题】:summarizing temperature data based on a vector of temperature thresholds基于温度阈值向量汇总温度数据
【发布时间】:2018-05-22 02:00:33
【问题描述】:

我有一个包含每日平均温度数据的数据框,结构如下:

 'data.frame':  4666 obs. of  6 variables:
 $ Site : chr  "EB" "FFCE" "IB" "FFCE" ...
 $ Date : Date, format: "2013-01-01" "2013-01-01" "2013-01-01" "2014-01-01" ... 
 $ Day  : int  1 1 1 1 1 1 1 1 1 1 ...
 $ Year : int  2013 2013 2013 2014 2014 2014 2014 2015 2015 2015 ...
 $ Month: int  1 1 1 1 1 1 1 1 1 1 ...
 $ Temp : num  28.5 28.3 28.3 27 27.8 ...

我正在尝试生成一个汇总表,其中仅汇总每个站点一年中高于某些温度阈值(例如 25c、26c)的天数。 我可以像这样使用 dplyr 手动实现这一点-

Days_above = Site_Daily_average %>% 
  group_by(Year, Site) %>% 
  summarise("23" = sum(Temp > 23), "24" = sum(Temp > 24),"25"= sum(Temp > 
25), "26"= sum(Temp > 26),  "27"= sum(Temp > 27), "28"= sum(Temp > 28), "29" 
= sum(Temp > 29),"30"= sum(Temp > 30), "31" = sum(Temp > 31), "ABOVE 
THRESHOLD" = sum(Temp > maxthreshold))%>% as.data.frame()  

生成这样的表格:

   Year Site  23  24  25  26  27  28  29 30 31 ABOVE THRESHOLD
1  2012   EB 142 142 142  91  64  22   0  0  0               0
2  2012 FFCE 238 238 238 210 119  64   0  0  0               0
3  2012   IB 238 238 238 218 138  87   1  0  0               0
4  2013   EB 115 115 115 115 115 109  44  0  0               0
5  2013 FFCE 223 223 216 197 148 114  94  0  0               0
6  2013   IB 365 365 365 348 299 194 135  3  0               0

...

但是,您可以看到代码相当冗长。我遇到的问题是为一系列温度阈值产生相同的输出,即 Tempclasses = Seq(16,32,0.25)。

如您所见,手动输入需要很长时间。我觉得这是一个非常简单的计算,应该有办法使用 dplyr 来识别序列向量中的每个变量,执行此功能并以完整的表格格式生成输出。抱歉,如果不清楚,因为我对 R 比较陌生, 欢迎任何建议,谢谢。

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    这是一个tidyverse 方法,同样使用mtcars 进行说明:

    library(tidyverse)
    
    mtcars %>% 
      mutate(threshold = cut(mpg, 
                             breaks=seq(10, max(mtcars$mpg)+10, 5), 
                             labels=seq(10, max(mtcars$mpg)+5, 5))) %>% 
      group_by(cyl, threshold) %>% 
      tally %>% 
      ungroup %>% 
      complete(threshold, nesting(cyl), fill=list(n=0)) %>% 
      arrange(desc(threshold)) %>% 
      group_by(cyl) %>% 
      mutate(N_above = cumsum(n)) %>% 
      select(-n) %>% 
      arrange(cyl, threshold)
    
       threshold cyl N_above
    1         10   4      11
    2         15   4      11
    3         20   4      11
    4         25   4       6
    5         30   4       4
    6         35   4       0
    7         10   6       7
    8         15   6       7
    9         20   6       3
    10        25   6       0
    11        30   6       0
    12        35   6       0
    13        10   8      14
    14        15   8       8
    15        20   8       0
    16        25   8       0
    17        30   8       0
    18        35   8       0
    

    如果您想要宽格式的最终​​数据,请在末尾添加spread并删除arrange

    ... %>%
    select(-n) %>% 
    spread(threshold, N_above)
    
      cyl 10 15 20 25 30 35
    1   4 11 11 11  6  4  0
    2   6  7  7  3  0  0  0
    3   8 14  8  0  0  0  0
    

    【讨论】:

    • 哦,我之前尝试过使用 spread 但显然没有正确安排它,非常感谢,太棒了
    • 我刚刚意识到与您的示例相比,我的 cumsum 反转了。您想要高于而不是低于阈值的天数吗?如果需要,我可以更新我的答案。
    • 如果可以的话最好在上面
    【解决方案2】:

    正如@dww 评论的那样,我们可以使用cut 来获得所需的格式。我已经在 mtcars 数据集上尝试过这个,我们为 mpg 列创建了从 10 到 35 的范围,步长为 5。

    df <- mtcars
    df$group <- cut(df$mpg, seq(10, 35, 5))
    

    然后我们按cyl 分组并使用table 来计算其中有多少落在相应的桶中。

    table(df$cyl, df$group)
    
    #  (10,15] (15,20] (20,25] (25,30] (30,35]
    #4       0       0       5       2       4
    #6       0       4       3       0       0
    #8       6       8       0       0       0
    

    现在,如果某个值大于 10,它也大于 15,因此 (15, 20) 桶中的数字还应包括 (10,15) 桶中的数字和 (20, 15) 桶中的数字应该包括前面的数字。因此,我们需要该表的逐行累积和

    t(apply(table(df$cyl, df$group), 1, cumsum))
    
    #   (10,15] (15,20] (20,25] (25,30] (30,35]
    # 4       0       0       5       7      11
    # 6       0       4       7       7       7
    # 8       6      14      14      14      14
    

    对于你的情况,代码会去

    Site_Daily_average$group <- cut(Site_Daily_average$Temp, seq(16,32,0.25))
    
    #and then do table to get required answer.
    t(apply(table(Site_Daily_average$Year,Site_Daily_average$Site, 
                  Site_Daily_average$group), 1, cumsum)
    

    【讨论】:

    • 哦,好的,所以这提供了由序列确定的温度等级中的温度计数?我试图实现的是计算该序列中每个单独值以上的观察总数,而不是每个“温度等级”的计数,这有意义吗?我不确定我解释清楚了
    • ohh..wait 所以sum(Temp &gt; 24) 也会有来自sum(Temp &gt; 23) 的值等等。每一行的数字会继续递增吗?
    • 不完全是,我认为令人困惑的是 sum( Temp > 24 ) 是一个有点欺骗性的公式,因为(据我了解)它是一个提供 数字总和的逻辑测试 该表达式为 TRUE 的数据点(即超过 24 c),而不是实际给您一个总和,因此它有效地为您提供逻辑 True 数据点的计数?那有意义吗?由于某种原因,我在使用“计数”和“长度”时遇到了问题。它更有意义我基本上需要高于序列中值的所有温度的“计数”/
    • 是的,没错。所以任何大于 24 的数字也大于 23。所以sum(Temp &gt; 24) 总是大于或等于sum(Temp &gt; 23)。我已经编辑了答案,看看它是否有意义。
    猜你喜欢
    • 2018-12-22
    • 2017-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-11
    • 1970-01-01
    相关资源
    最近更新 更多