我有一个数据帧(df),其中包含如下数据(仅提供一行):
df_raw_data = pd.DataFrame(data = {'checkin':datetime.date(2019, 01, 01),
'checkout':datetime.date(2019, 01, 05), 'booking_id':1234, 'tag':'A', 'rooms':2}, index = [0])
我想编写一个代码块,该代码块读取df_raw_data的每一行并创建一个新的df_split_data,该数据将df_raw_data的每一行如下:
df_split_data = pd.DataFrame(data = {'date':[datetime.date(2019, 01, 01), datetime.date(2019, 01, 02), datetime.date(2019, 01, 03), datetime.date(2019, 01, 04)], 'checkin':[datetime.date(2019, 01, 01), datetime.date(2019, 01, 01), datetime.date(2019, 01, 01), datetime.date(2019, 01, 01)], 'checkout':[datetime.date(2019, 01, 05), datetime.date(2019, 01, 05), datetime.date(2019, 01, 05), datetime.date(2019, 01, 05)], 'booking_id':[1234, 1234, 1234, 1234], 'tag':['A', 'A', 'A', 'A'], 'rooms':[2, 2, 2, 2]})
基本上,每次预订都应划分为天数=(结帐-签到),并以新列的形式获取日期,而其他列则保持完全相同。
我尝试使用如下所示的for循环进行此操作
df_split_data = pd.DataFrame()
for i in range(len(df_raw_data)):
df_1 = df_raw_data[i:i+1]
df_1.reset_index(inplace = True)
checkin_date = df_1['checkin'][0]
checkout_date = df_1['checkout'][0]
rooms = df_1['rooms'][0]
booking_id = df_1['booking_id'][0]
tag = df_1['tag'][0]
los = df_1['los'][0]
#los is a column which checkout - checkin in days
datelist = pd.date_range(checkin_date, periods=los).tolist()
datelist = [x.date() for x in datelist]
df_2 = pd.DataFrame(data = {'date':datelist})
df_2['checkin'] = checkin_date
df_2['checkout'] = checkout_date
df_2['rooms'] = rooms
df_2['booking_id'] = booking_id
df_2['tag'] = tag
df_split_data = df_split_data.append(df_2)
这样做可以得到正确的结果,但是当有200万个以上的条目时,执行将花费很长时间。
是否有更有效的方法?
答案 0 :(得分:1)
这是将index.repeat
与DataFrame.loc
和pandas.to_timedelta
一起创建扩展的DataFrame,然后使用groupby.cumcount
和{{3}}来更新date
列中的值的一种方法:
df_split_data = df_raw_data.loc[
df_raw_data.index.repeat(
(df_raw_data['checkout'] - df_raw_data['checkin']).dt.days + 1)]
df_split_data['date'] = (pd.to_datetime(df_split_data['date']) +
pd.to_timedelta(df_split_data.groupby(df_split_data.columns.tolist()).cumcount(), unit='d'))
[出]
checkin checkout booking_id tag rooms date
0 2019-01-01 2019-01-05 1234 A 2 2019-01-01
0 2019-01-01 2019-01-05 1234 A 2 2019-01-02
0 2019-01-01 2019-01-05 1234 A 2 2019-01-03
0 2019-01-01 2019-01-05 1234 A 2 2019-01-04
0 2019-01-01 2019-01-05 1234 A 2 2019-01-05