【问题标题】:Extract hourly max/min/median values with timestamp in R在R中提取带有时间戳的每小时最大值/最小值/中值
【发布时间】:2018-09-17 08:28:18
【问题描述】:

我有一个数据框,每 10 分钟测量一次温度。测量是在不同的位置(称为“LCZ”)进行的,每个位置的值在不同的列中。

这是我的数据框的一部分:(它还包含缺失值 NA)

 Time `LCZ 3-2` `LCZ 3-10` `LCZ 6-1` `LCZ 6-9` `LCZ 9-4`


               <dttm>     <dbl>      <dbl>     <dbl>     <dbl>     <dbl>
 1 2017-08-26 17:00:00      27.5       27.5      27.5      27.0      27.0
 2 2017-08-26 17:10:00      27.5       27.0      27.5      27.0      27.0
 3 2017-08-26 17:20:00      27.5       27.0      27.0      27.0      27.0
 4 2017-08-26 17:30:00      27.0       26.5      27.0      26.5      26.5
 5 2017-08-26 17:40:00      26.5       26.5      26.5      26.5      26.5
 6 2017-08-26 17:50:00      26.5       26.0      26.5      26.0      26.5
 7 2017-08-26 18:00:00      26.5       26.0      26.5      26.5      26.5
 8 2017-08-26 18:10:00      27.0       26.0      26.5      26.5      26.0
 9 2017-08-26 18:20:00      26.5       26.5      26.5      26.5      26.0
10 2017-08-26 18:30:00      26.5       26.5      26.5      26.5      26.0

我希望为每个位置或列计算每小时的最低/最高/中值温度,此外,对于每小时的最低/最高温度,我还希望计算分别发生最低/最高温度的原始数据的时间戳。

R 可以做到这一点吗?

我已经尝试了各种功能。

group_by 允许我计算每列的最小值/最大值,但没有时间戳。 period.apply 还允许我计算最小值/最大值/中值,但仅限于一列。 aggregate() 也没有成功。

我正在学习 R,但没有接近解决这个问题。

这个网站帮助我解决了各种问题,但我真的被困在这个问题上。有人可以帮忙吗?提前致谢

【问题讨论】:

  • 如何定义一个小时?
  • 一小时作为 17:10, 17:20,...,17:50 的值的汇总,同样适用于 18:10, 18:20,...,18: 50等
  • @M95 如果您可以在问题中包含所需输出的格式,这将有所帮助。谢谢
  • 所以每小时需要 15 个值 = 5 cols x 3 stats?
  • 是的,我不确定会发生什么输出,但这满足了我的需求。谢谢您的回答!还有你回答中的额外解释,这让我在 R 中再次了解了更多。

标签: r dataframe time


【解决方案1】:

我们可以使用 包中的floor_date 创建一个新列Time2 来显示每小时信息。如果这不是您想要定义每小时分组的方式,您也可以尝试round_dateceiling_date。之后,我们可以使用包中的gather将数据帧从宽格式转换为长格式。

library(dplyr)
library(tidyr)
library(lubridate)

dat2 <- dat %>%
  mutate(Time = ymd_hms(Time),
         Time2 = floor_date(Time, unit = "hour")) %>%
  gather(LCZ, Value, starts_with("LCZ")) %>%
  group_by(Time2, LCZ)

之后,我们可以通过LCZTime2来汇总数据。

dat3 <- dat2 %>%
  summarise(Min = min(Value, na.rm = TRUE),
            Max = max(Value, na.rm = TRUE),
            Median = median(Value, na.rm = TRUE)) %>%
  ungroup()
dat3
# # A tibble: 10 x 5
#    Time2               LCZ        Min   Max Median
#    <dttm>              <chr>    <dbl> <dbl>  <dbl>
#  1 2017-08-26 17:00:00 LCZ.3.10  26.0  27.5   26.8
#  2 2017-08-26 17:00:00 LCZ.3.2   26.5  27.5   27.2
#  3 2017-08-26 17:00:00 LCZ.6.1   26.5  27.5   27.0
#  4 2017-08-26 17:00:00 LCZ.6.9   26.0  27.0   26.8
#  5 2017-08-26 17:00:00 LCZ.9.4   26.5  27.0   26.8
#  6 2017-08-26 18:00:00 LCZ.3.10  26.0  26.5   26.2
#  7 2017-08-26 18:00:00 LCZ.3.2   26.5  27.0   26.5
#  8 2017-08-26 18:00:00 LCZ.6.1   26.5  26.5   26.5
#  9 2017-08-26 18:00:00 LCZ.6.9   26.5  26.5   26.5
# 10 2017-08-26 18:00:00 LCZ.9.4   26.0  26.5   26.0

