【问题标题】:Counting Number of People in a Hotel (R)计算酒店的人数 (R)
【发布时间】:2021-11-10 22:04:18
【问题描述】:

我正在使用 R 编程语言。假设有一家酒店有一个客户列表,上面有他们的入住和退房时间(注:日期的实际值是“POSIXct”,写成“年-月-日”。):

check_in_date <- c('2010-01-01', '2010-01-02' ,'2010-01-01', '2010-01-08', '2010-01-08', '2010-01-15', '2010-01-15', '2010-01-16', '2010-01-19', '2010-01-22')
check_out_date <- c('2010-01-07', '2010-01-04' ,'2010-01-09', '2010-01-21', '2010-01-11', '2010-01-22', 'still in hotel as of today', '2010-01-20', '2010-01-25', '2010-01-29')
Person = c("John", "Smith", "Alex", "Peter", "Will", "Matt", "Tim", "Kevin", "Tom", "Adam")

hotel <- data.frame(check_in_date, check_out_date, Person )

数据看起来像这样:

   check_in_date             check_out_date Person
1     2010-01-01                 2010-01-07   John
2     2010-01-02                 2010-01-04  Smith
3     2010-01-01                 2010-01-09   Alex
4     2010-01-08                 2010-01-21  Peter
5     2010-01-08                 2010-01-11   Will
6     2010-01-15                 2010-01-22   Matt
7     2010-01-15 still in hotel as of today    Tim
8     2010-01-16                 2010-01-20  Kevin
9     2010-01-19                 2010-01-25    Tom
10    2010-01-22                 2010-01-29   Adam

问题:我试图在任何一天找出酒店里还有多少人。这看起来像这样(只是一个例子,与上述数据不对应):

  day_of_the_year Number_of_people_currently_in_hotel
1      2010-01-01                                   1
2      2010-01-02                                   1
3      2010-01-03                                   2
4      2010-01-04                                   0
5      2010-01-05                                   5
6      2010-01-06                                   5
7      2010-01-07                                   2
8      2010-01-08                                   2
9      2010-01-09                                   8

我尝试通过 3 个步骤解决此问题:

第一步:我生成了一个包含从开始到结束的每个日期的列(例如,在本例中,假设有 31 天:从 2010 年 1 月开始到结束)

day_of_the_year = seq(as.Date("2010/1/1"), as.Date("2010/1/31"),by="day")

第二步:然后我确定了每天入住酒店的人数:

library(dplyr)

#create some indicator variable 
hotel$event = 1

check_ins = hotel %>% group_by(check_in_date) %>%   summarise(n = n())

 check_in_date     n
  <chr>         <int>
1 2010-01-01        2
2 2010-01-02        1
3 2010-01-08        2
4 2010-01-15        2
5 2010-01-16        1
6 2010-01-19        1
7 2010-01-22        1

第三步:然后我重复了类似的步骤来确定每天有多少人退房:

check_outs = hotel %>% group_by(check_out_date) %>%   summarise(n = n())

   check_out_date                 n
   <chr>                      <int>
 1 2010-01-04                     1
 2 2010-01-07                     1
 3 2010-01-09                     1
 4 2010-01-11                     1
 5 2010-01-20                     1
 6 2010-01-21                     1
 7 2010-01-22                     1
 8 2010-01-25                     1
 9 2010-01-29                     1
10 still in hotel as of today     1

问题:现在,我不知道如何将上述 3 个步骤组合起来,以便我们可以了解每月每天有多少人入住酒店。有人可以告诉我怎么做吗?

谢谢!

注意:我发现了一个“类似”问题counting the number of people in the system in R,我目前正在尝试查看是否可以针对我的问题调整此问题中使用的方法。

