我正在使用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
我试着用三步来解决这个问题:
:我生成了一个包含从开始到结束的每个日期的列(例如,在本例中,让我们假设有31天:从1月开始到1月结束-2010)
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个步骤结合起来,这样我们就可以知道这个月每天有多少人住在这家酒店。有人能告诉我怎么做吗?
谢谢!
注意:我发现了一个"相似"在R中计算系统中的人数,我目前正在尝试看看我是否可以将这个问题中使用的方法用于我的问题。
我使用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
...
我认为这可能会有所帮助,但对于一个完整的解决方案,我们需要一个参考日期,为那些还没有检查出
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
您可以尝试使用"包裹,我相信是tidyverse的一部分。因此,如果加载了tidyverse,就不必再加载润滑油了。
使用ymd将字符转换为日期,因为年-月-日是您的日期格式。
dt <- tibble(checkin = lubridate::ymd(check_in_date),
checkout = lubridate::ymd(check_out_date),
person = Person)
对于尚未结帐的人,使用today()函数为他们指定今天的结帐日期。或者,如果您知道收集此数据的日期,则可以在这里分配另一个合理的日期。
创建起始日期为签入日期,结束日期为签出日期的间隔对象。类似地,为您想要检查的日期创建interval对象。这里我用的是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