Pandas: 计算入住日期和退房日期之间入住率的有效方法
Pandas: Efficient ways to calculate occupancy rate between check-in and check-out dates
我有以下玩具数据
a = pd.DataFrame({"chkin": ["2022-05-22", "2022-05-22", "2022-05-23", "2022-05-24"],
"chkout": ["2022-05-25", "2022-05-23", "2022-05-26", "2022-05-27"],
"rtype": ["A", "A", "A", "A"],
"nbooked": [1, 2, 3, 1],
"nrooms": [10, 10, 10, 10]})
b = pd.DataFrame({"chkin": ["2022-05-22", "2022-05-23", "2022-05-23", "2022-05-24"],
"chkout": ["2022-05-24", "2022-05-26", "2022-05-24", "2022-05-25"],
"rtype": ["B", "B", "B", "B"],
"nbooked": [2, 1, 1, 3],
"nrooms": [12, 12, 12, 12]})
booking = pd.concat([a, b], axis=0, ignore_index=True, sort=False)
booking["chkin"] = pd.to_datetime(booking["chkin"])
booking["chkout"] = pd.to_datetime(booking["chkout"])
我的问题如下图解释
nbooked
指的是预订房间的数量。日历上的每个颜色条代表输入数据的每一行。我想计算从最早入住日期到最后入住日期的每一天的入住率。 (假设每种房型的入住率为零)。
因为每天都可以办理入住和退房,如日历所示。直接组合 nbooked
不应该保证得到正确答案。我可以建议如何有效地计算
您可以创建一个日期范围,然后展开它,让您可以对每一天进行分组和求和。如果您的 DataFrame 很长,则创建日期范围和展开会有点慢。
这也只会在输出中为您提供入住率 non-zero 的日期。如果您还需要零,reindex
覆盖您关心的日期列表。
booking['chkout_2'] = booking.chkout - pd.offsets.DateOffset(days=1)
booking['date'] = booking.apply(lambda r: pd.date_range(r.chkin, r.chkout_2, freq='D'), axis=1)
res = (booking.set_index(['rtype', 'nbooked', 'nrooms'])
.explode('date')
.reset_index()
.groupby(['rtype', 'date'])
.agg({'nbooked': 'sum', 'nrooms': 'max'}))
res['occ'] = res['nbooked']/res['nrooms']
print(res)
nbooked nrooms occ
rtype date
A 2022-05-22 3 10 0.300000
2022-05-23 4 10 0.400000
2022-05-24 5 10 0.500000
2022-05-25 4 10 0.400000
2022-05-26 1 10 0.100000
B 2022-05-22 2 12 0.166667
2022-05-23 4 12 0.333333
2022-05-24 4 12 0.333333
2022-05-25 1 12 0.083333
如果您有一小部分与每个 'rtype'
相关的日期,另一个选项可能会更高效,它是对所有日期进行交叉连接,然后过滤到您关心的行关于。输出与上面相同。
# Daily df of relevant dates
df_dates = pd.DataFrame({'date': pd.date_range('2022-05-22', '2022-05-25', freq='D')})
res = (booking.merge(df_dates, how='cross')
.query('date >= chkin & date < chkout')
.groupby(['rtype', 'date'])
.agg({'nbooked': 'sum', 'nrooms': 'max'}))
res['occ'] = res['nbooked']/res['nrooms']
我有以下玩具数据
a = pd.DataFrame({"chkin": ["2022-05-22", "2022-05-22", "2022-05-23", "2022-05-24"],
"chkout": ["2022-05-25", "2022-05-23", "2022-05-26", "2022-05-27"],
"rtype": ["A", "A", "A", "A"],
"nbooked": [1, 2, 3, 1],
"nrooms": [10, 10, 10, 10]})
b = pd.DataFrame({"chkin": ["2022-05-22", "2022-05-23", "2022-05-23", "2022-05-24"],
"chkout": ["2022-05-24", "2022-05-26", "2022-05-24", "2022-05-25"],
"rtype": ["B", "B", "B", "B"],
"nbooked": [2, 1, 1, 3],
"nrooms": [12, 12, 12, 12]})
booking = pd.concat([a, b], axis=0, ignore_index=True, sort=False)
booking["chkin"] = pd.to_datetime(booking["chkin"])
booking["chkout"] = pd.to_datetime(booking["chkout"])
我的问题如下图解释
nbooked
指的是预订房间的数量。日历上的每个颜色条代表输入数据的每一行。我想计算从最早入住日期到最后入住日期的每一天的入住率。 (假设每种房型的入住率为零)。
因为每天都可以办理入住和退房,如日历所示。直接组合 nbooked
不应该保证得到正确答案。我可以建议如何有效地计算
您可以创建一个日期范围,然后展开它,让您可以对每一天进行分组和求和。如果您的 DataFrame 很长,则创建日期范围和展开会有点慢。
这也只会在输出中为您提供入住率 non-zero 的日期。如果您还需要零,reindex
覆盖您关心的日期列表。
booking['chkout_2'] = booking.chkout - pd.offsets.DateOffset(days=1)
booking['date'] = booking.apply(lambda r: pd.date_range(r.chkin, r.chkout_2, freq='D'), axis=1)
res = (booking.set_index(['rtype', 'nbooked', 'nrooms'])
.explode('date')
.reset_index()
.groupby(['rtype', 'date'])
.agg({'nbooked': 'sum', 'nrooms': 'max'}))
res['occ'] = res['nbooked']/res['nrooms']
print(res)
nbooked nrooms occ
rtype date
A 2022-05-22 3 10 0.300000
2022-05-23 4 10 0.400000
2022-05-24 5 10 0.500000
2022-05-25 4 10 0.400000
2022-05-26 1 10 0.100000
B 2022-05-22 2 12 0.166667
2022-05-23 4 12 0.333333
2022-05-24 4 12 0.333333
2022-05-25 1 12 0.083333
如果您有一小部分与每个 'rtype'
相关的日期,另一个选项可能会更高效,它是对所有日期进行交叉连接,然后过滤到您关心的行关于。输出与上面相同。
# Daily df of relevant dates
df_dates = pd.DataFrame({'date': pd.date_range('2022-05-22', '2022-05-25', freq='D')})
res = (booking.merge(df_dates, how='cross')
.query('date >= chkin & date < chkout')
.groupby(['rtype', 'date'])
.agg({'nbooked': 'sum', 'nrooms': 'max'}))
res['occ'] = res['nbooked']/res['nrooms']