Spec-Zone.ru › pandas 0.18

Инструменты вычислений

Статистические функции

Процентное изменение

Series, DataFrame, и Panel все имеют метод pct_change, для вычисления процентного изменения за заданное количество периодов (используя fill_method для заполнения значений NaN/null перед вычислением процентного изменения).

In [1]: ser = pd.Series(np.random.randn(8))

In [2]: ser.pct_change()
Out[2]: 
0         NaN
1   -1.602976
2    4.334938
3   -0.247456
4   -2.067345
5   -1.142903
6   -1.688214
7   -9.759729
dtype: float64
In [3]: df = pd.DataFrame(np.random.randn(10, 4))

In [4]: df.pct_change(periods=3)
Out[4]: 
          0         1         2         3
0       NaN       NaN       NaN       NaN
1       NaN       NaN       NaN       NaN
2       NaN       NaN       NaN       NaN
3 -0.218320 -1.054001  1.987147 -0.510183
4 -0.439121 -1.816454  0.649715 -4.822809
5 -0.127833 -3.042065 -5.866604 -1.776977
6 -2.596833 -1.959538 -2.111697 -3.798900
7 -0.117826 -2.169058  0.036094 -0.067696
8  2.492606 -1.357320 -1.205802 -1.558697
9 -1.012977  2.324558 -1.003744 -0.371806

Ковариация

Объект Series имеет метод cov для вычисления ковариации между рядами (исключая значения NaN/null).

In [5]: s1 = pd.Series(np.random.randn(1000))

In [6]: s2 = pd.Series(np.random.randn(1000))

In [7]: s1.cov(s2)
Out[7]: 0.00068010881743110698

Аналогично, DataFrame имеет метод cov для вычисления парных ковариаций между рядами в DataFrame, также исключая значения NaN/null.

Примечание

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

In [8]: frame = pd.DataFrame(np.random.randn(1000, 5), columns=['a', 'b', 'c', 'd', 'e'])

In [9]: frame.cov()
Out[9]: 
          a         b         c         d         e
a  1.000882 -0.003177 -0.002698 -0.006889  0.031912
b -0.003177  1.024721  0.000191  0.009212  0.000857
c -0.002698  0.000191  0.950735 -0.031743 -0.005087
d -0.006889  0.009212 -0.031743  1.002983 -0.047952
e  0.031912  0.000857 -0.005087 -0.047952  1.042487

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

In [10]: frame = pd.DataFrame(np.random.randn(20, 3), columns=['a', 'b', 'c'])

In [11]: frame.ix[:5, 'a'] = np.nan

In [12]: frame.ix[5:10, 'b'] = np.nan

In [13]: frame.cov()
Out[13]: 
          a         b         c
a  1.210090 -0.430629  0.018002
b -0.430629  1.240960  0.347188
c  0.018002  0.347188  1.301149

In [14]: frame.cov(min_periods=12)
Out[14]: 
          a         b         c
a  1.210090       NaN  0.018002
b       NaN  1.240960  0.347188
c  0.018002  0.347188  1.301149

Корреляция

Предоставлены несколько методов для вычисления корреляций:

Название метода Описание
pearson (default) Коэффициент корреляции
kendall Коэффициент корреляции Кендалла
spearman Коэффициент ранговой корреляции Спирмена

Все они в настоящее время вычисляются с использованием парных полных наблюдений.

Примечание

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

In [15]: frame = pd.DataFrame(np.random.randn(1000, 5), columns=['a', 'b', 'c', 'd', 'e'])

In [16]: frame.ix[::2] = np.nan

# Series with Series
In [17]: frame['a'].corr(frame['b'])
Out[17]: 0.013479040400098789

In [18]: frame['a'].corr(frame['b'], method='spearman')
Out[18]: -0.0072898851595406388

# Pairwise correlation of DataFrame columns
In [19]: frame.corr()
Out[19]: 
          a         b         c         d         e
a  1.000000  0.013479 -0.049269 -0.042239 -0.028525
b  0.013479  1.000000 -0.020433 -0.011139  0.005654
c -0.049269 -0.020433  1.000000  0.018587 -0.054269
d -0.042239 -0.011139  0.018587  1.000000 -0.017060
e -0.028525  0.005654 -0.054269 -0.017060  1.000000

Обратите внимание, что нечисловые столбцы будут автоматически исключены из расчёта корреляции.

Подобно cov, corr также поддерживает необязательное ключевое слово min_periods.

In [20]: frame = pd.DataFrame(np.random.randn(20, 3), columns=['a', 'b', 'c'])

In [21]: frame.ix[:5, 'a'] = np.nan

In [22]: frame.ix[5:10, 'b'] = np.nan

In [23]: frame.corr()
Out[23]: 
          a         b         c
a  1.000000 -0.076520  0.160092
b -0.076520  1.000000  0.135967
c  0.160092  0.135967  1.000000

In [24]: frame.corr(min_periods=12)
Out[24]: 
          a         b         c
a  1.000000       NaN  0.160092
b       NaN  1.000000  0.135967
c  0.160092  0.135967  1.000000

Реализованный родственный метод corrwith применяется к DataFrame для вычисления корреляции между рядами с одинаковыми метками, содержащимися в разных объектах DataFrame.

