计算旅馆中的人数 (R)

Counting Number of People in a Hotel (R)

我正在使用 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个步骤结合起来,这样我们才能知道每天有多少人入住酒店月的。有人可以告诉我怎么做吗?

谢谢!

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

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

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

我使用 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
...

您可以尝试使用“lubridate”包,我相信它是 tidyverse 的一部分。因此,如果加载 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