Как добавить метку времени между двумя указанными c метками времени промышленного оборудования - Python Pandas - PullRequest
0 голосов
/ 23 марта 2020

Я работаю над наличием определенного c оборудования. После нескольких обработок данных у меня наконец есть время в часах недоступности оборудования.

Анализируя мои результаты, я обнаруживаю, что у меня недоступность составляет 41 час в день ... невозможно.

Я наконец нашел проблему, вот два примера:

Date              Unavailability
2019-10-25                 41.47

Flag                       Timestamp
begin         2019-10-25 16:35:22.48
end           2019-10-27 09:50:31.71
begin         2019-10-29 14:04:33.09
end           2019-10-29 14:05:07.63

В примере 1 у меня есть начало, которое начинается 10-25, но заканчивается 27 ..., пока компания закрылась в 5 вечера, чтобы они больше не производили. Но проблема не была решена до 27 в 9:50

Я нашел решение, но мне все еще крайне не хватает опыта работы с метками времени в pandas.

Бизнес открывается в 7:00 утра каждый день и закрывается в 17:00

Строка с флагом «end 2019-10-27» не совпадает дата как строка перед «начало 2019-10-25». Чтобы иметь начало-конец последовательности с той же датой, поэтому мы должны добавить:

Flag                   Timestamp
end       2019-10-25 17:00:00.00
begin     2019-10-27 07:00:00.00

Мы должны добавить дни (ы) ТОЛЬКО Если начало-конец последовательности имеют другую дату , Таким образом, мы делаем различие между днями, 27-25 = 2, и для завершения недоступности требуется дата между началом и концом.

без вставки между последовательностями конца-начала, даже если есть несколько дней. между

Flag                   Timestamp
begin     2019-10-26 07:00:00.00
end       2019-10-26 17:00:00.00

Если мы go вернемся к примеру 1 со сцеплением, это даст:

Date              Unavailability
2019-10-25                 25min
2019-10-26                   10h 
2019-10-27               2h50min 

Flag                     Timestamp
begin       2019-10-25 16:35:22.48
end         2019-10-25 17:00:00.00
begin       2019-10-26 07:00:00.00
end         2019-10-26 17:00:00.00
begin       2019-10-27 07:00:00.00
end         2019-10-27 09:50:31.71
begin       2019-10-29 14:04:33.09
end         2019-10-29 14:05:07.63

С другим примером:

Date              Unavailability
2019-10-21                   10h

Flag                   Timestamp
begin     2019-10-21 15:30:22.48
end       2019-10-22 08:30:31.71

То же отражение сигнал тревоги начинается 2019-10-21 и заканчивается 2019-10-22, поэтому недоступность 10:00 не является хорошей. Потому что вы должны учитывать рабочее время. мы делаем разность дат: 22-21 = 1, поэтому мы должны добавить:

Flag                   Timestamp
end          2019-10-21 17:00:00
begin        2019-10-22 07:00:00

со сцеплением, это дает:

Date              Unavailability
2019-10-21                  1h30
2019-10-21                  1h30

Flag                   Timestamp
begin     2019-10-21 15:30:22.48
end       2019-10-21 17:00:00.00
begin     2019-10-22 07:00:00.00
end       2019-10-22 08:30:31.71

Пример моего фрейма данных:

Flag                     Timestamp
begin   2019-10-25 09:39:39.914889
end     2019-10-25 09:41:09.103102
begin   2019-10-25 10:39:58.352073
end     2019-10-25 10:40:06.266782
begin   2019-10-25 16:35:22.485574
end     2019-10-27 09:50:31.713192
begin   2019-10-29 14:04:33.095633
end     2019-10-29 14:05:07.639344
begin   2019-10-29 14:13:07.924966
end     2019-10-29 14:13:08.888890

Спасибо за ваше время!

Доказательство:

start   Tranc   dayofMonth  lapse   TrancRecalibration
0   2019-10-25 09:39:39.914889  begin   25.0    0.0     1
1   2019-10-25 09:41:09.103102  end     25.0    0.0     2
2   2019-10-25 10:39:58.352073  begin   25.0    0.0     1
3   2019-10-25 10:40:06.266782  end     25.0    0.0     2
4   2019-10-25 16:35:22.485574  begin   25.0    0.0     1
5   2019-10-25 17:00:22.485574  end     NaN     0.0     2
7   2019-10-26 07:00:39.914889  begin   NaN     1.0     1
6   2019-10-26 17:00:39.914889  end     NaN     1.0     2
11  2019-10-27 07:00:39.914889  begin   NaN     1.0     1
8   2019-10-27 08:00:31.713192  begin   NaN     0.0     1
9   2019-10-27 09:50:31.713192  end     27.0    0.0     2
10  2019-10-27 17:00:39.914889  end     NaN     1.0     2
15  2019-10-28 07:00:39.914889  begin   NaN     1.0     1
12  2019-10-28 14:04:33.095633  begin   28.0    0.0     1
14  2019-10-28 14:05:07.639344  end     28.0    0.0     2
13  2019-10-28 14:13:07.924966  begin   28.0    0.0     1
16  2019-10-28 14:13:08.888890  end     28.0    0.0     2
17  2019-10-28 17:00:39.914889  end     NaN     1.0     

Действительно здорово, что вы сделали, мне так и не удалось ...

Еще один последний момент, если вы позволите:

это результат с изменением с 4:55 вечера до 7:00 утра.

Как мы можем заметить, мы имеем:

начало 7:00, начало 8:00, конец 9:50, конец 5:00, начало 7:00, начало 14:04. , конец 2:13 вечера конец 5:00 вечера

Для расчета в отношении моих аварий У меня должен быть альтернативный конец начала каждый раз. поэтому, если у меня есть два начала, которые следуют, я хотел бы удалить 7:00 утра, и если у меня есть два конца, которые следуют, я хотел бы удалить 5:00 вечера, пожалуйста.

Ответы [ 2 ]

1 голос
/ 25 марта 2020

Хотел бы сделать это кратким, но должен убедиться, что вы понимаете, как я это сделал. Давайте узнаем, если мы вас неправильно поняли.

Кадр данных

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

После вашего запроса ограничить время начала до 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

Отсюда приступите и проанализируйте свою недоступность:

0 голосов
/ 23 марта 2020

n Сначала я должен преобразовать df, чтобы иметь отдельные столбцы начала и конца:

df1['begin'] = df[df['Flag']=='begin']['Timestamp']
df1['end'] = df[df['Flag']=='end']['Timestamp']

, затем рассчитать время до end и время до 17:00, взять min () из двух:

df1['time_to_end'] = df1['end'] - df1['begin']
df1['time_to_17'] = pd.Timestamp(year = df1['begin'].dt.year, month = df1['begin'].dt.month, day = df1['begin'].dt.day ,hour=17, minute=0) - df1['begin']
df1['Unavailibility'] = df1[['time_to_end','time_to_17']].min(1)

Вам нужно сгруппировать дату:

df1[['begin','Unavailibility']].set_index('begin').groupby(pd.Grouper(freq='D')).sum()
...