In [25]: index = ['a', 'b', 'c', 'd', 'e']

In [26]: columns = ['one', 'two', 'three', 'four']

In [27]: df1 = pd.DataFrame(np.random.randn(5, 4), index=index, columns=columns)

In [28]: df2 = pd.DataFrame(np.random.randn(4, 4), index=index[:4], columns=columns)

In [29]: df1.corrwith(df2)
Out[29]: 
one     -0.125501
two     -0.493244
three    0.344056
four     0.004183
dtype: float64

In [30]: df2.corrwith(df1, axis=1)
Out[30]: 
a   -0.675817
b    0.458296
c    0.190809
d   -0.186275
e         NaN
dtype: float64

Ранжирование данных

Метод rank генерирует ранжирование данных, при этом одинаковые значения присваивают среднее значение рангов (по умолчанию) для группы:

In [31]: s = pd.Series(np.random.np.random.randn(5), index=list('abcde'))

In [32]: s['d'] = s['b'] # so there's a tie

In [33]: s.rank()
Out[33]: 
a    5.0
b    2.5
c    1.0
d    2.5
e    4.0
dtype: float64

rank также является методом DataFrame и может ранжировать либо строки (axis=0), либо столбцы (axis=1). Значения NaN исключаются из ранжирования.

In [34]: df = pd.DataFrame(np.random.np.random.randn(10, 6))

In [35]: df[4] = df[2][:5] # some ties

In [36]: df
Out[36]: 
          0         1         2         3         4         5
0 -0.904948 -1.163537 -1.457187  0.135463 -1.457187  0.294650
1 -0.976288 -0.244652 -0.748406 -0.999601 -0.748406 -0.800809
2  0.401965  1.460840  1.256057  1.308127  1.256057  0.876004
3  0.205954  0.369552 -0.669304  0.038378 -0.669304  1.140296
4 -0.477586 -0.730705 -1.129149 -0.601463 -1.129149 -0.211196
5 -1.092970 -0.689246  0.908114  0.204848       NaN  0.463347
6  0.376892  0.959292  0.095572 -0.593740       NaN -0.069180
7 -1.002601  1.957794 -0.120708  0.094214       NaN -1.467422
8 -0.547231  0.664402 -0.519424 -0.073254       NaN -1.263544
9 -0.250277 -0.237428 -1.056443  0.419477       NaN  1.375064

In [37]: df.rank(1)
Out[37]: 
     0    1    2    3    4    5
0  4.0  3.0  1.5  5.0  1.5  6.0
1  2.0  6.0  4.5  1.0  4.5  3.0
2  1.0  6.0  3.5  5.0  3.5  2.0
3  4.0  5.0  1.5  3.0  1.5  6.0
4  5.0  3.0  1.5  4.0  1.5  6.0
5  1.0  2.0  5.0  3.0  NaN  4.0
6  4.0  5.0  3.0  1.0  NaN  2.0
7  2.0  5.0  3.0  4.0  NaN  1.0
8  2.0  5.0  3.0  4.0  NaN  1.0
9  2.0  3.0  1.0  4.0  NaN  5.0

rank необязательно принимает параметр ascending, который по умолчанию равен true; если он false, данные сортируются в обратном порядке, и более высоким значениям присваивается меньший ранг.

rank поддерживает различные методы разбиения при равенстве, задаваемые параметром method:

  • average: средний ранг связанной группы
  • min: наименьший ранг в группе
  • max: наибольший ранг в группе
  • first: ранги назначаются в порядке их появления в массиве

Функции окна

Предупреждение

До версии 0.18.0 pd.rolling_*, pd.expanding_*, и pd.ewm* были функциями уровня модуля и теперь устарели. Они заменены использованием объектов Rolling, Expanding и EWM и соответствующего вызова метода.

Предупреждение об устаревании покажет новый синтаксис, см. пример здесь. Вы можете просмотреть предыдущую документацию здесь.

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

Примечание

API для статистик окон очень похож на работу с объектами GroupBy, см. документацию здесь.

Мы работаем с данными rolling, expanding и exponentially weighted через соответствующие объекты Rolling, Expanding и EWM.

In [38]: s = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))

In [39]: s = s.cumsum()

In [40]: s
Out[40]: 
2000-01-01    -0.268824
2000-01-02    -1.771855
2000-01-03    -0.818003
2000-01-04    -0.659244
2000-01-05    -1.942133
2000-01-06    -1.869391
2000-01-07     0.563674
                ...    
2002-09-20   -68.233054
2002-09-21   -66.765687
2002-09-22   -67.457323
2002-09-23   -69.253182
2002-09-24   -70.296818
2002-09-25   -70.844674
2002-09-26   -72.475016
Freq: D, dtype: float64

Они создаются из методов объектов Series и DataFrame.

In [41]: r = s.rolling(window=60)

In [42]: r
Out[42]: Rolling [window=60,center=False,axis=0]

Эти объекты обеспечивают автодополнение доступных методов и свойств.

In [14]: r.
r.agg         r.apply       r.count       r.exclusions  r.max         r.median      r.name        r.skew        r.sum
r.aggregate   r.corr        r.cov         r.kurt        r.mean        r.min         r.quantile    r.std         r.var

