#python #pandas #dataframe #time-series
#питон #панды #фрейм данных #временные ряды
Вопрос:
У меня есть некоторые данные, отсортированные по времени, которые отслеживают время начала и окончания различных событий. Для иллюстрации представьте, что я отслеживаю, когда включается и выключается набор лампочек. Мои данные структурированы следующим образом:
Идентификатор лампы | Событие (вкл/выкл) | Время (ы) |
---|---|---|
1 | на | 2 |
2 | на | 5 |
1 | ВЫКЛ | 6 |
3 | на | 8 |
3 | ВЫКЛ | 10 |
2 | ВЫКЛ | 14 |
Я хочу найти общее время, в течение которого хотя бы одна из лампочек включена. До сих пор моя лучшая идея состоит в том, чтобы изменить столбец событий в двоичном флаге и выполнить суммирование по этому столбцу, затем использовать numpy.diff
и numpy.where
найти строки, в которых сумма изменяется от 1 до 0 или от 0 до 1, затем соединить их и добавить разницу во времени между этими двумя строками в общую сумму. Так что что-то вроде этого:
df["event_flag"] = df["Event (on/off)"].map({"on": 1, "off": -1}) df["cumulative"] = df["event_flag"].cumsum() df["cumulative"] = df.apply(lambda x: 1 if x gt;= 1 else 0) switch_rows = df["Time (s)"][df["cumulative"].diff != 0].tolist() total_time = 0 for i in range(0, len(switch_rows), 2): total_time = switch_rows[i 1] - switch_rows[i]
Это работает, но это не очень безопасно, так как предполагается, что данные начинаются и заканчиваются выключенными лампочками, что не обязательно так. Есть ли более аккуратный и/или безопасный способ сделать это, или мне следует придерживаться того, что у меня есть, и добавить проверки исходного состояния системы?
Ответ №1:
Ваше решение может сработать, но в нем много «если» и «но». Попробуй pd.pivot_table
pd.pivot_table(data=df,values="Time (s)", columns="Event (on/off)", index="Bulb ID",aggfunc=np.sum)
Это может быть использовано для дальнейшего расчета материала.
Комментарии:
1. Это не совсем дает мне то, что я ищу — с помощью этого я получаю сумму временных меток, когда каждая лампочка была включена/выключена. Что мне нужно, так это общее время, когда горит хотя бы одна лампочка, без двойного счета, когда горит более одной.
Ответ №2:
Я придумал решение, используя pandas.resample
. Я выполняю первые два шага своего первоначального решения, затем извлекаю только столбцы cumsum и time, устанавливаю столбец времени в качестве индекса timedelta, затем повторно делаю выборку с постоянной скоростью, как показано ниже:
df["event_flag"] = df["Event (on/off)"].map({"on": 1, "off": -1}) df["cumulative"] = df["event_flag"].cumsum() time_data = df[["cumulative"]].set_index(pd.TimedeltaIndex(data=df["Time (s)"], unit="s")) time_data = time_data.resample("1s").pad()
Как только у меня будет постоянная частота дискретизации, я смогу просто посчитать строки, в которых значение ненулевое.
total_time = time_data[time_data["cumulative"] != 0].count()
Если бы моя частота дискретизации не была в секундах, я мог бы затем разделить это количество на частоту кадров, например, если бы я работал с интервалами 0,2 с, то мое общее время равно
total_time = 5 * time_data[time_data["cumulative"] != 0].count()
Это решение позволяет избежать проблем, которые у меня были с моим первым решением, и гораздо менее трудоемко.