Определите действия во временных рядах в Python - PullRequest
1 голос
/ 28 марта 2020

График показывает температуру воды в зависимости от времени. Когда происходит активация, температура увеличивается. Когда активация завершится, температура начнет снижаться (хотя иногда может быть временная задержка). enter image description here

Я хотел бы подсчитать, сколько раз произошло событие (каждый синий круг представляет одну активацию). Времена случайного шума (красные кружки - указывают на случайное изменение температуры, но вы можете видеть, что есть только увеличение или уменьшение, но не то и другое одновременно, что означает, что это не правильное событие).

Обновление записей температуры для каждого 0,5 ° C изменение температуры независимо от времени.

Я попытался использовать 1) разность температур и 2) градиент изменения температуры смежных точек данных, чтобы идентифицировать метки времени начала и окончания события и считать его как одно событие. Но это не очень точно.

Мне сказали, что я должен использовать только разницу температур и идентифицировать образец (увеличение - максимальная температура - уменьшение) как одно событие. Есть идеи, как правильно рассчитать общее количество активаций?


Обновление1:

Пример данных:

        id      timestamp               temperature 
27581   27822   2020-01-02 07:53:05.173 19.5    
27582   27823   2020-01-02 07:53:05.273 20.0    
27647   27888   2020-01-02 10:01:46.380 20.5    
27648   27889   2020-01-02 10:01:46.480 21.0    
27649   27890   2020-01-02 10:01:48.463 21.5    
27650   27891   2020-01-02 10:01:48.563 22.0    
27711   27952   2020-01-02 10:32:19.897 21.5    
27712   27953   2020-01-02 10:32:19.997 21.0
27861   28102   2020-01-02 11:34:41.940 21.5    
...

Обновление2:

Попытка:

df['timestamp'] = pd.to_datetime(df['timestamp'])
df['Date'] = [datetime.datetime.date(d) for d in df['timestamp']] 
df['Date'] = pd.to_datetime(df['Date'])   
df = df[df['Date'] == '2020-01-02']

# one does not need duplicate temperature values, 
# because the task is to find changing values
df2 = df.loc[df['temperature'].shift() != df['temperature']]

# ye good olde forward difference
der = np.diff(df2['temperature'])
# to have the same length as index
der = np.insert(der,len(der),np.NaN)
# make it column
df2['sig'] = np.sign(der)

# temporary array
evts = np.zeros(len(der))
# we find that points, where the signum is changing from 1 to -1, i.e. crosses zero
evts[(df2['sig'].shift() != df2['sig'])&(0 > df2['sig'])] = 1.0
# make it column for plotting
df2['events'] = evts

# preparing plot
fig,ax = plt.subplots(figsize=(20,20))
ax.xaxis_date()
ax.xaxis.set_major_locator(plticker.MaxNLocator(20))

# temperature itself
ax.plot(df2['temperature'],'-xk')
ax2=ax.twinx()

# 'events'
ax2.plot(df2['events'],'-xg')

## uncomment next two lines for plotting of signum
# ax3=ax.twinx()
# ax3.plot(df2['sig'],'-m')

# x-axis tweaking
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))
minLim = '2020-01-02 00:07:00'
maxLim = '2020-01-02 23:59:00'
plt.xlim(mdates.date2num(pd.Timestamp(minLim)),
          mdates.date2num(pd.Timestamp(maxLim)))
plt.show()

и возникла пустая диаграмма с сообщениями:

/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:31: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:38: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

Update3:

Запись for-l oop для создания графика для каждого дня:

df['timestamp'] = pd.to_datetime(df['timestamp'])   
df['Date'] = df['timestamp'].dt.date     
df.set_index(df['timestamp'], inplace=True)

start_date = pd.to_datetime('2020-01-01 00:00:00')
end_date = pd.to_datetime('2020-02-01 00:00:00')
df = df.loc[(df.index >= start_date) & (df.index <= end_date)]

for date in df['Date'].unique():   
  df_date = df[df['Date'] == date]

# one does not need duplicate temperature values, 
# because the task is to find changing values
  df2 = pd.DataFrame.copy(df_date.loc[df_date['temperature'].shift() != df_date['temperature']])

# ye good olde forward difference
  der = np.sign(np.diff(df2['temperature']))
# to have the same length as index
  der = np.insert(der,len(der),np.NaN)
# make it column
  df2['sig'] = der

# temporary array
  evts = np.zeros(len(der))
# we find that points, where the signum is changing from 1 to -1, i.e. crosses zero
  evts[(df2['sig'].shift() != df2['sig'])&(0 > df2['sig'])] = 1.0
# make it column for plotting
  df2['events'] = evts

# preparing plot
  fig,ax = plt.subplots(figsize=(30,10))

  ax.xaxis_date()
# df2['timestamp'] = pd.to_datetime(df2['timestamp'])
  ax.xaxis.set_major_locator(plticker.MaxNLocator(20)) 