В целом, у этих методов одинаковый интерфейс. Все они принимают следующие аргументы:

  • window: размер скользящего окна
  • min_periods: порог непустых значений данных для требования (в противном случае результат NA)
  • center: булево, устанавливать метки в центре (по умолчанию False)

Предупреждение

Аргументы freq и how были в API до изменений 0.18.0. Они устарели в новом API. Можно просто перевыбрать входные данные перед созданием функции окна.

Например, вместо s.rolling(window=5,freq='D').max() для получения максимального значения в окне скользящего среднего 5 дней можно использовать s.resample('D').max().rolling(window=5).max(), что сначала перевыбирает данные до дневных данных, а затем предоставляет окно скользящего среднего 5 дней.

Затем мы можем вызвать методы этих объектов rolling. Они возвращают объекты с аналогичными индексами.

In [43]: r.mean()
Out[43]: 
2000-01-01          NaN
2000-01-02          NaN
2000-01-03          NaN
2000-01-04          NaN
2000-01-05          NaN
2000-01-06          NaN
2000-01-07          NaN
                ...    
2002-09-20   -62.694135
2002-09-21   -62.812190
2002-09-22   -62.914971
2002-09-23   -63.061867
2002-09-24   -63.213876
2002-09-25   -63.375074
2002-09-26   -63.539734
Freq: D, dtype: float64
In [44]: s.plot(style='k--')
Out[44]: <matplotlib.axes._subplots.AxesSubplot at 0x11ce37110>

In [45]: r.mean().plot(style='k')
Out[45]: <matplotlib.axes._subplots.AxesSubplot at 0x11ce37110>
_images/rolling_mean_ex.png

Они также могут применяться к объектам DataFrame. Это фактически просто синтаксический сахар для применения оператора скользящего окна ко всем столбцам DataFrame:

In [46]: df = pd.DataFrame(np.random.randn(1000, 4),
   ....:                   index=pd.date_range('1/1/2000', periods=1000),
   ....:                   columns=['A', 'B', 'C', 'D'])
   ....: 

In [47]: df = df.cumsum()

In [48]: df.rolling(window=60).sum().plot(subplots=True)
Out[48]: 
array([<matplotlib.axes._subplots.AxesSubplot object at 0x11cdc2890>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x120dfef50>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x120cd4110>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x1127f6e90>], dtype=object)
_images/rolling_mean_frame.png

Краткое описание методов

Мы предоставляем ряд распространенных статистических функций:

Метод Описание
count() Количество непустых наблюдений
sum() Сумма значений
mean() Среднее значение значений
median() Арифметическая медиана значений
min() Минимальное значение
max() Максимальное значение
std() Выборочное стандартное отклонение (с поправкой на бесслововость)
var() Несмещённая дисперсия
skew() Выборочная асимметрия (третий момент)
kurt() Выборовый эксцесс (четвертый момент)
quantile() Выборочный квантиль (значение в %)
apply() Общее применение
cov() Несмещённая ковариация (бинарная)
corr() Корреляция (бинарная)

Функция apply() принимает дополнительный аргумент func и выполняет общие вычисления скользящего среднего. Аргумент func должен быть единственной функцией, которая создаёт единственное значение из входного массива ndarray. Предположим, что мы хотели вычислить среднее абсолютное отклонение в скользящем режиме:

In [49]: mad = lambda x: np.fabs(x - x.mean()).mean()

In [50]: s.rolling(window=60).apply(mad).plot(style='k')
Out[50]: <matplotlib.axes._subplots.AxesSubplot at 0x112f25950>
_images/rolling_apply_ex.png

Скользящие окна

Передача win_type в .rolling генерирует вычисление скользящего окна общего вида, взвешенное согласно win_type. Доступны следующие методы:

Метод Описание
sum() Сумма значений
mean() Среднее значение

Веса, используемые в окне, задаются ключевым словом win_type. Список распознаваемых типов:

  • boxcar
  • triang
  • blackman
  • hamming
  • bartlett
  • parzen
  • bohman
  • blackmanharris
  • nuttall
  • barthann
  • kaiser (требуется beta)
  • gaussian (требуется std)
  • general_gaussian (требуется power, width)
  • slepian (требуется width).
In [51]: ser = pd.Series(np.random.randn(10), index=pd.date_range('1/1/2000', periods=10))

In [52]: ser.rolling(window=5, win_type='triang').mean()
Out[52]: 
2000-01-01         NaN
2000-01-02         NaN
2000-01-03         NaN
2000-01-04         NaN
2000-01-05   -1.037870
2000-01-06   -0.767705
2000-01-07   -0.383197
2000-01-08   -0.395513
2000-01-09   -0.558440
2000-01-10   -0.672416
Freq: D, dtype: float64

Обратите внимание, что окно boxcar эквивалентно mean().

In [53]: ser.rolling(window=5, win_type='boxcar').mean()
Out[53]: 
2000-01-01         NaN
2000-01-02         NaN
2000-01-03         NaN
2000-01-04         NaN
2000-01-05   -0.841164
2000-01-06   -0.779948
2000-01-07   -0.565487
2000-01-08   -0.502815
2000-01-09   -0.553755
2000-01-10   -0.472211
Freq: D, dtype: float64

