逐行执行操作时处理不同列中的值

时间:2019-04-24 12:16:18

标签: r dataframe dplyr

我有一些包含酒店客房预订信息的数据,看起来像下面的示例:

   user_id h_name h_capacity check_in_date check_out_date
         1     A1          2    2019-01-01     2019-01-05
         2     A1          2    2019-01-02     2019-01-05
         3     A1          2    2019-01-02     2019-01-03
         4     A2          3    2019-01-02     2019-01-04
         5     A2          3    2019-01-04     2019-01-05

user_id:客户ID

h_name:酒店名称

h_capacity:酒店的最大房间数。

check_in_datecheck_out_date:不言自明。

我的目的是找出哪些酒店正在按规定的容量接待人员。

我尝试的方法涉及到为每个日期创建新列,从而导致上面给出示例数据框。看起来如下:

    <...> 2019-01-01 2019-01-02 2019-01-03 2019-01-04 2019-01-05
    <...>          0          0          0          0          0
    <...>          0          0          0          0          0
    <...>          0          0          0          0          0
    <...>          0          0          0          0          0
    <...>          0          0          0          0          0

<...>表示出现在顶部第一个数据框中的列。

完成上述操作后,我想将数字1插入用户在酒店居住的日期的列中,结果如下所示:

    <...> 2019-01-01 2019-01-02 2019-01-03 2019-01-04 2019-01-05
    <...>          1          1          1          1          1
    <...>          0          1          1          1          1
    <...>          0          1          1          0          0
    <...>          0          1          1          1          0
    <...>          0          0          0          1          1

<...>代表显示在顶部示例中的列。

最后,我只需要在h_name上使用summary来获取每天的床位总数。

问题是我无法在该人已占用房间的日期列中用值1填充上面显示的数据框。 这涉及将值填充到每一行的不同列中,这意味着对于用户而言,我需要将1插入代表他们在酒店停留日期的列中。并没有找到最佳解决方案,最终使用了for循环来执行,该循环耗时32分钟。

我为此谦虚地寻求最佳解决方案。 (请注意:数据有50万行)

1 个答案:

答案 0 :(得分:3)

我没有遵循您的方法,但这可以解决您的问题。注意:我假设酒店的容量会随着时间的推移而保持不变,并且退房日期将像您在示例中一样计为床位。

library(tidyverse)

hotel_data %>% 
  gather(check_in, date, check_in_date, check_out_date) %>% 
  group_by(h_name, h_capacity, user_id) %>% 
  complete(date = seq.Date(first(date), last(date), by = "day"), 
           fill = list(check_in = "stay")) %>% 
  group_by(h_name, date) %>% 
  mutate(people = n()) %>% 
  filter(people > h_capacity)

# A tibble: 6 x 6
# Groups:   h_name, date [2]
#   h_name h_capacity user_id date       check_in       people
#   <chr>       <dbl>   <dbl> <date>     <chr>           <int>
# 1 A1              2       1 2019-01-02 stay                3
# 2 A1              2       1 2019-01-03 stay                3
# 3 A1              2       2 2019-01-02 check_in_date       3
# 4 A1              2       2 2019-01-03 stay                3
# 5 A1              2       3 2019-01-02 check_in_date       3
# 6 A1              2       3 2019-01-03 check_out_date      3

说明
首先,我使用gather将您的数据转换为长格式,因为使用complete可以轻松地为每个组(酒店和用户)填写缺少的日期值。然后仅按酒店和日期分组,我计算人数,然后按超出人数的人数筛选。

数据

hotel_data <- structure(list(user_id = c(1, 2, 3, 4, 5), 
                             h_name = c("A1", "A1", "A1", "A2", "A2"), 
                             h_capacity = c(2, 2, 2, 3, 3), 
                             check_in_date = structure(c(17897, 17898, 17898, 17898, 17900), class = "Date"), 
                             check_out_date = structure(c(17901, 17901, 17899, 17900, 17901), class = "Date")), 
                        class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -5L))