Найдите отметку времени, после которой набор данных становится монотонным

У меня есть фрейм данных, который содержит столбец высоты. Вначале высота остается неизменной с точки зрения колебаний сигнала GPS. В какой-то момент высота меняется, когда GPS-приемник перемещается во время подъема в гору. Как мне найти временную метку, когда высота начнет непрерывно перемещаться вверх? Простое сравнение «больше чем» не сработает, поскольку вначале во время разминки высота немного подпрыгивает.

Пример таймера здесь:

import pandas as pd
import numpy as np
 
df_GPS = pd.DataFrame([['2024-06-21 06:22:38', 605.968389],
                     ['2024-06-21 06:22:39', 606.009398],
                     ['2024-06-21 06:22:40', 605.630573],
                     ['2024-06-21 06:22:41', 605.476367 ],
                     ['2024-06-21 06:22:42', 605.322161],
                     ['2024-06-21 06:22:43', 605.268389],
                     ['2024-06-21 06:22:44', 605.559398],
                     ['2024-06-21 06:22:45', 606.630573],
                     ['2024-06-21 06:22:46', 607.476367 ],
                     ['2024-06-21 06:22:47', 609.322161],
                    ], columns=['time', 'Altitude'])

В идеале я бы получил в результате: время = 2024-06-21 06:22:43 так как оттуда высота монотонно возрастает.

Мой код все еще неисправен

start_move = df_GPS.loc[df_GPS['Altitude'] == df_GPS["Altitude"].is_monotonic_increasing, 'time'] 
print(start_move)    

Где моя опечатка?

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

user19077881 01.07.2024 12:06

@user19077881 user19077881 ты имеешь в виду что-то вроде start_move = df_GPS.loc[df_GPS['Altitude'][::-1] == df_GPS["Altitude"].loc[::-1].is_monotonic_decreasing, 'time'] ? Это тоже не сработает, поскольку, очевидно, я вернулся с горы, и трек тоже содержит данные о восхождении :-(

Swawa 01.07.2024 13:01

Я мог бы использовать пороговое значение для сравнения с предыдущими данными. Если разница между двумя наборами данных превышает пороговое значение, это мое время start_move. Очевидно, что таким образом трек начнется на несколько секунд позже...

Swawa 01.07.2024 13:09

что-то вроде этого было бы обходным решением, даже если это не совсем то решение: start_move = df_GPS.loc[df_GPS['Altitude'].diff(periods=1) > 0.5, 'time'].min()

Swawa 01.07.2024 13:26
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
4
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Предполагая, что time преобразован в datatime/timestamp, вы можете просто посмотреть назад с конца, чтобы найти изменение от монотонного. Предполагая, что данные времени необходимо отсортировать, сначала измените порядок:

df_GPS_rev = df_GPS.sort_values(by = 'time', ascending = False)

Альтернативно, если данные уже упорядочены по времени, то единственным требованием является изменение существующего порядка на противоположный, поэтому необходимо только переиндексировать:

df_GPS_rev = df_GPS.reindex(index = df_GPS.index[::-1])

затем

start_move = df_GPS_rev[df_GPS_rev['Altitude'] < df_GPS_rev['Altitude'].shift(-1)].iloc[0]

print(start_move['time'])

дает:

2024-06-21 06:22:43

Если (как позже определено в комментариях OP) данные НЕ всегда монотонно увеличиваются, а, например, уменьшаются в конце, то можно проверить скользящие окна на предмет монотонного увеличения:

# define window size
win= 3

# find windows which are monotonic increasing
df_GPS['win_inc'] = df_GPS.rolling(win)['Altitude'].apply(lambda x: x.is_monotonic_increasing)

#get index of end of first increasing window
idx = df_GPS[df_GPS['win_inc'].eq(True)].index[0]

# get time at start of first increasing window
start_move = df_GPS.loc[idx-win+1, 'time']
print(start_move)

что снова дает:

2024-06-21 06:22:43

Более быстрый, но менее лаконичный подход может использовать Numpy:

# define window size
win= 3
#create numpy array
alt = df_GPS['Altitude'].to_numpy()

#search through np array looking for first increasing window
start_idx = None
for idx, val in enumerate(alt[:1-win]):
    if np.all(np.diff(alt[idx:idx+win]) > 0):
        start_idx = idx
        break

if start_idx is not None:
    start_move = df_GPS.loc[start_idx, 'time']
    print(start_move)
else:
    print('no increasing windows')

что снова дает тот же результат

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

Swawa 01.07.2024 16:07

См. отредактированный ответ: необходимо только переиндексировать, а не сортировать. Возможно, это лечит головную боль!

user19077881 01.07.2024 18:31

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

Swawa 03.07.2024 07:33

См. отредактированный ответ с подходом rolling window, который касается данных, которые также спускаются позже. Надеюсь, теперь это будет полезно.

user19077881 03.07.2024 13:04

вау, круто, это работает для набора данных, содержащего подъем и спуск! Я бы оценил его еще раз, если бы мог. Большое спасибо за помощь в понимании программирования на Python. Часть .apply(lambda x: x.is_monotonic_increasing) была той, о которой я не думал...

Swawa 03.07.2024 14:21

Хотя код краток, метод прокрутки Pandas может быть несколько неэффективным для огромных наборов данных, поскольку он находит все увеличивающиеся окна, прежде чем использовать только первое из них. У меня есть аналогичный, хотя и менее краткий подход, который следует той же логике, используя цикл Numpy для проверки только первого увеличивающегося окна — дайте мне знать, если это важно для вас.

user19077881 03.07.2024 15:51

да, ты прав. Для обработки больших наборов данных требуется некоторое время. Если существует более быстрое решение, которое прекращает расчет, как только происходит первое обнаружение, мне было бы любопытно узнать об этом. Вы имеете в виду решение с циклом for?

Swawa 04.07.2024 07:07

У него есть цикл for, но внутри массива Numpy, а не Pandas, и он предназначен только для поиска первого окна, следовательно, намного быстрее. Смотрите отредактированный ответ.

user19077881 04.07.2024 12:09

кажется, это более быстрый способ расчета. Следовательно, мне нужно как-то немного изменить одну строку, чтобы она работала и на моей машине: if start_idx is not None: start_move = df_GPS['time'][start_idx]. Большой! Спасибо за этот приятный урок :-)

Swawa 04.07.2024 19:23

первое решение занимает около 0,585 с, второе — около 0,002 с, время обработки набора данных, содержащего 9486 строк записей данных — почти в 300 раз быстрее... Это потрясающе :-)

Swawa 04.07.2024 19:33

Другие вопросы по теме