In [54]: ser.rolling(window=5).mean()
Out[54]: 
2000-01-01         NaN
2000-01-02         NaN
2000-01-03         NaN
2000-01-04         NaN
2000-01-05   -0.841164
2000-01-06   -0.779948
2000-01-07   -0.565487
2000-01-08   -0.502815
2000-01-09   -0.553755
2000-01-10   -0.472211
Freq: D, dtype: float64

Для некоторых функций окон, необходимо указать дополнительные параметры:

In [55]: ser.rolling(window=5, win_type='gaussian').mean(std=0.1)
Out[55]: 
2000-01-01         NaN
2000-01-02         NaN
2000-01-03         NaN
2000-01-04         NaN
2000-01-05   -1.309989
2000-01-06   -1.153000
2000-01-07    0.606382
2000-01-08   -0.681101
2000-01-09   -0.289724
2000-01-10   -0.996632
Freq: D, dtype: float64

Примечание

Для .sum() с win_type, нормализация весов для окна не выполняется. Передача пользовательских весов [1, 1, 1] даст другой результат, чем передача весов [2, 2, 2], например. При передаче win_type вместо явного указания весов, веса уже нормализованы, так что максимальный вес равен 1.

В отличие от этого, характер вычисления .mean() таков, что веса нормализуются относительно друг друга. Веса [1, 1, 1] и [2, 2, 2] дают одинаковый результат.

Центрирование окон

По умолчанию метки устанавливаются на правом краю окна, но доступно ключевое слово center, чтобы метки можно было установить в центр.

In [56]: ser.rolling(window=5).mean()
Out[56]: 
2000-01-01         NaN
2000-01-02         NaN
2000-01-03         NaN
2000-01-04         NaN
2000-01-05   -0.841164
2000-01-06   -0.779948
2000-01-07   -0.565487
2000-01-08   -0.502815
2000-01-09   -0.553755
2000-01-10   -0.472211
Freq: D, dtype: float64

In [57]: ser.rolling(window=5, center=True).mean()
Out[57]: 
2000-01-01         NaN
2000-01-02         NaN
2000-01-03   -0.841164
2000-01-04   -0.779948
2000-01-05   -0.565487
2000-01-06   -0.502815
2000-01-07   -0.553755
2000-01-08   -0.472211
2000-01-09         NaN
2000-01-10         NaN
Freq: D, dtype: float64

Двоичные функции окна

cov() и corr() могут вычислять статистику скользящего окна по двум Series или любой комбинации DataFrame/Series или DataFrame/DataFrame. Вот поведение в каждом случае:

  • два Series: вычислить статистику для сопряжения.
  • DataFrame/Series: вычислить статистику для каждого столбца DataFrame с переданным Series, тем самым возвращая DataFrame.
  • DataFrame/DataFrame: по умолчанию вычисляет статистику для соответствующих имен столбцов, возвращая DataFrame. Если передано ключевое слово pairwise=True, то вычисляет статистику для каждой пары столбцов, возвращая Panel, чьи items являются датами, о которых идет речь (см. следующий раздел).

Например:

In [58]: df2 = df[:20]

In [59]: df2.rolling(window=5).corr(df2['B'])
Out[59]: 
                   A    B         C         D
2000-01-01       NaN  NaN       NaN       NaN
2000-01-02       NaN  NaN       NaN       NaN
2000-01-03       NaN  NaN       NaN       NaN
2000-01-04       NaN  NaN       NaN       NaN
2000-01-05 -0.262853  1.0  0.334449  0.193380
2000-01-06 -0.083745  1.0 -0.521587 -0.556126
2000-01-07 -0.292940  1.0 -0.658532 -0.458128
...              ...  ...       ...       ...
2000-01-14  0.519499  1.0 -0.687277  0.192822
2000-01-15  0.048982  1.0  0.167669 -0.061463
2000-01-16  0.217190  1.0  0.167564 -0.326034
2000-01-17  0.641180  1.0 -0.164780 -0.111487
2000-01-18  0.130422  1.0  0.322833  0.632383
2000-01-19  0.317278  1.0  0.384528  0.813656
2000-01-20  0.293598  1.0  0.159538  0.742381

[20 rows x 4 columns]

Вычисление скользящих парных ковариаций и корреляций

В финансовом анализе и других областях часто приходится вычислять матрицы ковариации и корреляции для набора временных рядов. Зачастую также интересуют матрицы скользящей ковариации и корреляции. Это можно сделать, передав ключевое слово pairwise, которое в случае DataFrame входных данных вернёт Panel, чьи items являются датами, о которых идет речь. В случае единственного аргумента DataFrame аргумент pairwise можно даже опустить:

Примечание

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

In [60]: covs = df[['B','C','D']].rolling(window=50).cov(df[['A','B','C']], pairwise=True)

In [61]: covs[df.index[-50]]
Out[61]: 
          A         B          C
B  2.667506  1.671711   1.938634
C  8.513843  1.938634  10.556436
D -7.714737 -1.434529  -7.082653
In [62]: correls = df.rolling(window=50).corr()