【问题讨论】:

    标签: r dplyr group-by count data-manipulation


    【解决方案1】:

    我使用hotel$check_in_date = as.Date(hotel$check_in_date) 和hotel$check_out_date = as.Date(hotel$check_out_date) 将字符串转换为日期。然后,此功能将计算给定日期的客人数量。由于您为当前登记入住的客人提供了备注,因此我在函数中创建了一个临时数据框以避免覆盖原始数据。

    count_guests = function(date) {
      temp = hotel
      temp$check_out_date = ifelse(is.na(temp$check_out_date), as.Date(date), temp$check_out_date)
      counts = ifelse((temp$check_in_date <= date) &(temp$check_out_date >= date), 1, 0)
      return(sum(counts))
    }
    
    count_guests(as.Date("2010-01-02"))
    [1] 3
    
    count_guests(as.Date("2010-01-10"))
    [1] 2
    
    count_guests(as.Date("2010-01-21"))
    [1] 4
    

    编辑:再三考虑,您似乎想要一个新的数据框。这可以通过apply() 轻松完成。

    guests = data.frame(day_of_the_year = seq(as.Date("2010/1/1"), as.Date("2010/1/31"),by="day"))
    guests$num_checked_in = lapply(guests$day_of_the_year, FUN = count_guests)
    
     day_of_the_year num_checked_in
    1       2010-01-01              2
    2       2010-01-02              3
    3       2010-01-03              3
    4       2010-01-04              3
    5       2010-01-05              2
    ...
    

    【讨论】:

    • 感谢您的回答!假设“今天仍在酒店”被替换为 2010-01-31。这会让事情变得更容易吗?
    • 数据框中不会有要处理的NA,但如果日期延长到 2 月,则会提前签出。
    【解决方案2】:

    我认为这可能会有所帮助,但对于一个完整的解决方案,我们需要为那些尚未检查 ou 的人提供一个参考日期

    library(tidyverse)
    
    hotel %>% 
      mutate(
        across(.cols = ends_with("_date"),.fns = ymd),
        check_out_date = if_else(is.na(check_out_date), today(),check_out_date) 
        ) %>% 
      mutate(
        date = map2(
          .x = check_in_date,
          .y = check_out_date,
          .f = function(x,y)seq.Date(from = x,to = y,by = "1 day"))
      ) %>% 
      unnest() %>% 
      count(date)
    
    # A tibble: 29 x 2
       date           n
       <date>     <int>
     1 2010-01-01     2
     2 2010-01-02     3
     3 2010-01-03     3
     4 2010-01-04     3
     5 2010-01-05     2
     6 2010-01-06     2
     7 2010-01-07     2
     8 2010-01-08     3
     9 2010-01-09     3
    10 2010-01-10     2
    # ... with 19 more rows
    

    【讨论】:

    • 感谢您的回答!假设“今天仍在酒店”被替换为 2010-01-31。这会让事情变得更容易吗?
    【解决方案3】:

    您可以尝试使用我认为是 tidyverse 的一部分的“lubridate”包。因此,如果加载 tidyverse,您不必再次加载 lubridate。

    使用 ymd 将字符转换为日期,因为年-月-日是您的日期格式。

    dt <- tibble(checkin = lubridate::ymd(check_in_date),
    checkout = lubridate::ymd(check_out_date),
    person = Person)
    

    对于尚未结帐的任何人,使用 today() 函数为其分配今天的结帐日期。或者,如果您知道收集此数据的日期,这可能是在此处指定的另一个合理日期。

    创建以签入日期开始并以签出日期结束的间隔对象。 同样为要检查的日期创建间隔对象。这里我使用的是 2010-01-07。 使用 int_overlap() 查找重叠

    dt<- dt %>% mutate(
    checkout = replace_na(checkout, today()),
    stay_interval = lubridate::interval(start = checkin, end = checkout),
    date_of_interest = lubridate::interval(ymd("2010-01-07"), ymd("2010-01-07")),
    stay = lubridate::int_overlaps(date_of_interest, stay_interval)
    )
    dt %>% count(stay)
    
    # A tibble: 2 x 2
      stay      n
      <lgl> <int>
    1 FALSE     8
    2 TRUE      2
    

    【讨论】:

      猜你喜欢
      • 2022-11-11
      • 1970-01-01
      • 2016-01-28
      • 1970-01-01
      • 2012-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多