2013-12-20 2 views
7

Есть ли способ приблизить периодичность временных рядов в пандах? Для R объекты xts имеют метод, называемый periodicity, который служит именно для этой цели. Есть ли реализованный метод для этого?Как я могу приблизиться к периодичности периода панды Серия

Например, можно ли вывести частоту из временных рядов, которые не указывают частоту?

import pandas.io.data as web 
aapl = web.get_data_yahoo("AAPL") 

<class 'pandas.tseries.index.DatetimeIndex'> 
[2010-01-04 00:00:00, ..., 2013-12-19 00:00:00] 
Length: 999, Freq: None, Timezone: None 

Частота этой серии может быть приближена к ежедневной.

Update:

Я думаю, что это может быть полезно, чтобы показать исходный код реализации АиР методы периодичности.

function (x, ...) 
{ 
    if (timeBased(x) || !is.xts(x)) 
     x <- try.xts(x, error = "'x' needs to be timeBased or xtsible") 
    p <- median(diff(.index(x))) 
    if (is.na(p)) 
     stop("can not calculate periodicity of 1 observation") 
    units <- "days" 
    scale <- "yearly" 
    label <- "year" 
    if (p < 60) { 
     units <- "secs" 
     scale <- "seconds" 
     label <- "second" 
    } 
    else if (p < 3600) { 
     units <- "mins" 
     scale <- "minute" 
     label <- "minute" 
     p <- p/60L 
    } 
    else if (p < 86400) { 
     units <- "hours" 
     scale <- "hourly" 
     label <- "hour" 
    } 
    else if (p == 86400) { 
     scale <- "daily" 
     label <- "day" 
    } 
    else if (p <= 604800) { 
     scale <- "weekly" 
     label <- "week" 
    } 
    else if (p <= 2678400) { 
     scale <- "monthly" 
     label <- "month" 
    } 
    else if (p <= 7948800) { 
     scale <- "quarterly" 
     label <- "quarter" 
    } 
    structure(list(difftime = structure(p, units = units, class = "difftime"), 
     frequency = p, start = start(x), end = end(x), units = units, 
     scale = scale, label = label), class = "periodicity") 
} 

Я думаю, что эта линия является ключом, который я не совсем понимаю, p <- median(diff(.index(x)))

+0

Возможно, поможет преобразование Фурье? – Paul

ответ

5

На этот раз серия пропускает выходные (и праздников), поэтому на самом деле у него нет ежедневной частоты для начала. Вы можете использовать asfreq для повышения частоты дискретизации его временного ряд с ежедневной частотой, однако:

aapl = aapl.asfreq('D', method='ffill') 

Это распространяется вперед последнее наблюдаемое значение даты с пропущенными значениями.

Обратите внимание, что панды также имеет рабочий день частоту, так что можно также повышающую дискретизацию в рабочие дни с помощью:

aapl = aapl.asfreq('B', method='ffill') 

Если вы хотите автоматизировать процесс выводя медианы частоты в дней, то вы можете сделать это:

import pandas as pd 
import numpy as np 
import pandas.io.data as web 
aapl = web.get_data_yahoo("AAPL") 
f = np.median(np.diff(aapl.index.values)) 
days = f.astype('timedelta64[D]').item().days 
aapl = aapl.asfreq('{}D'.format(days), method='ffill') 
print(aapl) 

Этот код нуждается в тестировании, но, возможно, речь идет о рядом с кодом R, который вы отправили:

import pandas as pd 
import numpy as np 
import pandas.io.data as web 

def infer_freq(ts): 
    med = np.median(np.diff(ts.index.values)) 
    seconds = int(med.astype('timedelta64[s]').item().total_seconds()) 
    if seconds < 60: 
     freq = '{}s'.format(seconds) 
    elif seconds < 3600: 
     freq = '{}T'.format(seconds//60) 
    elif seconds < 86400: 
     freq = '{}H'.format(seconds//3600) 
    elif seconds < 604800: 
     freq = '{}D'.format(seconds//86400) 
    elif seconds < 2678400: 
     freq = '{}W'.format(seconds//604800) 
    elif seconds < 7948800: 
     freq = '{}M'.format(seconds//2678400) 
    else: 
     freq = '{}Q'.format(seconds//7948800) 
    return ts.asfreq(freq, method='ffill') 

aapl = web.get_data_yahoo("AAPL") 
print(infer_freq(aapl)) 
3

Я не знаю, о частоте, единственной значимой мерой я могу придумать подло timedelta, для пример в дни:

>>> import numpy as np 
>>> idx = aapl.index.values 
>>> (np.roll(idx, -1) - idx)[:-1].mean()/np.timedelta64(1, 'D') 
1.4478957915831596 

или в часах:

>>> (np.roll(idx, -1) - idx)[:-1].mean()/np.timedelta64(1, 'h') 
34.749498997995836 

То же самое с более pandorable выражения, престижность к @DSM:

>>> aapl.index.to_series().diff().mean()/(60*60*10**9) 
34.749498997995993 

Конечно медиана будет 24 часа, как и большинство дней существует в списке:

>>> aapl.index.to_series().diff().median()/(60*60*10**9) 
24.0 
+2

Я думаю, что более удобно писать 'aapl.index.to_series(). Diff(). Mean()' или '.median()'. – DSM

+0

@DSM Спасибо, этот 'to_series' - это то, что я пропустил, чтобы использовать' .diff() '. – alko

Смежные вопросы