In [63]: correls[df.index[-50]]
Out[63]: 
          A         B         C         D
A  1.000000  0.604221  0.767429 -0.776170
B  0.604221  1.000000  0.461484 -0.381148
C  0.767429  0.461484  1.000000 -0.748863
D -0.776170 -0.381148 -0.748863  1.000000

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

In [64]: correls.loc[:, 'A', 'C'].plot()
Out[64]: <matplotlib.axes._subplots.AxesSubplot at 0x11ea521d0>
_images/rolling_corr_pairwise_ex.png

Агрегирование

После создания объектов Rolling, Expanding или EWM, доступны несколько методов для выполнения нескольких вычислений над данными. Это очень похоже на агрегирование .groupby(...).agg , описанное здесь.

In [65]: dfa = pd.DataFrame(np.random.randn(1000, 3),
   ....:                    index=pd.date_range('1/1/2000', periods=1000),
   ....:                    columns=['A', 'B', 'C'])
   ....: 

In [66]: r = dfa.rolling(window=60,min_periods=1)

In [67]: r
Out[67]: Rolling [window=60,min_periods=1,center=False,axis=0]

Мы можем агрегировать, передавая функцию всему DataFrame или выбирая Series (или несколько Series) с помощью стандартного getitem.

In [68]: r.aggregate(np.sum)
Out[68]: 
                   A          B         C
2000-01-01  0.314226  -0.001675  0.071823
2000-01-02  1.206791   0.678918 -0.267817
2000-01-03  1.421701   0.600508 -0.445482
2000-01-04  1.912539  -0.759594  1.146974
2000-01-05  2.919639  -0.061759 -0.743617
2000-01-06  2.665637   1.298392 -0.803529
2000-01-07  2.513985   1.923089 -1.928308
...              ...        ...       ...
2002-09-20  1.447669 -12.360302  2.734381
2002-09-21  1.871783 -13.896542  3.086102
2002-09-22  2.540658 -12.594402  3.162542
2002-09-23  2.974674 -12.727703  3.861005
2002-09-24  1.391366 -13.584590  3.790683
2002-09-25  2.027313 -15.083214  3.377896
2002-09-26  1.290363 -13.569459  3.809884

[1000 rows x 3 columns]

In [69]: r['A'].aggregate(np.sum)
Out[69]: 
2000-01-01    0.314226
2000-01-02    1.206791
2000-01-03    1.421701
2000-01-04    1.912539
2000-01-05    2.919639
2000-01-06    2.665637
2000-01-07    2.513985
                ...   
2002-09-20    1.447669
2002-09-21    1.871783
2002-09-22    2.540658
2002-09-23    2.974674
2002-09-24    1.391366
2002-09-25    2.027313
2002-09-26    1.290363
Freq: D, Name: A, dtype: float64

In [70]: r[['A','B']].aggregate(np.sum)
Out[70]: 
                   A          B
2000-01-01  0.314226  -0.001675
2000-01-02  1.206791   0.678918
2000-01-03  1.421701   0.600508
2000-01-04  1.912539  -0.759594
2000-01-05  2.919639  -0.061759
2000-01-06  2.665637   1.298392
2000-01-07  2.513985   1.923089
...              ...        ...
2002-09-20  1.447669 -12.360302
2002-09-21  1.871783 -13.896542
2002-09-22  2.540658 -12.594402
2002-09-23  2.974674 -12.727703
2002-09-24  1.391366 -13.584590
2002-09-25  2.027313 -15.083214
2002-09-26  1.290363 -13.569459

[1000 rows x 2 columns]

Как вы видите, результат агрегирования будет содержать выбранные столбцы или все столбцы, если они не выбраны.

Применение нескольких функций одновременно

В случае оконных Series вы также можете передать список или словарь функций для агрегирования, что выведет DataFrame:

In [71]: r['A'].agg([np.sum, np.mean, np.std])
Out[71]: 
                 sum      mean       std
2000-01-01  0.314226  0.314226       NaN
2000-01-02  1.206791  0.603396  0.408948
2000-01-03  1.421701  0.473900  0.365959
2000-01-04  1.912539  0.478135  0.298925
2000-01-05  2.919639  0.583928  0.350682
2000-01-06  2.665637  0.444273  0.464115
2000-01-07  2.513985  0.359141  0.479828
...              ...       ...       ...
2002-09-20  1.447669  0.024128  1.034827
2002-09-21  1.871783  0.031196  1.031417
2002-09-22  2.540658  0.042344  1.026341
2002-09-23  2.974674  0.049578  1.030021
2002-09-24  1.391366  0.023189  1.024793
2002-09-25  2.027313  0.033789  1.022099
2002-09-26  1.290363  0.021506  1.024751

[1000 rows x 3 columns]

Если передаётся словарь, ключи будут использоваться для именования столбцов. В противном случае будет использоваться имя функции (сохранённое в объекте функции).

In [72]: r['A'].agg({'result1' : np.sum,
   ....:             'result2' : np.mean})
   ....: 
Out[72]: 
             result2   result1
