Локализуйте каждую строку индекса отметки времени панд отдельно - PullRequest
0 голосов
/ 12 ноября 2018

У меня есть временная серия, состоящая из следующего списка:

for i in range(10):
    d = {
        'ts': i,
        'ts_offset': 6 * 60 * 60,
        'value': 1234.0
    }
    if i >= 5:
        d['ts_offset'] = 12 * 60 * 60
    data.append(d)
frame = pd.DataFrame(data)
frame.index = pd.to_datetime(frame.ts, unit='s')

                        ts  ts_offset   value
ts                                        
1970-01-01 00:00:00   0      21600  1234.0
1970-01-01 00:00:01   1      21600  1234.0
1970-01-01 00:00:02   2      21600  1234.0
1970-01-01 00:00:03   3      21600  1234.0
1970-01-01 00:00:04   4      21600  1234.0
1970-01-01 00:00:05   5      43200  1234.0
1970-01-01 00:00:06   6      43200  1234.0
1970-01-01 00:00:07   7      43200  1234.0
1970-01-01 00:00:08   8      43200  1234.0
1970-01-01 00:00:09   9      43200  1234.0

Индекс - это временная метка плюс смещение, зависящее от локализации (в секундах).Как вы можете видеть, мой вариант использования заключается в том, что смещение может измениться в любой момент времени.Я хотел бы преобразовать эту конструкцию в серию, где индексом является локализованный pd.TimeSeriesIndex, но пока мне удалось найти только функции локализации, которые работали над всем индексом.

Кто-нибудь знает эффективный метод для преобразования каждого индекса с (возможно) отдельным часовым поясом?Серия может состоять из нескольких тысяч строк, и эта функция будет вызываться много, поэтому я хотел бы векторизовать ее как можно больше.


Редактировать:

Я взял на себя смелость выбрать решение для группировки FLabs по сравнению с простым циклом Python со следующим скриптом:

import pandas as pd
import numpy as np
import datetime


def to_series1(data, metric):
    idx = []
    values = []
    for i in data:
        tz = datetime.timezone(datetime.timedelta(seconds=i["ts_offset"]))
        idx.append(pd.Timestamp(i["ts"] * 10**9, tzinfo=tz))
        values.append(np.float(i["value"]))
    series = pd.Series(values, index=idx, name=metric)
    return series


def to_series2(data, metric):
    frame = pd.DataFrame(data)
    frame.index = pd.to_datetime(frame.ts, unit='s', utc=True)
    grouped = frame.groupby('ts_offset')

    out = {}
    for name, group in grouped:
        out[name] = group
        tz = datetime.timezone(datetime.timedelta(seconds=name))
        out[name].index = out[name].index.tz_convert(tz)

    out = pd.concat(out, axis=0).sort_index(level='ts')
    out.index = out.index.get_level_values('ts')
    series = out.value
    series.name = metric
    series.index.name = None
    return series


metric = 'bla'
data = []
for i in range(100000):
    d = {
        'ts': i,
        'ts_offset': 6 * 60 * 60,
        'value': 1234.0
    }
    if i >= 50000:
        d['ts_offset'] = 12 * 60 * 60
    data.append(d)

%timeit to_series1(data, metric)

%timeit to_series2(data, metric)

Результаты были следующие:

2.59 s ± 113 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
3.03 s ± 125 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Итак, я 'Я по-прежнему открыт для предложений, которые, возможно, быстрее.

1 Ответ

0 голосов
/ 12 ноября 2018

Вы можете использовать groupby ts_offset, чтобы можно было применить одно смещение к кадру данных (векторизованная операция):

grouped = frame.groupby('ts_offset')

out = {}
for name, group in grouped:
    print(name)
    out[name] = group
    out[name].index = out[name].index + pd.DateOffset(seconds=name)

out = pd.concat(out, axis=0, names=['offset', 'ts']).sort_index(level='ts')

Отображение примененного смещения только для проверки результатов:

Out[17]: 
                           ts  ts_offset   value
      ts                                        
21600 1970-01-01 06:00:00   0      21600  1234.0
      1970-01-01 06:00:01   1      21600  1234.0
      1970-01-01 06:00:02   2      21600  1234.0
      1970-01-01 06:00:03   3      21600  1234.0
      1970-01-01 06:00:04   4      21600  1234.0
43200 1970-01-01 12:00:05   5      43200  1234.0
      1970-01-01 12:00:06   6      43200  1234.0
      1970-01-01 12:00:07   7      43200  1234.0
      1970-01-01 12:00:08   8      43200  1234.0
      1970-01-01 12:00:09   9      43200  1234.0

Наконец, вы можете удалить первый индекс:

out.index = out.index.get_level_values('ts')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...