Рассчитать разницу во времени, если разница больше часа, пометить как «пропущенные», построить зазор на линейном графике в этой области - PullRequest
0 голосов
/ 01 марта 2019

У меня есть базовый фрейм данных pandas на python, который берет данные и строит линейный график.Каждая точка данных включает в себя время.Если с файлом данных все работает, в идеале каждая временная отметка примерно на 30 минут отличается друг от друга.В некоторых случаях данные не поступают более чем за час.В это время я хочу пометить этот период как «отсутствующий» и построить прерывистый линейный график, наглядно показывающий, где отсутствовали данные.

Мне трудно разобраться, как это сделать, и дажеискать решение, так как проблема довольно специфична.Данные «живые», где они постоянно обновляются, поэтому я не могу просто указать определенную область и отредактировать как обходной путь.

Что-то похожее на это:

Пример

Код, использованный для создания столбца даты и времени:

#convert first time columns into one datetime column
df['datetime'] = pd.to_datetime(df[['year', 'month', 'day', 'hour', 'minute', 'second']])

Я выяснил, как рассчитать разницу во времени, что связано с созданием нового столбца.Вот этот код на всякий случай:

df['timediff'] = (df['datetime']-df['datetime'].shift().fillna(pd.to_datetime("00:00:00", format="%H:%M:%S")))

Базовый взгляд на фрейм данных:

datetime               l1    l2    l3
2019-02-03 01:52:16   0.1   0.2   0.4
2019-02-03 02:29:26   0.1   0.3   0.6
2019-02-03 02:48:03   0.1   0.3   0.6
2019-02-03 04:48:52   0.3   0.8   1.4
2019-02-03 05:25:59   0.4   1.1   1.7
2019-02-03 05:44:34   0.4   1.3   2.2

Я просто не уверен, как создать прерывистый «живой» сюжет, включающийразница во времени.

Заранее спасибо.

Ответы [ 3 ]

0 голосов
/ 02 марта 2019

Редактировать: @ Игорь Рауш дал лучший ответ, но я все равно оставляю его, поскольку визуализация немного отличается.

Посмотрите, поможет ли это вам:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# Track the time delta in seconds
# I used total_seconds() and not seconds as seconds are limited to the amount of secs in one day
df['timediff'] = (df['datetime'] - df['datetime'].shift(1)).dt.total_seconds().cumsum().fillna(0)
# Create a dataframe of all the possible seconds in the time range
all_times_df = pd.DataFrame(np.arange(df['timediff'].min(), df['timediff'].max()), columns=['timediff']).set_index('timediff')
# Join the dataframes and fill nulls with 0s, so the values change only where data has been received
live_df = all_times_df.join(df.set_index('timediff')).ffill()
# Plot only your desired columns
live_df[['l1', 'l3']].plot()
plt.show()

Output

0 голосов
/ 12 марта 2019

Решено с использованием моего нового столбца timediff и функции df.loc.

df['timediff'] = (df['datetime']-df['datetime'].shift().fillna(pd.to_datetime("00:00:00", format="%H:%M:%S")))

Благодаря этому я смог собрать разницу во времени для каждой строки.

Затем с помощью df.locЯ смог найти значения в столбцах l1 и l2, где timediff был больше часа, и сделать тогда nan.В результате в этот момент на графике отсутствует линия, как я и хотел.

missing_l1 = df['l1'].loc[df['timediff'] > timedelta(hours=1)] = np.nan
missing_l2 = df['l2'].loc[df['timediff'] > timedelta(hours=1)] = np.nan
0 голосов
/ 02 марта 2019

Не совсем то, что вы хотите, но быстрое и элегантное решение состоит в повторной выборке ваших данных.

df = df.set_index('datetime')
df
                      l1   l2   l3
datetime                          
2019-02-03 01:52:16  0.1  0.2  0.4
2019-02-03 02:29:26  0.1  0.3  0.6
2019-02-03 02:48:03  0.1  0.3  0.6
2019-02-03 04:48:52  0.3  0.8  1.4
2019-02-03 05:25:59  0.4  1.1  1.7
2019-02-03 05:44:34  0.4  1.3  2.2
df.resample('30T').mean()['l1'].plot(marker='*')

resampled plot


Если вам абсолютно необходимо составить точную диаграмму для каждой выборки, вы можете разделить данные, если разница между последовательными временными метками превышает некоторый порог, и построить каждый фрагмент отдельно.

from datetime import timedelta

# get difference between consecutive timestamps
dt = df.index.to_series()
td = dt - dt.shift()

# generate a new group index every time the time difference exceeds
# an hour
gp = np.cumsum(td > timedelta(hours=1))

# get current axes, plot all groups on the same axes
ax = plt.gca()
for _, chunk in df.groupby(gp):
    chunk['l1'].plot(marker='*', ax=ax)

chunked plot

Кроме того, вы можете добавить «дыры» в свои данные.

# find samples which occurred more than an hour after the previous
# sample
holes = df.loc[td > timedelta(hours=1)]

# "holes" occur just before these samples
holes.index -= timedelta(microseconds=1)

# append holes to the data, set values to NaN
df = df.append(holes)
df.loc[holes.index] = np.nan

# plot series
df['l1'].plot(marker='*')

plot with holes

...