2000-01-01  0.314226  0.314226
2000-01-02  0.603396  1.206791
2000-01-03  0.473900  1.421701
2000-01-04  0.478135  1.912539
2000-01-05  0.583928  2.919639
2000-01-06  0.444273  2.665637
2000-01-07  0.359141  2.513985
...              ...       ...
2002-09-20  0.024128  1.447669
2002-09-21  0.031196  1.871783
2002-09-22  0.042344  2.540658
2002-09-23  0.049578  2.974674
2002-09-24  0.023189  1.391366
2002-09-25  0.033789  2.027313
2002-09-26  0.021506  1.290363

[1000 rows x 2 columns]

В случае оконного DataFrame вы можете передать список функций, применяемых к каждому столбцу, что даёт агрегированный результат с иерархическим индексом:

In [73]: r.agg([np.sum, np.mean])
Out[73]: 
                   A                    B                   C          
                 sum      mean        sum      mean       sum      mean
2000-01-01  0.314226  0.314226  -0.001675 -0.001675  0.071823  0.071823
2000-01-02  1.206791  0.603396   0.678918  0.339459 -0.267817 -0.133908
2000-01-03  1.421701  0.473900   0.600508  0.200169 -0.445482 -0.148494
2000-01-04  1.912539  0.478135  -0.759594 -0.189899  1.146974  0.286744
2000-01-05  2.919639  0.583928  -0.061759 -0.012352 -0.743617 -0.148723
2000-01-06  2.665637  0.444273   1.298392  0.216399 -0.803529 -0.133921
2000-01-07  2.513985  0.359141   1.923089  0.274727 -1.928308 -0.275473
...              ...       ...        ...       ...       ...       ...
2002-09-20  1.447669  0.024128 -12.360302 -0.206005  2.734381  0.045573
2002-09-21  1.871783  0.031196 -13.896542 -0.231609  3.086102  0.051435
2002-09-22  2.540658  0.042344 -12.594402 -0.209907  3.162542  0.052709
2002-09-23  2.974674  0.049578 -12.727703 -0.212128  3.861005  0.064350
2002-09-24  1.391366  0.023189 -13.584590 -0.226410  3.790683  0.063178
2002-09-25  2.027313  0.033789 -15.083214 -0.251387  3.377896  0.056298
2002-09-26  1.290363  0.021506 -13.569459 -0.226158  3.809884  0.063498

[1000 rows x 6 columns]

Передача словаря функций по умолчанию имеет другое поведение, см. следующий раздел.

Применение разных функций к столбцам DataFrame

Передав словарь в aggregate, вы можете применить разную агрегацию к столбцам DataFrame:

In [74]: r.agg({'A' : np.sum,
   ....:        'B' : lambda x: np.std(x, ddof=1)})
   ....: 
Out[74]: 
                   A         B
2000-01-01  0.314226       NaN
2000-01-02  1.206791  0.482437
2000-01-03  1.421701  0.417825
2000-01-04  1.912539  0.851468
2000-01-05  2.919639  0.837474
2000-01-06  2.665637  0.935441
2000-01-07  2.513985  0.867770
...              ...       ...
2002-09-20  1.447669  1.084259
2002-09-21  1.871783  1.088368
2002-09-22  2.540658  1.084707
2002-09-23  2.974674  1.084936
2002-09-24  1.391366  1.079268
2002-09-25  2.027313  1.091334
2002-09-26  1.290363  1.060255

[1000 rows x 2 columns]

Имена функций также могут быть строками. Для того, чтобы строка была допустимой, она должна быть реализована в объекте окна.

In [75]: r.agg({'A' : 'sum', 'B' : 'std'})
Out[75]: 
                   A         B
2000-01-01  0.314226       NaN
2000-01-02  1.206791  0.482437
2000-01-03  1.421701  0.417825
2000-01-04  1.912539  0.851468
2000-01-05  2.919639  0.837474
2000-01-06  2.665637  0.935441
2000-01-07  2.513985  0.867770
...              ...       ...
2002-09-20  1.447669  1.084259
2002-09-21  1.871783  1.088368
2002-09-22  2.540658  1.084707
2002-09-23  2.974674  1.084936
2002-09-24  1.391366  1.079268
2002-09-25  2.027313  1.091334
2002-09-26  1.290363  1.060255

[1000 rows x 2 columns]

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

In [76]: r.agg({'A' : ['sum','std'], 'B' : ['mean','std'] })
Out[76]: 
                   A                   B          
                 sum       std      mean       std
2000-01-01  0.314226       NaN -0.001675       NaN
2000-01-02  1.206791  0.408948  0.339459  0.482437
2000-01-03  1.421701  0.365959  0.200169  0.417825
2000-01-04  1.912539  0.298925 -0.189899  0.851468
2000-01-05  2.919639  0.350682 -0.012352  0.837474
2000-01-06  2.665637  0.464115  0.216399  0.935441
2000-01-07  2.513985  0.479828  0.274727  0.867770
...              ...       ...       ...       ...
2002-09-20  1.447669  1.034827 -0.206005  1.084259
2002-09-21  1.871783  1.031417 -0.231609  1.088368
2002-09-22  2.540658  1.026341 -0.209907  1.084707
2002-09-23  2.974674  1.030021 -0.212128  1.084936
2002-09-24  1.391366  1.024793 -0.226410  1.079268
2002-09-25  2.027313  1.022099 -0.251387  1.091334
2002-09-26  1.290363  1.024751 -0.226158  1.060255

