【问题标题】:How to Group by 28 day Period and District in R如何在 R 中按 28 天期间和地区分组
【发布时间】:2020-04-02 19:41:11
【问题描述】:

我在 CSV 中有以下数据:

OBJECTID,District,Zone,year_value,FROM_DATE,SUM_Crime
1,Northwestern,Not in Zone,2019,2/6/2019,4
2,Northwestern,Zone 30,2019,2/7/2019,6
3,Northwestern,Zone 40,2019,2/8/2019,5
4,Northwestern,Zone 30,2019,2/9/2019,2
5,Northwestern,Not in Zone,2019,2/10/2019,4
6,Northwestern,Zone 40,2019,2/11/2019,4
7,Northwestern,Zone 30,2019,2/12/2019,0

我将如何每 3 天分组一次,从 R 中的 6 日开始?最终结果如下所示(值是 3 天期间的 Sum_Crime):

Zone,2/6/2019 - 2/8/2019,2/9/2019 - 2/11/2019,2/12/2019 - 2/13/2019

Not in Zone,4,4,
Zone 30,6,2,0
Zone 40,5,4,

但是,这仅适用于一个地区(西北部),理想情况下,我拥有的每个地区都会这样做。

谢谢。

【问题讨论】:

  • (1) 您需要转换为 R 中的Date 类,也许是as.Date(FROM_DATE, format="%m/%d/%Y")(我假设格式,验证)。 (2) 你可以使用类似于seq.Date(Sys.Date(), Sys.Date()+100, by = 3) 的东西(使用你喜欢的开始日期)来产生一个边界向量,然后cut 得到你需要的东西。
  • (您可以通过stackoverflow.com/q/60894989下的cmets建议的方式控制cut(..., labels=...)

标签: r


【解决方案1】:

有几种方法可以解决这个问题。

首先,我们需要确定每个 3 天的期限。为此,我将创建一个datevec,它是一个天序列。

dat$RealDate <- as.Date(dat$FROM_DATE, format = "%m/%d/%Y")
datevec <- seq(min(dat$RealDate), max(dat$RealDate) + 3, by = 3)
dat$Period1 <- cut(dat$RealDate, datevec,
                   labels = paste(datevec[-length(datevec)], datevec[-1], sep = " - "))
dat
#   OBJECTID     District        Zone year_value FROM_DATE SUM_Crime   RealDate                 Period1
# 1        1 Northwestern Not in Zone       2019  2/6/2019         4 2019-02-06 2019-02-06 - 2019-02-09
# 2        2 Northwestern     Zone 30       2019  2/7/2019         6 2019-02-07 2019-02-06 - 2019-02-09
# 3        3 Northwestern     Zone 40       2019  2/8/2019         5 2019-02-08 2019-02-06 - 2019-02-09
# 4        4 Northwestern     Zone 30       2019  2/9/2019         2 2019-02-09 2019-02-09 - 2019-02-12
# 5        5 Northwestern Not in Zone       2019 2/10/2019         4 2019-02-10 2019-02-09 - 2019-02-12
# 6        6 Northwestern     Zone 40       2019 2/11/2019         4 2019-02-11 2019-02-09 - 2019-02-12
# 7        7 Northwestern     Zone 30       2019 2/12/2019         0 2019-02-12 2019-02-12 - 2019-02-15

如果您想保留日期格式(在 R 中不是真正的 Dates),那么我们可以为该格式添加第二列:

datevec2 <- format(datevec, format = "%m/%d/%Y")
dat$Period2 <- cut(dat$RealDate, datevec,
                   labels = paste(datevec2[-length(datevec2)], datevec2[-1], sep = " - "))
dat
#   OBJECTID     District        Zone year_value FROM_DATE SUM_Crime   RealDate                 Period1                 Period2
# 1        1 Northwestern Not in Zone       2019  2/6/2019         4 2019-02-06 2019-02-06 - 2019-02-09 02/06/2019 - 02/09/2019
# 2        2 Northwestern     Zone 30       2019  2/7/2019         6 2019-02-07 2019-02-06 - 2019-02-09 02/06/2019 - 02/09/2019
# 3        3 Northwestern     Zone 40       2019  2/8/2019         5 2019-02-08 2019-02-06 - 2019-02-09 02/06/2019 - 02/09/2019
# 4        4 Northwestern     Zone 30       2019  2/9/2019         2 2019-02-09 2019-02-09 - 2019-02-12 02/09/2019 - 02/12/2019
# 5        5 Northwestern Not in Zone       2019 2/10/2019         4 2019-02-10 2019-02-09 - 2019-02-12 02/09/2019 - 02/12/2019
# 6        6 Northwestern     Zone 40       2019 2/11/2019         4 2019-02-11 2019-02-09 - 2019-02-12 02/09/2019 - 02/12/2019
# 7        7 Northwestern     Zone 30       2019 2/12/2019         0 2019-02-12 2019-02-12 - 2019-02-15 02/12/2019 - 02/15/2019

从这里开始,基础 R 聚合:

ag <- aggregate(SUM_Crime ~ Zone + Period2, data = dat, FUN = sum)
ag
#          Zone                 Period2 SUM_Crime
# 1 Not in Zone 02/06/2019 - 02/09/2019         4
# 2     Zone 30 02/06/2019 - 02/09/2019         6
# 3     Zone 40 02/06/2019 - 02/09/2019         5
# 4 Not in Zone 02/09/2019 - 02/12/2019         4
# 5     Zone 30 02/09/2019 - 02/12/2019         2
# 6     Zone 40 02/09/2019 - 02/12/2019         4
# 7     Zone 30 02/12/2019 - 02/15/2019         0
xtabs( SUM_Crime ~ Zone + Period2, data = ag)
#              Period2
# Zone          02/06/2019 - 02/09/2019 02/09/2019 - 02/12/2019 02/12/2019 - 02/15/2019
#   Not in Zone                       4                       4                       0
#   Zone 30                           6                       2                       0
#   Zone 40                           5                       4                       0

如果您愿意,也可以将其放入 dplyr 管道中:

library(dplyr)
library(tidyr) # pivot_wider
dat2 <- dat %>%
  mutate(RealDate = as.Date(FROM_DATE, format = "%m/%d/%Y"))
datevec <- seq(min(dat2$RealDate), max(dat2$RealDate) + 3, by = 3)
dat2 %>%
  mutate(
    Period1 = cut(RealDate, datevec,
                  labels = paste(datevec[-length(datevec)], datevec[-1], sep = " - "))
  ) %>%
  group_by(Zone, Period1) %>%
  summarize(SUM_Crime = sum(SUM_Crime)) %>%
  ungroup() %>%
  filter(SUM_Crime > 0) %>%  
  pivot_wider(., "Zone", names_from = "Period1", values_from = "SUM_Crime")
# # A tibble: 3 x 3
#   Zone        `2019-02-06 - 2019-02-09` `2019-02-09 - 2019-02-12`
#   <chr>                           <int>                     <int>
# 1 Not in Zone                         4                         4
# 2 Zone 30                             6                         2
# 3 Zone 40                             5                         4

数据

dat <- read.csv(header = TRUE, stringsAsFactors = FALSE, text = "
OBJECTID,District,Zone,year_value,FROM_DATE,SUM_Crime
1,Northwestern,Not in Zone,2019,2/6/2019,4
2,Northwestern,Zone 30,2019,2/7/2019,6
3,Northwestern,Zone 40,2019,2/8/2019,5
4,Northwestern,Zone 30,2019,2/9/2019,2
5,Northwestern,Not in Zone,2019,2/10/2019,4
6,Northwestern,Zone 40,2019,2/11/2019,4
7,Northwestern,Zone 30,2019,2/12/2019,0")

【讨论】:

  • 谢谢!这很棒。现在,如果对 ag
  • 你试过SUM_Crime ~ District + Zone + Period2吗?
  • 这有重叠吗?我希望日期分组是互斥的。
  • cut 不重叠。
  • 我将如何调整此过程以便将 Period 存储桶标记为互斥,以及如何翻转该过程以便 Period 组中的第一个日期不决定 RealDate 的放置位置,但最后一个确实如此。我希望分组中的最终日期是该期间的最终 RealDate 值所在的位置。
【解决方案2】:

一种方法可能是从第一个日期开始计算 3 天的 Period。可以在这 3 天的 firstlast 之间计算出 Date_Range。然后pivot_wider 会将数据变成长格式。

library(tidyverse)

df2 <- df %>%
  group_by(Period = rep(row_number(), length.out = n(), each = 3)) %>%
  mutate(Date_Range = paste(first(FROM_DATE), "-", last(FROM_DATE))) %>%
  pivot_wider(id_cols = c(District, Zone), names_from = Date_Range, values_from = SUM_Crime) 

然后要放入逗号分隔的格式,可以添加:

cat(format_csv(df2))

输出

District,Zone,2/6/2019 - 2/8/2019,2/9/2019 - 2/11/2019,2/12/2019 - 2/12/2019
Northwestern,Not in Zone,4,4,NA
Northwestern,Zone 30,6,2,0
Northwestern,Zone 40,5,4,NA

【讨论】:

    【解决方案3】:

    代码:

    library('data.table')
    setDT(df)[, FROM_DATE := as.Date(FROM_DATE, "%m/%d/%y")]
    date_seq <- seq(from = as.Date("2020-02-06"), to =max(df$FROM_DATE), by = 3)
    
    df1 <- df[FROM_DATE >= as.Date("2020-02-06"), .(Zone, SUM_Crime, 
                                                    DATE_INTERVAL = paste0(date_seq[findInterval(x = FROM_DATE, vec = date_seq)], " - ",
                                                                           date_seq[findInterval(x = FROM_DATE, vec = date_seq)]+2)), 
              by = .(District)]
    dcast(df1, Zone + District ~ DATE_INTERVAL, value.var = 'SUM_Crime', fill = NA)
    #           Zone     District 2020-02-06 - 2020-02-08 2020-02-09 - 2020-02-11 2020-02-12 - 2020-02-14
    # 1: Not in Zone Northwestern                       4                       4                      NA
    # 2:     Zone 30 Northwestern                       6                       2                       0
    # 3:     Zone 40 Northwestern                       5                       4                      NA
    

    数据:

    df <- read.table(text='OBJECTID,District,Zone,year_value,FROM_DATE,SUM_Crime
    1,Northwestern,Not in Zone,2019,2/6/2019,4
                     2,Northwestern,Zone 30,2019,2/7/2019,6
                     3,Northwestern,Zone 40,2019,2/8/2019,5
                     4,Northwestern,Zone 30,2019,2/9/2019,2
                     5,Northwestern,Not in Zone,2019,2/10/2019,4
                     6,Northwestern,Zone 40,2019,2/11/2019,4
                     7,Northwestern,Zone 30,2019,2/12/2019,0', header = TRUE, stringsAsFactors = FALSE, sep = ",")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-17
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      • 2022-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多