# temperature itself
  ax.plot(df2['temperature'],'-xk')
  ax2=ax.twinx()

# 'events'
  g= ax2.plot(df2['events'],'-xg')

# x-axis tweaking
  ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))
  minLim = '2020-01-02 00:07:00'
  maxLim = '2020-01-02 23:59:00'
  plt.xlim(mdates.date2num(pd.Timestamp(minLim)),
          mdates.date2num(pd.Timestamp(maxLim)))

  ax.autoscale()     
  plt.title(date)
  print(np.count_nonzero(df2['events'][minLim:maxLim]))
  plt.show(g)

График работал, но не количество отсчетов.


Обновление 4:

enter image description here

enter image description here Это похоже на некоторые графики (например, 2020 -01-01, 2020-01-04, 2020-01-05) превышают случайный фрагмент времени (вероятно, по выходным). Есть ли способ удалить в эти дни?

1 Ответ

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

Прежде всего, я бы посоветовал вам увеличить количество баллов, то есть в самой экспериментальной установке.
Тем не менее, похоже, что можно извлечь «события» из предоставленных данных. Идея проста: нам нужно найти «пики», характеризующиеся паттерном «подъём-снижение». Чтобы находить подъемы и спады, естественно использовать производную первого порядка, и поскольку нас интересует только знак (плюс для увеличения функции, минус для уменьшения), я просто использовал сигнум над разностью вперед первого порядка. Поскольку мы предполагаем, что спонтанно возникающих пиков нет, нам нужно найти точки прямой разницы, где меняется знак. Фактически, это суррогатная производная второго порядка, и, фактически, я достиг почти того же результата, используя простую разность вперед 2-го порядка, однако это не очень удобно.


Я использовал следующую процедуру

# imports
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.ticker as plticker
# endimports

# path to csv
path = r'JanuaryData.csv'
# reading the csv
df = pd.read_csv(path,usecols=['timestamp','temperature'],parse_dates=True, index_col='timestamp')

# selecting the part for the analysis
startDate = '2020-01-01 00:00:00'
endDate = '2020-01-03 23:59:00'
df = df.loc[startDate:endDate]

# one does not need duplicate temperature values, 
# because the task is to find changing values
df2 = df.loc[df['temperature'].shift() != df['temperature']]

# ye good olde forward difference
der = np.diff(df2['temperature'])
# to have the same length as index
der = np.insert(der,len(der),np.NaN)
# make it column
df2['sig'] = np.sign(der)

# temporary array
evts = np.zeros(len(der))
# we find that points, where the signum is changing from 1 to -1, i.e. crosses zero
evts[(df2['sig'].shift() != df2['sig'])*(0 > df2['sig'])] = 1.0
# make it column for plotting
df2['events'] = evts

# preparing plot
fig,ax = plt.subplots(figsize=(20,20))
ax.xaxis_date()
ax.xaxis.set_major_locator(plticker.MaxNLocator(20))

# temperature itself
ax.plot(df2['temperature'],'-xk')
ax2=ax.twinx()

# 'events'
ax2.plot(df2['events'],'-xg')

## uncomment next two lines for plotting of signum
# ax3=ax.twinx()
# ax3.plot(df2['sig'],'-m')

# x-axis tweaking
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))
minLim = '2020-01-02 00:07:00'
maxLim = '2020-01-02 23:59:00'
plt.xlim(mdates.date2num(pd.Timestamp(minLim)),
          mdates.date2num(pd.Timestamp(maxLim)))
plt.show()

Изображение, полученное с помощью кода: The image produced by the code Пики зеленой кривой показывают начало соответствующего пика температуры, и я извиняюсь за не столь визуальное представление. Я попытался проанализировать другие данные в .csv, и похоже, что алгоритм работает хорошо.


EDIT # 1 заменить строку

df2 = df.loc[df['temperature'].shift() != df['temperature']]

с помощью

df2 = pd.DataFrame.copy(df.loc[df['temperature'].shift() != df['temperature']])

избавиться от SettingWithCopyWarning.

, а также перезаписать строки с разницей в прямом направлении от

# ye good olde forward difference
der = np.diff(df2['temperature'])
# to have the same length as index
der = np.insert(der,len(der),np.NaN)
# make it column
df2['sig'] = np.sign(der)

до

# ye good olde forward difference
der = np.sign(np.diff(df2['temperature']))
# to have the same length as index
der = np.insert(der,len(der),np.NaN)
# make it column
df2['sig'] = der

до запретить np.sign() предупреждение о значении NaN.


РЕДАКТИРОВАТЬ # 2 , чтобы напечатать число событий в диапазоне, используйте

print(np.count_nonzero(df2['events'][minLim:maxLim]))

для пределов, используемых над ним. 6, для всего набора данных это дает 174.

...