Эффективное создание меток для данных таймсерий на основе будущих данных таймсерий - PullRequest
1 голос
/ 06 августа 2020

У меня есть данные датчиков за два года в формате pandas. Индекс представляет собой временной ряд. Выглядит это так:


                     temp1     overtemp  time_to_overtemp
datetime                                                    
2019-01-02 09:31:00  305.96
2019-01-02 09:32:00  305.98
2019-01-02 09:33:00  305.70
2019-01-02 09:34:00  305.30
2019-01-02 09:35:00  306.88

Я хочу сделать l oop по временному ряду, чтобы заполнить столбцы «overtemp» и «time_to_overtemp». «Overtemp» необходимо присвоить 1, если температура данные в любое время в течение следующих двух недель увеличиваются более чем на 2%. "time_to_overtemp" должен отображать время следующего> 2% чтения, если оно существует в следующие две недели. Если температура показывает в пределах 2% для следующих двух недель, обоим столбцам следует присвоить 0.

Например, 2019-01-02 09:31:00 следует просмотреть данные о температуре за следующие две недели и поставить 0 в оба столбца, потому что все данные в этот период времени находится в пределах 2% от значения. Значение перегрева для 02.01.2020 09:35:00 должно быть равно 1, потому что через неделю значение увеличилось на 5%. Значение time_to_overtemp должно указывать на 7 дней, 2 часа , 38 минут, потому что именно тогда произошло превышение температуры.

Я успешно делаю еще несколько математических задач, используя iterrows:

for datetime, row in df.iterrows():

, но это занимает вечность. И я не еще не научился делать итерации по времени и вычисления.

Я сделал другую маркировку:

df['overtemp'] = np.select([df['temp1']<305, df['temp1']>305], [1,0])

Я думаю, это векторизует процесс? Конечно, это работает намного быстрее, чем повторение. Но я не могу понять, как реализовать часть datetime + две недели.

Ответы [ 2 ]

1 голос
/ 06 августа 2020

Вот предложение о том, как решить вашу проблему, используя apply и индексацию.

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

Или вы можете распараллелить функцию apply , чтобы ускорить ее.

df = pd.DataFrame(pd.date_range(start='2020-01-01', end='2020-03-01', freq='H'), columns=['datetime'])
df['temp'] =  [np.random.uniform(low=300, high=310) for _ in range(df.shape[0])]

def get_overtemp(row):
    now = row.datetime
    next_14_days = now + timedelta(days=14)
    temp = row.temp
    
    filtered = df[
        (df['datetime'] > now) & 
        (df['datetime'] <= next_14_days) & 
        (df['temp'] > temp * 1.02)
    ]
    
    overtemp = len(filtered) > 0
    time_to_overtemp = None
    if overtemp:
        time_to_overtemp = filtered['datetime'].values[0] - now
        
    return pd.Series([overtemp, time_to_overtemp])

df[['overtemp', 'time_to_overtemp']] = df.apply(get_overtemp, axis=1)
df.head(20)

Результат:

|    | datetime            |    temp | overtemp   | time_to_overtemp   |
|---:|:--------------------|--------:|:-----------|:-------------------|
|  0 | 2020-01-01 00:00:00 | 309.502 | False      | NaT                |
|  1 | 2020-01-01 01:00:00 | 303.816 | True       | 7 days 00:00:00    |
|  2 | 2020-01-01 02:00:00 | 307.297 | False      | NaT                |
|  3 | 2020-01-01 03:00:00 | 306.252 | False      | NaT                |
|  4 | 2020-01-01 04:00:00 | 303.458 | True       | 0 days 07:00:00    |
|  5 | 2020-01-01 05:00:00 | 304.27  | False      | NaT                |
|  6 | 2020-01-01 06:00:00 | 300.98  | True       | 0 days 05:00:00    |
|  7 | 2020-01-01 07:00:00 | 306.652 | False      | NaT                |
|  8 | 2020-01-01 08:00:00 | 304.107 | False      | NaT                |
|  9 | 2020-01-01 09:00:00 | 300.077 | True       | 0 days 02:00:00    |

См.: https://github.com/nalepae/pandarallel

0 голосов
/ 06 августа 2020

Думаю, вы могли бы сделать это с pandas качением, применив функции, вот мой go, надеюсь, это то, что вам нужно:

# create random data
ind = pd.date_range(start = pd.to_datetime("2019-01-02 09:31:00"), periods=28*24*60, freq='min')
v = [random.randint(30000, 32000)/100 for x in ind]
df = pd.DataFrame(v, index=ind, columns = ['temp1'])

# define funcs
def overtemp(S):
    l = S[S>=S[-1]*1.02]
    if len(l)>0:
        return l[-1]
    else:
        return 0

def overtemp_seconds(S):
    l = np.argwhere(S.values>=S.values[-1]*1.02)
    if len(l)>0:
        i = l[-1][0]
        delta = S.index[i] - S.index[-1]
        return delta.seconds
    else:
        return 0

# apply funcs to time window (reversed cause rolling gives you time window till offset)
over_temp = df[::-1].rolling('14D').apply(overtemp)[::-1]['temp1']
seconds_to_over_temp = df[::-1].rolling('14D').apply(overtemp_seconds)[::-1]['temp1']

# add to orig df
df['over_temp'] = over_temp
df['seconds_to_over_temp'] = seconds_to_over_temp
...