如果需要,我们可以创建二进制值来指示该值是最小值、最大值还是中值,如下所示。当您要进一步过滤数据框时,此格式很有用。

dat4 <- dat2 %>%
  mutate(Min = (Value == min(Value, na.rm = TRUE)) + 0L,
         Max = (Value == max(Value, na.rm = TRUE)) + 0L,
         Median = (Value == median(Value, na.rm = TRUE)) + 0L) %>%
  ungroup()
dat4
# # A tibble: 50 x 7
#    Time                Time2               LCZ     Value   Min   Max Median
#    <dttm>              <dttm>              <chr>   <dbl> <int> <int>  <int>
#  1 2017-08-26 17:00:00 2017-08-26 17:00:00 LCZ.3.2  27.5     0     1      0
#  2 2017-08-26 17:10:00 2017-08-26 17:00:00 LCZ.3.2  27.5     0     1      0
#  3 2017-08-26 17:20:00 2017-08-26 17:00:00 LCZ.3.2  27.5     0     1      0
#  4 2017-08-26 17:30:00 2017-08-26 17:00:00 LCZ.3.2  27.0     0     0      0
#  5 2017-08-26 17:40:00 2017-08-26 17:00:00 LCZ.3.2  26.5     1     0      0
#  6 2017-08-26 17:50:00 2017-08-26 17:00:00 LCZ.3.2  26.5     1     0      0
#  7 2017-08-26 18:00:00 2017-08-26 18:00:00 LCZ.3.2  26.5     1     0      1
#  8 2017-08-26 18:10:00 2017-08-26 18:00:00 LCZ.3.2  27.0     0     1      0
#  9 2017-08-26 18:20:00 2017-08-26 18:00:00 LCZ.3.2  26.5     1     0      1
# 10 2017-08-26 18:30:00 2017-08-26 18:00:00 LCZ.3.2  26.5     1     0      1
# # ... with 40 more rows

数据

dat <- read.table(text = "Time 'LCZ 3-2' 'LCZ 3-10' 'LCZ 6-1' 'LCZ 6-9' 'LCZ 9-4'
                  '2017-08-26 17:00:00'      27.5       27.5      27.5      27.0      27.0
                  '2017-08-26 17:10:00'      27.5       27.0      27.5      27.0      27.0
                  '2017-08-26 17:20:00'      27.5       27.0      27.0      27.0      27.0
                  '2017-08-26 17:30:00'      27.0       26.5      27.0      26.5      26.5
                  '2017-08-26 17:40:00'      26.5       26.5      26.5      26.5      26.5
                  '2017-08-26 17:50:00'      26.5       26.0      26.5      26.0      26.5
                  '2017-08-26 18:00:00'      26.5       26.0      26.5      26.5      26.5
                  '2017-08-26 18:10:00'      27.0       26.0      26.5      26.5      26.0
                  '2017-08-26 18:20:00'      26.5       26.5      26.5      26.5      26.0
                  '2017-08-26 18:30:00'      26.5       26.5      26.5      26.5      26.0",
                  header = TRUE, stringsAsFactors = FALSE)

【讨论】:

  • 也许OP 想要将locationmin/max/median 值与location 发生最小值/最大值的实际日期/时间结合起来。但我们需要等待他的评论。
  • 你是对的。这是可能的,因为 OP 没有指定所需的输出。
  • 一旦知道所需的输出,它总是很容易找到正确的解决方案。也许我们可以向 OP 提问。
  • 我认为 OP 可以读取我们的 cmets。有时人们在看到一些示例之前可能不知道所需的输出。很高兴我们有几个不同的答案供 OP 审查。
【解决方案2】:

这是一种使用dplyr动词的方法:

library(lubridate)

df %>%
  gather(Location, Temp, -Time) %>%
  group_by(Date = date(Time), HoD = hour(Time), Location) %>%
  mutate_at(.vars = "Temp", .funs = list(Min = min, Max = max, Median = median)) %>%
  filter(Temp == Min | Temp == Max) %>%
  arrange(Location, Time) %>%
  distinct(Temp, .keep_all = T) %>%
  mutate(MinMax = ifelse(Temp == Min, "MinTime", "MaxTime")) %>%
  dplyr::select(-Temp) %>%
  spread("MinMax", "Time")

输出:

注意NA,这意味着当天、那个小时和那个位置的最低和最高温度是相同的。

