【问题标题】:Counting observations in each year from a date range in dplyr从 dplyr 中的日期范围计算每年的观察值
【发布时间】:2020-12-16 19:59:57
【问题描述】:

假设我有一个由行业类型以及开始和结束日期组成的 data.frame(例如,对于员工)。

mydf <- data.frame(industry = c("Government", "Education", "Military", "Private Sector", "Government", "Private Sector"),
                   start_date = c("2014-01-01", "2016-02-01", "2012-11-01", "2013-03-01", "2012-12-01", "2011-12-01"),
                   end_date = c("2020-12-01", "2016-10-01", "2014-01-01", "2016-10-01", "2015-10-01", "2014-09-01"))

> mydf
        industry start_date   end_date
1     Government 2014-01-01 2020-12-01
2      Education 2016-02-01 2016-10-01
3       Military 2012-11-01 2014-01-01
4 Private Sector 2013-03-01 2016-10-01
5     Government 2012-12-01 2015-10-01
6 Private Sector 2011-12-01 2014-09-01

我想创建一个堆叠的 ggplot 条形图,其中 start_date 列中的每个唯一年份都在 X 轴上(例如 2011-2016),y 轴表示观察总数(行数) 代表该年的特定行业。

我不确定操作 data.frame 的正确方法是什么。大概我需要操纵数据以具有industryyearcount 的列。但我不确定如何从日期范围生成年份列。有什么想法吗?

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    将日期列转换为Date,使用map2(来自purrr)、unnest@987654328 为每一行创建从“start_date”到“end_date”的“日期”sequence @ 输出,count yeargeom_bar 绘图

    library(dplyr)
    library(tidyr)
    library(purrr)
    library(ggplot2)
    mydf %>%
       mutate(across(c(start_date, end_date), as.Date)) %>% 
       transmute(industry, date = map2(start_date, end_date, seq, by = 'day')) %>% 
       unnest(c(date)) %>% 
       count(industry, year = factor(year(date))) %>%
       ggplot(aes(x = year, y = n, fill = industry)) + 
            geom_col() +
            theme_bw()
    

    如果情节应该为每个“行业”分开

    mydf %>%
       mutate(across(c(start_date, end_date), as.Date)) %>% 
       transmute(industry, date = map2(start_date, end_date, seq, by = 'day')) %>% 
       unnest(c(date)) %>% 
       count(industry, year = factor(year(date))) %>%
       ggplot(aes(x = year, y = n, fill = industry)) + 
            geom_col() + 
            facet_wrap(~ industry) +
            theme_bw()
    

    -输出


    正如@IanCampbell 建议的那样,seqby 可以是'year'

    mydf %>%
       mutate(across(c(start_date, end_date), as.Date)) %>% 
       transmute(industry, date = map2(start_date, end_date, seq, by = 'year')) %>% 
       unnest(c(date)) %>% 
       count(industry, year = factor(year(date))) %>%
       ggplot(aes(x = year, y = n, fill = industry)) + 
            geom_col() + 
            facet_wrap(~ industry) +
            theme_bw()
    

    【讨论】:

    • 你太棒了。我每周都从你那里学到新东西。这是完美的,谢谢!
    • 嗯,我刚刚在我的实际数据集上意识到unnest 步骤大量高估了每个范围内的真实值数,但 Ian 的解决方案效果很好。我不知道为什么它不起作用
    • @Parseltongue 我不确定。但是感谢您分享这些信息
    • 我认为如果你只是将by = 参数更改为seq'year',你应该会很好。
    【解决方案2】:

    这就是你要找的吗? 我建议使用purrr::pmap 根据原始数据的每一行创建一个新的数据框,其中每一年都有一行。

    我们可以使用purrr::pmap_dfr 自动返回一个按行绑定的单个数据框。

    我们可以使用~with(list(...), ) 技巧来按名称引用列。

    然后我们可以使用dplyr::count按列组合计数。然后就很简单了。

    library(dplyr)
    library(purrr)
    library(lubridate)
    library(ggplot)
    mydf %>%
      mutate(across(c(start_date, end_date), as.Date),
             start_year = year(start_date),
             end_year = year(end_date)) %>%
      pmap_dfr(~with(list(...),data.frame(industry,
                                          year = seq(start_year, end_year)))) %>%
      count(year, industry) %>%
    ggplot(aes(x = year, y = n, fill = industry)) + 
      geom_bar(stat="identity")
    

    【讨论】:

    • 这很好! ~with(list(...) 行是如何工作的?
    • with from base R 从第一个参数创建一个环境,在该环境中评估第二个参数。考虑with(mtcars,cyl-mpg)。在这种情况下,... 是由pmap 创建的一组命名参数,其中包括原始数据的每一列。通过这样做,我们可以在第二个参数中按名称引用这些列。考虑pmap_dbl(mtcars,~with(list(...), cyl - mpg))
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多