Хотел бы сделать это кратким, но должен убедиться, что вы понимаете, как я это сделал. Давайте узнаем, если мы вас неправильно поняли.
Кадр данных
df=pd.DataFrame({'Tranc':['begin', 'end', 'begin', 'end', 'begin', 'end', 'begin', 'end', 'begin', 'end'], 'lapse':[-1.0, -1.0, -42.0, -15.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0],'start':['2019-10-25 09:39:39.914889', '2019-10-25 09:41:09.103102', '2019-10-25 10:39:58.352073', '2019-10-25 10:40:06.266782', '2019-10-25 16:35:22.485574', '2019-10-27 09:50:31.713192', '2019-10-28 14:04:33.095633', '2019-10-28 14:05:07.639344', ' 2019-10-28 14:13:07.924966', '2019-10-28 14:13:08.888890']})
Приведите дату к дате и установите дату начала как индекс
df['start']=pd.to_datetime(df['start'])
df.set_index('start', inplace=True)
Рассчитайте разницу во времени, чтобы определить 1 день различия
df['dayofMonth']=df.index.day
df['lapse']=df.dayofMonth.diff().fillna(0)
df.reset_index(inplace=True)
Вставить строки, в которых есть разность дней
k = df.index[df.lapse >=1]
insertdata= pd.DataFrame({'lapse':[-1]})
df2= pd.DataFrame(insertdata.values.tolist() * len(k),
columns=insertdata.columns, index=k-1)
res = pd.concat([df, df2]).sort_index().reset_index(drop=True)
Переслать Вставка обратной засыпки , чтобы мы могли решить проблемы с существующими датами и подготовьте df
для заполнения пропущенных дат
res.Tranc=res.Tranc.bfill()
res.start=res.start.ffill()
res.sort_values(by='Tranc', ascending=True)
res
Дни запроса вставлены и маска
m=(res['lapse']==-1.0) & (res['Tranc']=='end')
mask=(res['lapse']==-1.0) & (res['Tranc']=='begin')
Отредактируйте вставленные конечные часы начала
res.loc[m, 'start']= res.loc[m, 'start'].apply(lambda x: x.replace(hour=17, minute=0))
res.loc[mask, 'start']= res.loc[mask, 'start'].apply(lambda x: x.replace(hour=8, minute=0))
res.drop(columns=['lapse'], inplace=True)
res.sort_values(by='start')
Часть вторая Вставьте недостающие даты и при необходимости укажите их. Обратите внимание, что я выбрал время начала 7:00
и время окончания 17:00
, чтобы упростить сортировку, а также с учетом того, что мы заполняем только даты. Вы можете изменить, если требуется.
Преобразовать res и перевести его на следующую фазу.
res2=res
res2
res2.set_index(res2['start'], inplace=True)
res2.drop(columns=['start'],inplace=True)
#df['dates']=df.index.date
res2.reset_index(inplace=True)
res2.set_index('start', inplace=True)
res2['lapse']=0
res2
Вставить пропущенные даты, сохраняя дубликаты
s = pd.Series(np.nan, index=pd.date_range(res2.index.min(), res2.index.max(), freq='D'))
df2=pd.concat([res2,s[~s.index.isin(res2.index)]]).sort_index()
df2.lapse.fillna(1, inplace=True)#Fill lapse with 1, so that can use that in df.repeat to replicate rows
df2.drop(columns=0, inplace=True)#default column, get rid of it
df2
Для вставленных строк: повторить их. Я использую целое число в промежутке, чтобы указать, сколько раз каждый индекс может быть реплицирован, и сохранить реплики в новом df3.
df3=df2.loc[df2.index.repeat(df2.lapse)]
df3
Concat df2
и df3
в новом временном файле df res3
res3 = pd.concat([df2, df3]).sort_index().reset_index(drop=False)
res3.rename(columns={'index':'start'}, inplace=True)
res3
Введите новый столбец, в который я вставляю шаблон 1 2, 1; начало и 2; конец для более позднего использования
res3['TrancRecalibration']=0
np.put(res3['TrancRecalibration'], np.arange(len(res3)), [1,2])
res3
Выберите все строки с помощью Tran c, что означает, что они имеют уже был установлен на этапе 1 в df4
и сбрасывает индекс, чтобы мы могли использовать его для последующего сопоставления
df4=res3[res3['Tranc'].notna()]
df4.set_index('start', inplace=True)
df4['Date']=df4.index.date
df4.reset_index(inplace=True)
df4.set_index('Date', inplace=True)
df4
Выберите недавно вставленные отсутствующие даты
df5=res3[res3['Tranc'].isna()]
df5['TrancRecalibration']=0
np.put(df5['TrancRecalibration'], np.arange(len(df5)), [1,2])
df5
маска df5 для изоляции TrancRecalibration
(1 или 2) означает начало или конец и приписывает Tranc
n=df5['TrancRecalibration']==1
l=df5['TrancRecalibration']==2
df5['Tranc']=np.where(n,'begin','end')
Установите время начала и окончания на 7:00 и 17:00 соответственно
df5.loc[n, 'start']= df5.loc[n, 'start'].apply(lambda x: x.replace(hour=7, minute=00))
df5.loc[l, 'start']= df5.loc[l, 'start'].apply(lambda x: x.replace(hour=17, minute=0))
сбросить индекс для df5
, чтобы его можно было объединить в df4
df5.set_index('start', inplace=True)
df5['Date']=df5.index.date
df5.reset_index(inplace=True)
df5.set_index('Date', inplace=True)
df5
Concat df4
и df5
в результате
result = pd.concat([df4, df5]).sort_index().reset_index(drop=True).sort_values(by='start')
result
Выход
![enter image description here](https://i.stack.imgur.com/JKaW8.png)
После вашего запроса ограничить время начала до 7 утра в случае вставки строки. Вы можете использовать следующее для последовательного удаления begin begin
и end end
подряд
Определение шаблонов
pattern1=['begin', 'begin']
Удаление первых появлений в последовательности шаблонов ['begin', 'begin']
p1=(result.Tranc==pattern1[0])&(result["Tranc"].shift(-1)==pattern1[1])
# p1 indicates the first begin in a pettern of begin begin
result2=result[~p1]# drops the first begin in a pattern of begin begin
Повторите вышеуказанный шаг, но на этот раз сбросьте последнюю запись в шаблоне последовательности ['end', 'end']
pattern2=['end', 'end']
p2=(result2.Tranc==pattern2[1])&(result2["Tranc"].shift(1)==pattern2[0])
result2[~p2].sort_values(by='start')
Окончательный вывод
![enter image description here](https://i.stack.imgur.com/FBm44.png)
Отсюда приступите и проанализируйте свою недоступность: