Время как тип данных в Python
Время — это важный тип структурированных данных, который используется во многих областях, таких как финансы, экономика, экология, нейронаука, физика и другие. Время может быть представлено в виде временных рядов — последовательностей значений, упорядоченных по времени. Временные ряды могут иметь фиксированную частоту (например, данные собираются каждые 15 секунд или каждый месяц) или нефиксированную (без определённой периодичности).
В этой главе рассматриваются три основных типа временных рядов:
Для обработки экспериментальных временных рядов можно использовать различные методы и алгоритмы. Индексом временного ряда может быть целое число или число с плавающей точкой, которое представляет количество времени, прошедшего с начала эксперимента. Наиболее распространённым типом временного ряда является индекс, основанный на времени (timestamp).
Библиотека Pandas предоставляет множество инструментов для работы с временными рядами, включая функции для индексации, нарезки, агрегации и передискретизации данных. Эти инструменты особенно полезны для финансовых и экономических приложений, а также для анализа серверных журналов.
Работа с датой и временем в Python
Python включает стандартные типы данных для работы с датой (date) и временем (time), а также функции для работы с календарём. Наиболее часто используемый тип данных — datetime, который позволяет хранить дату и время с точностью до миллисекунд.
Тип данных timedelta используется для представления разницы между двумя объектами datetime. Он может быть добавлен или вычтен из объекта datetime для создания нового объекта с изменённой датой или временем.
Модуль datetime содержит несколько типов данных, которые используются для работы со временем. В таблице 11-1 представлены основные типы данных модуля datetime.
Объекты datetime и pandas Timestamp могут быть преобразованы в строки с использованием методов str или strftime. Метод strptime позволяет преобразовать строку в объект datetime с помощью форматирования.
Pandas также предоставляет функцию to_datetime, которая может анализировать различные форматы даты и времени и создавать объекты datetime или временные индексы. Перевод текста на русский язык:
Начальные и конечные даты определяют строгие границы индекса дат. Например, если вы хотите создать индекс дат, состоящий из последнего рабочего дня каждого месяца, вы можете передать частоту «BM» (business end of month), которая будет включать только те даты в интервале (или точно на границе), которые соответствуют требованиям частоты:
In [78]: pd.date_range('2000-01-01', '2000-12-01', freq='BM')
Out[78]:
DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31', '2000-04-28',
'2000-05-31', '2000-06-30', '2000-07-31', '2000-08-31',
'2000-09-29', '2000-10-31', '2000-11-30'],
dtype='datetime64[ns]', freq='BM')
По умолчанию date_range сохраняет информацию о времени начала и окончания времени (если она есть):
In [79]: pd.date_range('2012-05-02 12:56:31', periods=5)
Out[79]:
DatetimeIndex(['2012-05-02 12:56:31', '2012-05-03 12:56:31',
'2012-05-04 12:56:31', '2012-05-05 12:56:31',
'2012-05-06 12:56:31'],
dtype='datetime64[ns]', freq='D')
Иногда, хотя начальные и конечные даты содержат информацию о времени, вы хотите получить набор временных меток, нормализованных до полуночи. Нормализация может быть достигнута с помощью опции normalize:
In [80]: pd.date_range('2012-05-02 12:56:31', periods=5, normalize=True)
Out[80]:
DatetimeIndex(['2012-05-02', '2012-05-03', '2012-05-04', '2012-05-05',
'2012-05-06'],
dtype='datetime64[ns]', freq='D')
Частота в pandas состоит из базовой частоты и множителя. Базовая частота обычно представлена в виде строкового псевдонима, например, «M» для месяца или «H» для часа. Для каждой базовой частоты существует соответствующий объект, называемый смещением даты:
In [81]: from pandas.tseries.offsets import Hour, Minute
In [82]: hour = Hour()
In [83]: hour
Out[83]: <Hour>
Передавая целое число, можно определить кратное смещение:
In [84]: four_hours = Hour(4)
In [85]: four_hours
Out[85]: <4 * Hours>
Как правило, нет необходимости явно создавать такие объекты, достаточно использовать псевдонимы строк, такие как «H» или «4H». Вы можете создать кратные, поставив перед базовой частотой целое число:
In [86]: pd.date_range('2000-01-01', '2000-01-03 23:59', freq='4h')
Out[86]:
DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 04:00:00',
'2000-01-01 08:00:00', '2000-01-01 12:00:00',
'2000-01-01 16:00:00', '2000-01-01 20:00:00',
'2000-01-02 00:00:00', '2000-01-02 04:00:00',
'2000-01-02 08:00:00', '2000-01-02 12:00:00',
'2000-01-02 16:00:00', '2000-01-02 20:00:00',
'2000-01-03 00:00:00', '2000-01-03 04:00:00',
'2000-01-03 08:00:00', '2000-01-03 12:00:00',
'2000-01-03 16:00:00', '2000-01-03 20:00:00'],
dtype='datetime64[ns]', freq='4H')
Большинство объектов смещения даты могут быть соединены с помощью сложения:
In [87]: Hour(2) + Minute(30)
Out[87]: <150 * Minutes>
Аналогично, вы также можете передать строку частоты («2h30min»), которая может быть эффективно проанализирована в эквивалентное выражение:
In [88]: pd.date_range('2000-01-01', periods=10, freq='1h30min')
Out[88]:
DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 01:30:00',
'2000-01-01 03:00:00', '2000-01-01 04:30:00',
'2000-01-01 06:00:00', '2000-01-01 07:30:00',
'2000-01-01 09:00:00', '2000-01-01 10:30:00',
'2000-01-01 12:00:00', '2000-01-01 13:30:00'],
dtype='datetime64[ns]', freq='90T')
Некоторые частоты описывают временные точки, которые не равномерно разделены. Например, «M» (последний день месяца) и «BM» (последний рабочий день каждого месяца) зависят от количества дней в месяце, а для последнего также необходимо учитывать, является ли конец месяца выходным днём. Поскольку нет лучшего термина, я называю их привязанными смещениями.
Таблица 11–4 перечисляет коды частот и классы смещения дат в pandas.
Примечание: пользователи могут настраивать некоторые классы частот для предоставления логики дат, отсутствующей в pandas, но конкретные детали выходят за рамки этой книги. Период «2007» с частотой «A-DEC».
Примечание: перевод выполнен автоматически, возможны неточности.
Перевод кода на русский язык:
In [160]: p = pd.Period('2007', freq='A-DEC')
In [161]: p
Out[161]: Period('2007', 'A-DEC')``` **2000-01-30 0.423331**
**2000-01-31 -0.654040**
**2000-02-01 2.089154**
**2000-02-02 -0.060220**
**2000-02-03 -0.167933**
Freq: D, dtype: float64
**В запросе представлен фрагмент кода на языке Python, который используется в библиотеке Pandas для работы с данными.**
В этом фрагменте кода создаются два массива данных с информацией о годе и квартале, которые затем объединяются в один индекс PeriodIndex. Это позволяет объединить данные в единый DataFrame с индексом, содержащим информацию о дате.
Далее в коде используется метод resample для изменения частоты данных. В данном случае данные с ежедневной частотой преобразуются в данные с месячной частотой.
*Этот фрагмент не содержит технических терминов или специфической информации о разработке программного обеспечения.* ```
ts.resample('M', kind='period').mean()
Out[222]:
2000-01 -0.165893
2000-02 0.078606
2000-03 0.223811
2000-04 -0.063643
Freq: M, dtype: float64
В этом фрагменте кода используется метод resample
для обработки временных рядов. Метод resample
позволяет изменять частоту данных временного ряда. В данном случае временной ряд агрегируется до ежемесячной частоты ('M'
).
Метод mean
применяется к агрегированным данным для вычисления среднего значения за каждый месяц. Результатом является серия с индексом в виде дат и значениями в виде средних значений за соответствующий месяц. ```
frame.resample('D').ffill()
Out[235]:
Colorado Texas New York Ohio
2000-01-05 -0,896431 0,677263 0,036503 0,087102
2000-01-06 -0,896431 0,677263 0,036503 0,087102
2000-01-07 -0,896431 0,677263 0,036503 0,087102
2000-01-08 -0,896431 0,677263 0,036503 0,087102
2000-01-09 -0,896431 0,677263 0,036503 0,087102
2000-01-10 -0,896431 0,677263 0,036503 0,087102
2000-01-11 -0,896431 0,677263 0,036503 0,087102
2000-01-12 -0,046662 0,927238 0,482284 -0,867130
Также можно заполнить только указанный период времени, чтобы ограничить использование предыдущих наблюдений:
```python
In [236]: frame.resample('D').ffill(limit=2)
Out[236]:
Colorado Texas New York Ohio
2000-01-05 -0,896431 0,677263 0,036503 0,087102
2000-01-06 -0,896431 0,677263 0,036503 0,087102
2000-01-07 -0,896431 0,677263 0,036503 0,087102
2000-01-08 NaN NaN NaN NaN
2000-01-09 NaN NaN NaN NaN
2000-01-10 NaN NaN NaN NaN
2000-01-11 NaN NaN NaN NaN
2000-01-12 -0,046662 0,927238 0,482284 -0,867130
Обратите внимание, что новый индекс даты может не совпадать со старым:
In [237]: frame.resample('W-THU').ffill()
Out[237]:
Colorado Texas New York Ohio
2000-01-06 -0,896431 0,677263 0,036503 0,087102
2000-01-13 -0,046662 0,927238 0,482284 -0,867130
``` Данный текст представляет собой фрагмент технической документации, в которой описывается использование функций для работы с временными рядами в библиотеке Pandas на языке Python.
В тексте рассматриваются функции для вычисления скользящих средних значений и других статистических показателей временных рядов. В частности, описываются функции rolling(), expand(), ewma() и их применение для анализа финансовых данных.
**Перевод текста:**
Теперь мы введём оператор rolling, который похож на resample и groupby. Его можно вызвать для TimeSeries или DataFrame, а также для окна, представляющего собой период времени (см. рисунок 11-4):
```python
In [238]: close_px.AAPL.plot()
Out[238]: <matplotlib.axes._subplots.AxesSubplot at 0x7f2f2570cf98>
In [239]: close_px.AAPL.rolling(250).mean().plot()
Выражение rolling(250) похоже на groupby, но вместо того чтобы группировать данные, оно создаёт объект скользящего окна с размером группы 250 дней. Затем мы получаем скользящее среднее значение цены акций компании Apple за 250 дней.
По умолчанию функция rolling требует, чтобы все значения в окне были не равны NA. Это поведение можно изменить, чтобы решить проблему недостающих данных. На самом деле, данные в начале временного ряда, где окно ещё не достигло своего размера, являются особым случаем (см. рисунок 11-5):
In [241]: appl_std250 = close_px.AAPL.rolling(250, min_periods=10).std()
In [242]: appl_std250[5:12]
Out[242]:
2003-01-09 NaN
2003-01-10 NaN
2003-01-13 NaN
2003-01-14 NaN
2003-01-15 0.077496
2003-01-16 0.074760
2003-01-17 0.112368
Freq: B, Name: AAPL, dtype: float64
In [243]: appl_std250.plot()
Чтобы вычислить расширенное скользящее среднее (expanding window mean), можно использовать expanding вместо rolling. «Расширение» означает, что окно начинается с начала временного ряда и увеличивается до тех пор, пока не превысит всю последовательность. Расширенное скользящее среднее для временного ряда apple_std250 выглядит следующим образом:
In [244]: expanding_mean = appl_std250.expanding().mean()
Вызов rolling_mean для DataFrame применяет преобразование ко всем столбцам (см. рисунок 11-6):
In [246]: close_px.rolling(60).mean().plot(logy=True)
Функция rolling также может принимать фиксированный размер временной компенсации в виде строки, а не набора периодов. Это удобно для обработки нерегулярных временных рядов. Эти строки также могут быть переданы в resample. Например, мы можем вычислить скользящее среднее за 20 дней:
In [247]: close_px.rolling('20D').mean()
Out[247]:
AAPL MSFT XOM
2003-01-02 7.400000 21.110000 29.220000
2003-01-03 7.425000 21.125000 29.230000
...
2011-10-03 398.002143 25.890714 72.413571
2011-10-04 396.802143 25.807857 72.427143
2011-10-05 395.751429 25.729286 72.422857
...
[2292 rows x 3 columns]
Другой способ использования окон фиксированного размера с равными весами для наблюдений — это определение коэффициента затухания (decay factor), чтобы недавние наблюдения имели больший вес. Существует множество способов определения коэффициента затухания, и один из наиболее распространённых — использование интервала времени (span), который позволяет результатам быть совместимыми с простым скользящим окном (simple moving window) функции, равным интервалу времени.
Поскольку экспоненциальное взвешивание присваивает больший вес недавним наблюдениям, оно может «адаптироваться» к изменениям быстрее, чем равноправное статистическое взвешивание.
Помимо rolling и expanding, pandas также имеет оператор ewm. Следующий пример сравнивает 30-дневное простое скользящее среднее цены акций Apple и 30-дневный интервал времени экспоненциального скользящего среднего (как показано на рисунке 11-7):
In [249]: aapl_px = close_px.AAPL['2006':'2007']
In [250]: ma60 = aapl_px.rolling(30, min_periods=20).mean()
In [251]: ewma60 = aapl_px.ewm(span=30).mean()
In [252]: ma60.plot(style='k--', label='Simple MA')
Out[252]: <matplotlib.axes._subplots.AxesSubplot at 0x7f2f252161d0>
In [253]: ewma60.plot(style='k-', label='EW MA')
Out[253]: <matplotlib.axes._subplots.AxesSubplot at 0x7f2f252161d0>
In [254]: plt.legend()
Рисунок 11–7: Простое скользящее среднее и экспоненциально взвешенное скользящее среднее
Некоторые статистические операции (например, корреляция и ковариация) требуют выполнения на двух временных рядах. Например, финансовые аналитики часто интересуются корреляцией между ценой акций определённой компании и некоторым эталонным индексом (таким как S&P 500). Чтобы проиллюстрировать это, сначала мы вычислим процентное изменение интересующего нас временного ряда:
In [256]: spx_px = close_px_all['SPX']
In [257]: spx_rets = spx_px.pct_change()
In [258]: returns = close_px.pct_change()
После вызова rolling корреляционная агрегатная функция начинает вычислять корреляцию скользящего окна AAPL с spx_rets (результаты показаны на рисунке 11-8):
In [259]: corr = returns.AAPL.rolling(125, min_periods=100).corr(spx_rets)
In [260]: corr.plot()
Рисунок 11–8: Корреляция доходности AAPL за шесть месяцев с доходностью S&P 500 Предположим, вы хотите однократно вычислить коэффициент корреляции между несколькими акциями и индексом S&P 500. Хотя написать цикл и создать новый DataFrame не так сложно, это довольно утомительно. На самом деле нужно только передать TimeSeries и DataFrame в функцию rolling_corr, которая автоматически вычислит коэффициент корреляции TimeSeries (в данном случае spx_rets) с каждой колонкой DataFrame. Результат показан на рисунке 11-9:
In [262]: corr = returns.rolling(125, min_periods=100).corr(spx_rets)
In [263]: corr.plot()
Рисунок 11–9. Коэффициент корреляции доходности трёх акций и индекса S&P 500 за шесть месяцев
Функция rolling_apply позволяет применять пользовательские функции к данным в скользящем окне. Единственное требование — функция должна возвращать единственное значение для каждого фрагмента массива (то есть «сжимать» данные). Например, при использовании rolling(...).quantile(q) для вычисления квантилей выборки может быть интересно узнать процентное содержание определённых значений в выборке. Для этого можно использовать функцию scipy.stats.percentileofscore (результат показан на рисунке 11-10):
In [265]: from scipy.stats import percentileofscore
In [266]: score_at_2percent = lambda x: percentileofscore(x, 0.02)
In [267]: result = returns.AAPL.rolling(250).apply(score_at_2percent)
In [268]: result.plot()
Рисунок 11–10. Процентное содержание доходности AAPL на уровне 2% (годовое окно)
Если у вас не установлен SciPy, его можно установить с помощью conda или pip.
По сравнению с данными из предыдущих разделов, анализ временных рядов требует других инструментов анализа и преобразования данных.
В следующих разделах мы изучим более продвинутые методы pandas и начнём использовать библиотеки моделирования statsmodels и scikit-learn.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )