У меня есть Pandas фрейм данных, df
. Вот первые пять строк:
Id StartDate EndDate
0 0 2015-08-11 2018-07-13
1 1 2014-02-15 2016-01-25
2 2 2014-12-20 NaT
3 3 2015-01-09 2015-01-14
4 4 2014-07-20 NaT
Я хочу создать новый фрейм данных, df2
. У df2
должна быть строка для каждого месяца от StartDate
до EndDate
включительно, для каждого Id
в df1
. Например, поскольку первая строка df1
имеет StartDate
в августе 2015 года и EndDate
в июле 2018 года, в df2
должны быть строки, соответствующие августу 2015 года, сентябрю 2015 года, ..., июлю 2018. Если значение Id
в df1
не имеет EndDate
, мы примем его за июнь 2019 года.
Я бы хотел df2
использовать мультииндекс с первым уровнем, соответствующим Id
в df1
второй уровень - год, а третий уровень - месяц. Например, если все вышеперечисленные пять строк были df1
, то df2
должно выглядеть следующим образом:
Id Year Month
0 2015 8
9
10
11
12
2016 1
2
3
4
5
6
7
8
9
10
11
12
2017 1
2
3
4
5
6
7
8
9
10
11
12
2018 1
... ... ...
4 2017 1
2
3
4
5
6
7
8
9
10
11
12
2018 1
2
3
4
5
6
7
8
9
10
11
12
2019 1
2
3
4
5
6
Следующий код справляется с задачей, но на моем приличном ноутбуке занимает около 20 секунд за 10 тыс. Id
s. Могу ли я быть более эффективным как-то?
import numpy as np
def build_multiindex_for_id_(id_, enroll_month, enroll_year, cancel_month, cancel_year):
# Given id_ and start/end dates,
# returns 2d array to be converted to multiindex.
# Each row of returned array represents a month/year
# between enroll date and cancel date inclusive.
year = enroll_year
month = enroll_month
multiindex_array = [[],[],[]]
while (month != cancel_month) or (year != cancel_year):
multiindex_array[0].append(id_)
multiindex_array[1].append(year)
multiindex_array[2].append(month)
month += 1
if month == 13:
month = 1
year += 1
multiindex_array[0].append(id_)
multiindex_array[1].append(year)
multiindex_array[2].append(month)
return np.array(multiindex_array)
# Begin by constructing array for first id.
array_for_multiindex = build_multiindex_for_id_(0,8,2015,7,2018)
# Append the rest of the multiindices for the remaining ids.
for _, row in df.loc[1:].fillna(pd.to_datetime('2019-06-30')).iterrows():
current_id_array = build_multiindex_for_id_(
row['Id'],
row['StartDate'].month,
row['StartDate'].year,
row['EndDate'].month,
row['EndDate'].year)
array_for_multiindex = np.append(array_for_multiindex, current_id_array, axis=1)
df2_index = pd.MultiIndex.from_arrays(array_for_multiindex).rename(['Id','Year','Month'])
pd.DataFrame(index=df2_index)