# A tibble: 10 x 8
# Groups:   Date, HoD, Location [10]
   Location Date         HoD   Min   Max Median MaxTime             MinTime            
   <chr>    <date>     <int> <dbl> <dbl>  <dbl> <chr>               <chr>              
 1 LCZ.3.10 2017-08-26    17  26.0  27.5   26.8 2017-08-26 17:00:00 2017-08-26 17:50:00
 2 LCZ.3.10 2017-08-26    18  26.0  26.5   26.2 2017-08-26 18:20:00 2017-08-26 18:00:00
 3 LCZ.3.2  2017-08-26    17  26.5  27.5   27.2 2017-08-26 17:00:00 2017-08-26 17:40:00
 4 LCZ.3.2  2017-08-26    18  26.5  27.0   26.5 2017-08-26 18:10:00 2017-08-26 18:00:00
 5 LCZ.6.1  2017-08-26    17  26.5  27.5   27.0 2017-08-26 17:00:00 2017-08-26 17:40:00
 6 LCZ.6.1  2017-08-26    18  26.5  26.5   26.5 NA                  2017-08-26 18:00:00
 7 LCZ.6.9  2017-08-26    17  26.0  27.0   26.8 2017-08-26 17:00:00 2017-08-26 17:50:00
 8 LCZ.6.9  2017-08-26    18  26.5  26.5   26.5 NA                  2017-08-26 18:00:00
 9 LCZ.9.4  2017-08-26    17  26.5  27.0   26.8 2017-08-26 17:00:00 2017-08-26 17:30:00
10 LCZ.9.4  2017-08-26    18  26.0  26.5   26.0 2017-08-26 18:00:00 2017-08-26 18:10:00