[1000 rows x 4 columns]

Расширяющие окна

Альтернативой скользящей статистике является использование расширяющегося окна, которое даёт значение статистики со всеми доступными данными до этого момента времени.

Они следуют аналогичному интерфейсу .rolling, причём метод .expanding возвращает объект Expanding.

Поскольку эти вычисления являются частным случаем скользящей статистики, они реализованы в pandas таким образом, что следующие два вызова эквивалентны:

In [77]: df.rolling(window=len(df), min_periods=1).mean()[:5]
Out[77]: 
                   A         B         C         D
2000-01-01 -1.388345  3.317290  0.344542 -0.036968
2000-01-02 -1.123132  3.622300  1.675867  0.595300
2000-01-03 -0.628502  3.626503  2.455240  1.060158
2000-01-04 -0.768740  3.888917  2.451354  1.281874
2000-01-05 -0.824034  4.108035  2.556112  1.140723

In [78]: df.expanding(min_periods=1).mean()[:5]
Out[78]: 
                   A         B         C         D
2000-01-01 -1.388345  3.317290  0.344542 -0.036968
2000-01-02 -1.123132  3.622300  1.675867  0.595300
2000-01-03 -0.628502  3.626503  2.455240  1.060158
2000-01-04 -0.768740  3.888917  2.451354  1.281874
2000-01-05 -0.824034  4.108035  2.556112  1.140723

У них есть аналогичный набор методов .rolling методов.

Краткое описание методов

Функция Описание
count() Количество ненулевых наблюдений
sum() Сумма значений
mean() Среднее значение
median() Арифметическая медиана значений
min() Минимальное значение
max() Максимальное значение
std() Несмещенное стандартное отклонение
var() Несмещенная дисперсия
skew() Несмещенная асимметрия (3-й момент)
kurt() Несмещенная эксцесс (4-й момент)
quantile() Выборочная квантиль (значение в %)
apply() Общее применение
cov() Несмещенная ковариация (бинарная)
corr() Корреляция (бинарная)

Помимо отсутствия параметра window, эти функции имеют такие же интерфейсы, как их .rolling аналоги. Как и выше, все они принимают следующие параметры:

  • min_periods: порог количества ненулевых точек данных, необходимых для вычисления статистики. По умолчанию используется минимальное количество, необходимое для вычисления статистики. Значение NaNs не будет выведено, как только будет встречено min_periods ненулевых точек данных.
  • center: булево значение, указывающее, нужно ли размещать метки в центре (по умолчанию False)

Примечание

Методы .rolling и .expanding не возвращают значение NaN, если в текущем окне присутствует не менее min_periods ненулевых значений. Это отличается от cumsum, cumprod, cummax, и cummin, которые возвращают NaN в выводе всякий раз, когда встречается NaN в вводе.

Статистика с расширяющимся окном будет более стабильной (и менее отзывчивой), чем её аналог с окном скользящего среднего, поскольку увеличение размера окна уменьшает относительное влияние отдельной точки данных. В качестве примера, вот результат mean() для предыдущего временного ряда данных:

In [79]: s.plot(style='k--')
Out[79]: <matplotlib.axes._subplots.AxesSubplot at 0x118390f10>

In [80]: s.expanding().mean().plot(style='k')
Out[80]: <matplotlib.axes._subplots.AxesSubplot at 0x118390f10>
_images/expanding_mean_frame.png

Экспоненциально взвешенные окна

Связанный набор функций представляет собой экспоненциально взвешенные версии нескольких вышеперечисленных статистик. Аналогичный интерфейс .rolling и .expanding достигается через метод .ewm для получения объекта EWM. Предоставлено несколько методов расширения EW (экспоненциально взвешенных):

Функция Описание
mean() EW скользящее среднее
var() EW скользящая дисперсия
std() EW скользящее стандартное отклонение
corr() EW скользящая корреляция
cov() EW скользящая ковариация

В общем случае взвешенное скользящее среднее вычисляется как

y_t = \frac{\sum_{i=0}^t w_i x_{t-i}}{\sum_{i=0}^t w_i},

где x_t — входные данные, а y_t — результат.

Функции EW поддерживают два варианта экспоненциальных весов. По умолчанию, adjust=True, используются веса w_i = (1 - \alpha)^i, что дает

y_t = \frac{x_t + (1 - \alpha)x_{t-1} + (1 - \alpha)^2 x_{t-2} + ...
+ (1 - \alpha)^t x_{0}}{1 + (1 - \alpha) + (1 - \alpha)^2 + ...
+ (1 - \alpha)^t}

Когда adjust=False указано, скользящие средние вычисляются как

y_0 &= x_0 \\
y_t &= (1 - \alpha) y_{t-1} + \alpha x_t,

что эквивалентно использованию весов

w_i = \begin{cases}
    \alpha (1 - \alpha)^i & \text{if } i < t \\
    (1 - \alpha)^i        & \text{if } i = t.
\end{cases}

Примечание

Эти уравнения иногда записываются с использованием \alpha' = 1 - \alpha, например:

y_t = \alpha' y_{t-1} + (1 - \alpha') x_t.

Различие между вышеуказанными двумя вариантами возникает потому, что мы имеем дело с рядами, которые имеют конечную историю. Рассмотрим ряд бесконечной истории:

y_t = \frac{x_t + (1 - \alpha)x_{t-1} + (1 - \alpha)^2 x_{t-2} + ...}
{1 + (1 - \alpha) + (1 - \alpha)^2 + ...}

Заметим, что знаменатель представляет собой геометрическую прогрессию с начальным членом, равным 1, и отношением 1 - \alpha, что дает

y_t &= \frac{x_t + (1 - \alpha)x_{t-1} + (1 - \alpha)^2 x_{t-2} + ...}
{\frac{1}{1 - (1 - \alpha)}}\\
&= [x_t + (1 - \alpha)x_{t-1} + (1 - \alpha)^2 x_{t-2} + ...] \alpha \\
&= \alpha x_t + [(1-\alpha)x_{t-1} + (1 - \alpha)^2 x_{t-2} + ...]\alpha \\
&= \alpha x_t + (1 - \alpha)[x_{t-1} + (1 - \alpha) x_{t-2} + ...]\alpha\\
&= \alpha x_t + (1 - \alpha) y_{t-1}

что показывает эквивалентность вышеуказанных двух вариантов для бесконечных рядов. При adjust=True получаем y_0 = x_0, и из последнего представления выше мы получаем y_t = \alpha x_t + (1 - \alpha) y_{t-1}, следовательно, предполагается, что x_0 — это не обычное значение, а экспоненциально взвешенное значение момента бесконечного ряда до этого момента.

Должно быть выполнено условие 0 < \alpha \leq 1, и хотя с версии 0.18.0 можно непосредственно передавать \alpha, зачастую проще использовать диапазон, центр масс (com) или период полураспада для экспоненциально взвешенного момента:

\alpha =
 \begin{cases}
     \frac{2}{s + 1},               & \text{for span}\ s \geq 1\\
     \frac{1}{1 + c},               & \text{for center of mass}\ c \geq 0\\
     1 - \exp^{\frac{\log 0.5}{h}}, & \text{for half-life}\ h > 0
 \end{cases}

Для функций EW необходимо указать ровно один из диапазона, центра масс, периода полураспада и альфа:

  • Диапазон соответствует тому, что обычно называют «EW скользящим средним за N дней».
  • Центр масс имеет более физическое толкование и может быть представлен в терминах диапазона: c = (s - 1) / 2.
  • Период полураспада — это период времени, в течение которого экспоненциальный вес уменьшается до половины.
  • Альфа непосредственно задаёт коэффициент сглаживания.

Вот пример для одномерного временного ряда:

In [81]: s.plot(style='k--')
Out[81]: <matplotlib.axes._subplots.AxesSubplot at 0x1132e2dd0>

In [82]: s.ewm(span=20).mean().plot(style='k')
Out[82]: <matplotlib.axes._subplots.AxesSubplot at 0x1132e2dd0>
_images/ewma_ex.png

EWM имеет аргумент min_periods, который имеет то же значение, что и во всех методах .expanding и .rolling: значения вывода не будут устанавливаться, пока не будет встречено не менее min_periods ненулевых значений в (расширяющемся) окне. (Это изменение по сравнению с версиями до 0.15.0, в которых аргумент min_periods влиял только на min_periods последовательные записи, начиная с первого ненулевого значения.)

EWM также имеет аргумент ignore_na, который определяет, как промежуточные нулевые значения влияют на вычисление весов. При значении ignore_na=False (по умолчанию) веса вычисляются на основе абсолютных позиций, так что промежуточные нулевые значения влияют на результат. При значении ignore_na=True (что воспроизводит поведение в версиях до 0.15.0), веса вычисляются, игнорируя промежуточные нулевые значения. Например, предполагая adjust=True, если ignore_na=False, взвешенное среднее значение 3, NaN, 5 вычисляется как

\frac{(1-\alpha)^2 \cdot 3 + 1 \cdot 5}{(1-\alpha)^2 + 1}

В то время как если ignore_na=True, взвешенное среднее значение вычисляется как

\frac{(1-\alpha) \cdot 3 + 1 \cdot 5}{(1-\alpha) + 1}.

Функции var(), std(), и cov() имеют аргумент bias, определяющий, должны ли результаты содержать смещённые или несмещённые статистики. Например, если bias=True, ewmvar(x) вычисляется как ewmvar(x) = ewma(x**2) - ewma(x)**2; в то время как при значении bias=False (по умолчанию), смещённые статистические показатели дисперсии масштабируются с помощью корректирующих факторов

\frac{\left(\sum_{i=0}^t w_i\right)^2}{\left(\sum_{i=0}^t w_i\right)^2 - \sum_{i=0}^t w_i^2}.

(Для w_i = 1, это сводится к обычному множителю N / (N - 1) с N = t + 1.) См. Взвешенная выборочная дисперсия для получения дополнительной информации.

© 2008–2012, AQR Capital Management, LLC, Lambda Foundry, Inc. and PyData Development Team
Licensed under the 3-clause BSD License.
https://pandas.pydata.org/pandas-docs/version/0.18.1/computation.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API