Python: Подгонка линий для обозначения убывающих частей моих данных (от максимального до минимального) и их экстраполяции (от максимального до максимального)? - PullRequest
1 голос
/ 04 апреля 2020

У меня ежедневные измерения уровня воды (гидравлика c напор) в течение нескольких лет (хранятся в серии с указателем даты и времени). Я пытаюсь вписать линию во все убывающие части данных. Эти прямые линии должны быть экстраполированы до следующего максимума данных. Если первая точка минимальна, я хочу установить прямую линию до следующего максимума. Это показано на рисунке ниже.

Мне удалось закодировать эту проблему в Python, но очень «безобразно», используя 150 строк кода (много операторов if).

Мой подход: сгладить данные путем подгонки сплайнов. Затем используйте find_peaks из scipy.signal, чтобы найти экстремумы (умножьте на -1, чтобы получить минимум). Поскольку эта функция не имеет дело с первым и последним пунктом, я использовал операторы if для решения этой проблемы. Затем я использую два цикла for для подгонки кривой и экстраполяции. Я использовал один для l oop в случае, если данные начинаются с минимума, а другой - в случае, если данные начинаются с максимума, поскольку границы моего «интервала подбора» и моего «интервала экстраполяции» различны для каждого случая. Если данные начинаются с минуты, я использовал прямую линию для первого интервала. Результат моего кода показан на изображении.

Изображение, показывающее результат моего кода

Есть идеи, как сделать это лучше? Без использования такого количества строк кода

Следующий фрагмент кода демонстрирует мой подход для случая, когда данные начинаются с максимума

    #hydraulic_head is a series of interpolated (spline) hydraulic head measurements with a datetime index

    from scipy.signal import find_peaks
    import pandas as pd
    import numpy as np

    peak_max=hydraulic_head[find_peaks(hydraulic_head)[0]] #hydraulic head at max
    peak_min=hydraulic_head[find_peaks(hydraulic_head*-1)[0]] #hydraulic head at min


   for gr in range(1,len(peak_max.index),1):

    interval_fit=hydraulic_head[peak_max.index[gr-1]:peak_min.index[gr-1]] #interval to fit curve from max to min
    t_fit=(interval_fit.index-interval_fit.index[0]).total_seconds().values #time in seconds

    parameters=np.polyfit(t_fit,interval_max_min.values,1) #fit a line
    parameter_estimated[gr]=parameterss #store the paramters of the line in a dict

    interval_extrapolate=hydraulic_head[peak_max.index[gr-1]:peak_max.index[gr]] #interval to extrapolate
    t_extrapolate=(interval_extrapolate.index-interval_extrapolate.index[0]).total_seconds().values #transform to time

    values_extrapolated=parameters[0]*t_extrapolate+parameters[1] #extrapolate the line
    new_index=interval_extrapolate.index #get the index from the extrapolated interval
    new_series=pd.DataFrame(data=values_extrapolated,index=new_index,columns=['extrapolated']) #new data frame with extrapolated values

    interpolation_out=pd.concat([interpolation_out,new_series]) #growing frame where lines are stored

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

Это мой первый вопрос здесь. Открыты для любого улучшения формулировки вопроса

...