【讨论】:

    【解决方案3】:

    这是tidyverse 解决方案。

    解释:我们新建一个小时-floored时间列Time.hour,我们可以通过它进行分组;然后我们计算必要的汇总统计。

    res <- df %>%
        mutate(Time = as.POSIXct(Time, format = "%Y-%m-%d %H:%M:%S")) %>%  # Time as POSIXct
        gather(location, value, -Time) %>%
        mutate(Time.hour = format(Time, "%y-%m-%d %H")) %>%
        group_by(Time.hour, location) %>%
        summarise(min = min(value), max = max(value), median = median(value));
    res;
    ## A tibble: 10 x 5
    ## Groups:   Time.hour [?]
    #   Time.hour   location   min   max median
    #   <chr>       <chr>    <dbl> <dbl>  <dbl>
    # 1 17-08-26 17 LCZ.3.10  26.0  27.5   26.8
    # 2 17-08-26 17 LCZ.3.2   26.5  27.5   27.2
    # 3 17-08-26 17 LCZ.6.1   26.5  27.5   27.0
    # 4 17-08-26 17 LCZ.6.9   26.0  27.0   26.8
    # 5 17-08-26 17 LCZ.9.4   26.5  27.0   26.8
    # 6 17-08-26 18 LCZ.3.10  26.0  26.5   26.2
    # 7 17-08-26 18 LCZ.3.2   26.5  27.0   26.5
    # 8 17-08-26 18 LCZ.6.1   26.5  26.5   26.5
    # 9 17-08-26 18 LCZ.6.9   26.5  26.5   26.5
    #10 17-08-26 18 LCZ.9.4   26.0  26.5   26.0
    

    如果需要,转换为宽:

    res %>%
        ungroup() %>%
        gather(what, val, min:median) %>%
        unite(key, what, location) %>%
        spread(key, val)
    ## A tibble: 2 x 16
    #  Time.hour   max_LCZ.3.10 max_LCZ.3.2 max_LCZ.6.1 max_LCZ.6.9 max_LCZ.9.4
    #  <chr>              <dbl>       <dbl>       <dbl>       <dbl>       <dbl>
    #1 17-08-26 17         27.5        27.5        27.5        27.0        27.0
    #2 17-08-26 18         26.5        27.0        26.5        26.5        26.5
    ## ... with 10 more variables: median_LCZ.3.10 <dbl>, median_LCZ.3.2 <dbl>,
    ##   median_LCZ.6.1 <dbl>, median_LCZ.6.9 <dbl>, median_LCZ.9.4 <dbl>,
    ##   min_LCZ.3.10 <dbl>, min_LCZ.3.2 <dbl>, min_LCZ.6.1 <dbl>,
    ##   min_LCZ.6.9 <dbl>, min_LCZ.9.4 <dbl>
    

    样本数据

    df <- read.table(text =
        "Time 'LCZ 3-2' 'LCZ 3-10' 'LCZ 6-1' 'LCZ 6-9' 'LCZ 9-4'
     1 '2017-08-26 17:00:00'      27.5       27.5      27.5      27.0      27.0
     2 '2017-08-26 17:10:00'      27.5       27.0      27.5      27.0      27.0
     3 '2017-08-26 17:20:00'      27.5       27.0      27.0      27.0      27.0
     4 '2017-08-26 17:30:00'      27.0       26.5      27.0      26.5      26.5
     5 '2017-08-26 17:40:00'      26.5       26.5      26.5      26.5      26.5
     6 '2017-08-26 17:50:00'      26.5       26.0      26.5      26.0      26.5
     7 '2017-08-26 18:00:00'      26.5       26.0      26.5      26.5      26.5
     8 '2017-08-26 18:10:00'      27.0       26.0      26.5      26.5      26.0
     9 '2017-08-26 18:20:00'      26.5       26.5      26.5      26.5      26.0
    10 '2017-08-26 18:30:00'      26.5       26.5      26.5      26.5      26.0", header = T, row.names = 1)
    

    【讨论】:

      【解决方案4】:

      不太确定OP 想要以哪种格式显示结果。使用mutate_at 可以找到一种解决方案:

      library(lubridate)
      library(dplyr)
      
      result <- df %>% mutate(Time = ymd_hms(Time)) %>%
        group_by(Hourly = format(Time, "%Y%m%d%H")) %>%
        mutate_at(vars(starts_with("LCZ")), funs(min = min, max = max, med = median )) %>%
        select(Time, Hourly, sort(names(select(.,-Time-Hourly))))
      

      结果

      result[,1:9]
      # # A tibble: 10 x 9
      # # Groups: Hourly [2]
      #   Time                Hourly     LCZ3_02 LCZ3_02_max LCZ3_02_med LCZ3_10 LCZ3_10_max LCZ3_10_med LCZ3_10_min
      #   <dttm>              <chr>        <dbl>       <dbl>       <dbl>   <dbl>       <dbl>       <dbl>       <dbl>
      # 1 2017-08-26 17:00:00 2017082617    27.5        27.5        27.2    27.5        27.5        26.8        26.0
      # 2 2017-08-26 17:10:00 2017082617    27.5        27.5        27.2    27.0        27.5        26.8        26.0
      # 3 2017-08-26 17:20:00 2017082617    27.5        27.5        27.2    27.0        27.5        26.8        26.0
      # 4 2017-08-26 17:30:00 2017082617    27.0        27.5        27.2    26.5        27.5        26.8        26.0
      # 5 2017-08-26 17:40:00 2017082617    26.5        27.5        27.2    26.5        27.5        26.8        26.0
      # 6 2017-08-26 17:50:00 2017082617    26.5        27.5        27.2    26.0        27.5        26.8        26.0
      # 7 2017-08-26 18:00:00 2017082618    26.5        27.0        26.5    26.0        26.5        26.2        26.0
      # 8 2017-08-26 18:10:00 2017082618    27.0        27.0        26.5    26.0        26.5        26.2        26.0
      # 9 2017-08-26 18:20:00 2017082618    26.5        27.0        26.5    26.5        26.5        26.2        26.0
      # 10 2017-08-26 18:30:00 2017082618    26.5        27.0        26.5    26.5        26.5        26.2        26.0
      

      数据

      df <- read.table(text =
      "Time    LCZ3_02    LCZ3_10   LCZ6_01   LCZ6_09    LCZ9_04
      1 '2017-08-26 17:00:00'      27.5       27.5      27.5      27.0      27.0
      2 '2017-08-26 17:10:00'      27.5       27.0      27.5      27.0      27.0
      3 '2017-08-26 17:20:00'      27.5       27.0      27.0      27.0      27.0
      4 '2017-08-26 17:30:00'      27.0       26.5      27.0      26.5      26.5
      5 '2017-08-26 17:40:00'      26.5       26.5      26.5      26.5      26.5
      6 '2017-08-26 17:50:00'      26.5       26.0      26.5      26.0      26.5
      7 '2017-08-26 18:00:00'      26.5       26.0      26.5      26.5      26.5
      8 '2017-08-26 18:10:00'      27.0       26.0      26.5      26.5      26.0
      9 '2017-08-26 18:20:00'      26.5       26.5      26.5      26.5      26.0
      10 '2017-08-26 18:30:00'      26.5       26.5      26.5      26.5      26.0",
      header = TRUE, stringsAsFactors = FALSE)
      

      【讨论】:

        猜你喜欢
        • 2019-05-18
        • 1970-01-01
        • 2012-04-03
        • 1970-01-01
        • 2019-01-16
        • 1970-01-01
        • 1970-01-01
        • 2015-07-04
        • 2014-10-17
        相关资源
        最近更新 更多