Временные ряды являются сердцем экономических и финансовых исследований. Наиболее часто здесь используются такие понятия, как темпы роста и прибыль.
В R есть несколько очень мощных пакетов, предназначенных для работы с временными рядами. В данной статье мы рассмотрим их возможности.
Создание dataframe
Dataframe - это очень популярный объект в R. Он очень активно используется в различных областях. Если вы загружаете внешние данные с помощью функций “read.table”, “read.csv” или “read.xlsx”, результатом будет dataframe.
В начале любого скрипта R желательно сразу указать, сколько чисел после запятой вам требуется. Я предпочитаю два, но в определенных случаях может потребоваться большая точность. Во всех случаях мы также можем использовать для этого функцию round, например round(x, 5) - пять чисел после запятой для объекта "x".
options(digits = 2)
# Создаем dataframe для временных рядов рыночной капитализации и отношения PE.
> data <- data.frame(Date = c("12-12-2012", "13-12-2012", "14-12-2012", "16-12-2012","19-12-2012"), MktCap = c(110, 120, 130, 200, 180), PE = c(18, 18, 18.5, 19, 19))
> data
> data
Date MktCap PE
1 12-12-2012 110 18.0
2 13-12-2012 120 18.0
3 14-12-2012 130 18.5
4 16-12-2012 200 19.0
5 19-12-2012 180 19.0
Объект Timeseries
Несмотря на широкое применение и гибкость dataframe, многие важные операции при работе с временными рядами невозможно выполнить с использованием dataframe.
В R есть пакета, которые чаще всего используются для работы с временными рядами: ts (Timeseries) и xts(eXtensible Time Series). Во временных рядах всегда в наличии даты и значения индикатора, соответствующие датам.
Date
Функция “as.Date” позволяет напрямую конвертировать символьные данные в даты заданного формата. Приведенная ниже таблица описывает коды, используемые для различных форматов даты.
Код Значение Вывод
%d День месяца 01-31
%m Месяц в виде числа 01,02…,12
%b Месяц в виде аббревиатуры Jun Jul
%B Полное название месяца June July
%y Год без века 01, 02, …, 10
%Y Год с веком 2001,2002, …., 2010
> date <- "12-01-2014"
> date
[1] "12-01-2014"
> date
[1] "12-01-2014"
> class(date)
[1] "character"
[1] "character"
# по умолчанию 'as.Date' генерирует дату в формате YYYYMMDD
> date <- as.Date(date, "%d-%m-%Y")
> date
[1] "2014-01-12"
> date
[1] "2014-01-12"
> class(date)
[1] "Date"
[1] "Date"
Используя приведенную выше таблицу, мы можем получить дату в любом формате. Однако я предпочитаю конвертировать дату в другие форматы только в том случае, если это необходимо для отчета, поскольку функция "format" меняет класс вектора на "character", лишая нас преимуществ класса "Date".
> date
[1] "12-Январь-2014"
[1] "12-Январь-2014"
> class(date)
[1] "character"
[1] "character"
Значения индикатора или числа
Функция “as.numeric” конвертирует символьный вектор в числовой.
# Создаем вектор
> number <- c("20", "30", "90", "40")
> class(number)
[1] "character"
> class(number)
[1] "character"
> number
[1] "20" "30" "90" "40"
[1] "20" "30" "90" "40"
# Конвертируем символьный вектор 'number' в числовой
> number <- as.numeric(number)
> class(number)
[1] "numeric"
> class(number)
[1] "numeric"
> number
[1] 20 30 90 40
[1] 20 30 90 40
Конвертирование dataframe в объект xts
Объект xts представляет собой временной ряд. dataframe очень просто конвертируется в xts. Процесс происходит следующим образом:
конвертируем столбец данных из dataframe в класс “date” -> конвертируем значения столбца индикатора из dataframe в класс “numeric” -> используем функцию - конструктор “xts” для создания объекта временного ряда.
Теперь давайте использовать функцию 'ls.str' вместо 'class', чтобы увидеть классы различных векторов в нашем объекте. Она отображает внутреннюю структуру объекта R. В выводе str() на каждый столбец объекта приходится одна строка.
> str(data)
'data.frame': 5 obs. of 3 variables:
$ Date : Factor w/ 5 levels "12-12-2012","13-12-2012",..: 1 2 3 4 5
$ MktCap: num 110 120 130 200 180
$ PE : num 18 18 18.5 19 19
'data.frame': 5 obs. of 3 variables:
$ Date : Factor w/ 5 levels "12-12-2012","13-12-2012",..: 1 2 3 4 5
$ MktCap: num 110 120 130 200 180
$ PE : num 18 18 18.5 19 19
Столбец 'Date' является факторным. Мы преобразуем его в символьный, а затем в Date, всего одной строкой кода:
> date <- as.Date(as.character(data$Date), "%d-%m-%Y")
> class(date)
[1] "Date"
> class(date)
[1] "Date"
> date
[1] "2012-12-12" "2012-12-13" "2012-12-14" "2012-12-16" "2012-12-19"
[1] "2012-12-12" "2012-12-13" "2012-12-14" "2012-12-16" "2012-12-19"
> mktCap <- as.numeric(data$MktCap)
> class(mktCap)
[1] "numeric"
> class(mktCap)
[1] "numeric"
> mktCap
[1] 110 120 130 200 180
[1] 110 120 130 200 180
Создадим объект временного ряда xts. Обратите внимание на порядок расположения данных и дат при сборке объекта: xts(data,date).
> library(xts)
> mcData <- xts(mktCap, date)
> mcData
[,1]
2012-12-12 110
2012-12-13 120
2012-12-14 130
2012-12-16 200
2012-12-19 180
> mcData <- xts(mktCap, date)
> mcData
[,1]
2012-12-12 110
2012-12-13 120
2012-12-14 130
2012-12-16 200
2012-12-19 180
Базовое форматирование объектов временных рядов
Изменение имени индикатора (столбца) объекта
# Читаем данные котировок google, используя пакет quantmod
> library(quantmod)
> getSymbols("GOOG",src="google", from="2010-01-01", to="2015-01-01")
[1] "GOOG"
> getSymbols("GOOG",src="google", from="2010-01-01", to="2015-01-01")
[1] "GOOG"
> head(GOOG, 5)
GOOG.Open GOOG.High GOOG.Low GOOG.Close GOOG.Volume
2010-01-04 313.16 314.44 311.81 313.06 NA
2010-01-05 313.28 313.61 310.46 311.68 NA
2010-01-06 312.62 312.62 302.88 303.83 NA
2010-01-07 304.40 304.70 296.03 296.75 NA
2010-01-08 295.70 301.32 294.26 300.71 NA
GOOG.Open GOOG.High GOOG.Low GOOG.Close GOOG.Volume
2010-01-04 313.16 314.44 311.81 313.06 NA
2010-01-05 313.28 313.61 310.46 311.68 NA
2010-01-06 312.62 312.62 302.88 303.83 NA
2010-01-07 304.40 304.70 296.03 296.75 NA
2010-01-08 295.70 301.32 294.26 300.71 NA
# Выводим названия столбцов объекта GOOG
> colnames(GOOG)
[1] "GOOG.Open" "GOOG.High" "GOOG.Low" "GOOG.Close" "GOOG.Volume"
[1] "GOOG.Open" "GOOG.High" "GOOG.Low" "GOOG.Close" "GOOG.Volume"
# Изменяем названия столбцов
> colnames(GOOG) <- c("Open", "High", "Low", "Close", "Volume")
# Изменяем название только одного столбца.
# Например, изменим “Volume” на “Vol”.
> colnames(GOOG)[5] <- "Vol"
> colnames(GOOG)
[1] "Open" "High" "Low" "Close" "Vol"
> colnames(GOOG)
[1] "Open" "High" "Low" "Close" "Vol"
Удаление столбцов
Перед тем, как мы двинемся дальше, важно знать, как извлечь из объекта один столбец. В нашем объекте “GOOG” пять столбцов: "Open", "High", "Low", "Close" и "Vol". Извлечь из него один столбец можно несколькими способами.
# Способ 1
> high <- GOOG[, 2]
> head(high, 5)
High
2010-01-04 314.44
2010-01-05 313.61
2010-01-06 312.62
2010-01-07 304.70
2010-01-08 301.32
> head(high, 5)
High
2010-01-04 314.44
2010-01-05 313.61
2010-01-06 312.62
2010-01-07 304.70
2010-01-08 301.32
# Способ 2
> high <- GOOG$High
> head(high, 5)
High
2010-01-04 314.44
2010-01-05 313.61
2010-01-06 312.62
2010-01-07 304.70
2010-01-08 301.32
> head(high, 5)
High
2010-01-04 314.44
2010-01-05 313.61
2010-01-06 312.62
2010-01-07 304.70
2010-01-08 301.32
Давайте теперь удалим “High” из объекта “GOOG”.
> GOOG.ex.High <- GOOG[, -2]
> head(GOOG.ex.High, 5)
> head(GOOG.ex.High, 5)
Open Low Close Vol
2010-01-04 313.16 311.81 313.06 NA
2010-01-05 313.28 310.46 311.68 NA
2010-01-06 312.62 302.88 303.83 NA
2010-01-07 304.40 296.03 296.75 NA
2010-01-08 295.70 294.26 300.71 NA
Также просто можно удалить несколько столбцов из объекта с большим количеством данных. Мы будем использовать набор временных рядов, показывающих ВВП на душу населения в 165 странах с 1970 по 2010 год. Файл можно скачать здесь.
# Загружаем данные в R
> library(xlsx)
> rawdata <- read.xlsx("gdp.xlsx", sheetIndex = 1)
> str(rawdata)
> rawdata <- read.xlsx("gdp.xlsx", sheetIndex = 1)
> str(rawdata)
# Конвертируем дату в объекте 'rawdata'
> date <- as.Date(as.character(rawdata[, 1]), "%Y-%m-%d")
> data <- xts(rawdata[, -1], date)
> data <- xts(rawdata[, -1], date)
# Удалим следующий набор из объекта 'data'
> set <- c("Brazil.", "Russia", "India.", "China.", "South.Africa.")
#Удаляем столбцы этих стран из 'data' и сохраняем data в 'dataExBRICS'
> dataExBRICS <- data[, -(which(colnames(data) %in% set))]
# Количество столбцов в объектах 'data' и 'dataExBRICS'
> ncol(data)
[1] 255
[1] 255
> ncol(dataExBRICS)
[1] 250
[1] 250
Добавление столбцов (объединение двух объектов данных)
Объединим два объекта с одним и тем же временным индексом
> library(quantmod)
# Объект 1
> getSymbols("GOOG",src="google", from="2017-08-01", to="2017-08-30")
[1] "GOOG"
[1] "GOOG"
> head(GOOG, 5)
GOOG.Open GOOG.High GOOG.Low GOOG.Close GOOG.Volume
2017-08-01 932.38 937.45 929.26 930.83 1277734
2017-08-02 928.61 932.60 916.68 930.39 1824448
2017-08-03 930.34 932.24 922.24 923.65 1202512
2017-08-04 926.75 930.31 923.03 927.96 1082267
2017-08-07 929.06 931.70 926.50 929.36 1032239
GOOG.Open GOOG.High GOOG.Low GOOG.Close GOOG.Volume
2017-08-01 932.38 937.45 929.26 930.83 1277734
2017-08-02 928.61 932.60 916.68 930.39 1824448
2017-08-03 930.34 932.24 922.24 923.65 1202512
2017-08-04 926.75 930.31 923.03 927.96 1082267
2017-08-07 929.06 931.70 926.50 929.36 1032239
# Объект 2
> getSymbols("MSFT",src="google", from="2017-08-01", to="2017-08-30")
[1] "MSFT"
[1] "MSFT"
> head(MSFT, 5)
MSFT.Open MSFT.High MSFT.Low MSFT.Close MSFT.Volume
2017-08-01 73.10 73.42 72.49 72.58 20823890
2017-08-02 72.55 72.56 71.44 72.26 26499158
2017-08-03 72.19 72.44 71.84 72.15 18214424
2017-08-04 72.40 73.04 72.24 72.68 22578952
2017-08-07 72.80 72.90 72.26 72.40 18705681
MSFT.Open MSFT.High MSFT.Low MSFT.Close MSFT.Volume
2017-08-01 73.10 73.42 72.49 72.58 20823890
2017-08-02 72.55 72.56 71.44 72.26 26499158
2017-08-03 72.19 72.44 71.84 72.15 18214424
2017-08-04 72.40 73.04 72.24 72.68 22578952
2017-08-07 72.80 72.90 72.26 72.40 18705681
# Объединяем объект 1 и объект 2 в объект mergedData
> mergedData <- merge(GOOG, MSFT)
> head(mergedData)
GOOG.Open GOOG.High GOOG.Low GOOG.Close GOOG.Volume MSFT.Open MSFT.High MSFT.Low MSFT.Close MSFT.Volume
2017-08-01 932.38 937.45 929.26 930.83 1277734 73.10 73.42 72.49 72.58 20823890
2017-08-02 928.61 932.60 916.68 930.39 1824448 72.55 72.56 71.44 72.26 26499158
2017-08-03 930.34 932.24 922.24 923.65 1202512 72.19 72.44 71.84 72.15 18214424
2017-08-04 926.75 930.31 923.03 927.96 1082267 72.40 73.04 72.24 72.68 22578952
2017-08-07 929.06 931.70 926.50 929.36 1032239 72.80 72.90 72.26 72.40 18705681
2017-08-08 927.09 935.81 925.61 926.79 1061579 72.09 73.13 71.75 72.79 22044587
> head(mergedData)
GOOG.Open GOOG.High GOOG.Low GOOG.Close GOOG.Volume MSFT.Open MSFT.High MSFT.Low MSFT.Close MSFT.Volume
2017-08-01 932.38 937.45 929.26 930.83 1277734 73.10 73.42 72.49 72.58 20823890
2017-08-02 928.61 932.60 916.68 930.39 1824448 72.55 72.56 71.44 72.26 26499158
2017-08-03 930.34 932.24 922.24 923.65 1202512 72.19 72.44 71.84 72.15 18214424
2017-08-04 926.75 930.31 923.03 927.96 1082267 72.40 73.04 72.24 72.68 22578952
2017-08-07 929.06 931.70 926.50 929.36 1032239 72.80 72.90 72.26 72.40 18705681
2017-08-08 927.09 935.81 925.61 926.79 1061579 72.09 73.13 71.75 72.79 22044587
Добавление строк
# Объект 1
> AAPL1=getSymbols("AAPL",src="google", from="2017-08-01", to="2017-08-10", auto.assign=FALSE)
#Смотрим последние 5 значений
> tail(AAPL1, 5)
AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume
2017-08-04 156.07 157.40 155.69 156.39 20559852
2017-08-07 157.06 158.92 156.67 158.81 21870321
2017-08-08 158.60 161.83 158.27 160.08 36205896
2017-08-09 159.26 161.27 159.11 161.06 26131530
2017-08-10 159.90 160.00 154.63 155.32 40804273
AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume
2017-08-04 156.07 157.40 155.69 156.39 20559852
2017-08-07 157.06 158.92 156.67 158.81 21870321
2017-08-08 158.60 161.83 158.27 160.08 36205896
2017-08-09 159.26 161.27 159.11 161.06 26131530
2017-08-10 159.90 160.00 154.63 155.32 40804273
# Объект 2
> AAPL2=getSymbols("AAPL",src="google", from="2017-08-11", to="2017-08-20", auto.assign=FALSE)
> tail(AAPL2, 5)
AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume
2017-08-14 159.32 160.21 158.75 159.85 22122734
2017-08-15 160.66 162.20 160.14 161.60 29465487
2017-08-16 161.94 162.51 160.15 160.95 27671612
2017-08-17 160.52 160.71 157.84 157.86 27940565
2017-08-18 157.86 159.50 156.72 157.50 27428069
AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume
2017-08-14 159.32 160.21 158.75 159.85 22122734
2017-08-15 160.66 162.20 160.14 161.60 29465487
2017-08-16 161.94 162.51 160.15 160.95 27671612
2017-08-17 160.52 160.71 157.84 157.86 27940565
2017-08-18 157.86 159.50 156.72 157.50 27428069
# Добавляем к объекту 1 строки из объекта 2 с помощью функции 'append'
# Имена столбцов должны быть одинаковые
> AAPL <- append(AAPL1, AAPL2)
> tail(AAPL, 5)
AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume
2017-08-14 159.32 160.21 158.75 159.85 22122734
2017-08-15 160.66 162.20 160.14 161.60 29465487
2017-08-16 161.94 162.51 160.15 160.95 27671612
2017-08-17 160.52 160.71 157.84 157.86 27940565
2017-08-18 157.86 159.50 156.72 157.50 27428069
> tail(AAPL, 5)
AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume
2017-08-14 159.32 160.21 158.75 159.85 22122734
2017-08-15 160.66 162.20 160.14 161.60 29465487
2017-08-16 161.94 162.51 160.15 160.95 27671612
2017-08-17 160.52 160.71 157.84 157.86 27940565
2017-08-18 157.86 159.50 156.72 157.50 27428069
Выборка интервалов
> library(xlsx)
> library(xts)
# Загружаем данные по ценам на нефть с 2015 по 2017 год.
> monOilRawData <- read.xlsx("Oil.xlsx", sheetIndex = 1, startRow = 1)
> monOilData <- xts(monOilRawData[, -1], monOilRawData[, 1])
> monOilData <- xts(monOilRawData[, -1], monOilRawData[, 1])
# Выводим временной индекс
> index(monOilData)
[1] "2015-01-15" "2015-02-15" "2015-03-15" "2015-04-15" "2015-05-15" "2015-06-15" "2015-07-15" "2015-08-15"
[9] "2015-09-15" "2015-10-15" "2015-11-15" "2015-12-15" "2016-01-15" "2016-02-15" "2016-03-15" "2016-04-15"
[17] "2016-05-15" "2016-06-15" "2016-07-15" "2016-08-15" "2016-09-15" "2016-10-15" "2016-11-15" "2016-12-15"
[25] "2017-01-15" "2017-02-15" "2017-03-15" "2017-04-15" "2017-05-15" "2017-06-15" "2017-07-15" "2017-08-15"
[33] "2017-09-15"
[1] "2015-01-15" "2015-02-15" "2015-03-15" "2015-04-15" "2015-05-15" "2015-06-15" "2015-07-15" "2015-08-15"
[9] "2015-09-15" "2015-10-15" "2015-11-15" "2015-12-15" "2016-01-15" "2016-02-15" "2016-03-15" "2016-04-15"
[17] "2016-05-15" "2016-06-15" "2016-07-15" "2016-08-15" "2016-09-15" "2016-10-15" "2016-11-15" "2016-12-15"
[25] "2017-01-15" "2017-02-15" "2017-03-15" "2017-04-15" "2017-05-15" "2017-06-15" "2017-07-15" "2017-08-15"
[33] "2017-09-15"
# Используем функцию 'window' для выборки нужного нам интервала из объекта 'monOilData'
> subMonOilData <- window(monOilData, start = "2016-12-01", end = "2017-08-01")
> index(subMonOilData)
[1] "2016-12-15" "2017-01-15" "2017-02-15" "2017-03-15" "2017-04-15" "2017-05-15" "2017-06-15" "2017-07-15"
> index(subMonOilData)
[1] "2016-12-15" "2017-01-15" "2017-02-15" "2017-03-15" "2017-04-15" "2017-05-15" "2017-06-15" "2017-07-15"
Выборка столбца
> library(xlsx)
> library(xts)
> library(xts)
> rawdata <- read.xlsx2("gdp.xlsx", sheetIndex = 1)
> date <- as.Date(as.character(rawdata[, 1]), "%Y-%m-%d")
> data <- xts(rawdata[, -1], date)
> date <- as.Date(as.character(rawdata[, 1]), "%Y-%m-%d")
> data <- xts(rawdata[, -1], date)
# Выбираем данные по нужным нам странам из объекта 'data'
> set <- c("Brazil.", "Russia", "India.", "China.", "South.Africa.")
> dataExBRICS <- data[, (which(colnames(data) %in% set))]
> colnames(dataExBRICS)
> dataExBRICS <- data[, (which(colnames(data) %in% set))]
> colnames(dataExBRICS)
[1] "Russia" "Brazil." "China." "India." "South.Africa."
Изменение временного индекса
Дневной в недельный
# Загружаем дневные данные по курсу доллара за 2017 год
> usdrub <- read.csv(file = "usdrub.csv", header = TRUE)
> date <- as.Date(as.character(usdrub[, 1]), "%Y-%m-%d")
> UsdtoRub <- xts(usdrub[, -1], date)
> date <- as.Date(as.character(usdrub[, 1]), "%Y-%m-%d")
> UsdtoRub <- xts(usdrub[, -1], date)
> week.end <- endpoints(UsdtoRub, on = "weeks")
#Дневной в недельный - последние значения
> weekly <- period.apply(UsdtoRub, INDEX = week.end, FUN = last)
> head(weekly, 5)
[,1]
2017-01-14 59.3700
2017-01-21 59.6697
2017-01-28 60.3196
2017-02-04 59.3137
2017-02-11 58.8457
> head(weekly, 5)
[,1]
2017-01-14 59.3700
2017-01-21 59.6697
2017-01-28 60.3196
2017-02-04 59.3137
2017-02-11 58.8457
# дневной в недельный - средние значения
> weekly <- period.apply(UsdtoRub, INDEX = week.end, FUN = mean)
> head(weekly, 5)
[,1]
2017-01-14 59.77572
2017-01-21 59.44260
2017-01-28 59.56486
2017-02-04 59.97126
2017-02-11 59.05750
> head(weekly, 5)
[,1]
2017-01-14 59.77572
2017-01-21 59.44260
2017-01-28 59.56486
2017-02-04 59.97126
2017-02-11 59.05750
Дневной в месячный
# дневной в месячный - последние значения
> month.end <- endpoints(UsdtoRub, on = "months")
> monthly <- period.apply(UsdtoRub, INDEX = month.end, FUN = last)> head(monthly, 5)
[,1]
2017-01-31 60.1618
2017-02-28 57.9371
2017-03-31 56.3779
2017-04-29 56.9838
2017-05-31 56.5168
> monthly <- period.apply(UsdtoRub, INDEX = month.end, FUN = last)> head(monthly, 5)
[,1]
2017-01-31 60.1618
2017-02-28 57.9371
2017-03-31 56.3779
2017-04-29 56.9838
2017-05-31 56.5168
# дневной в месячный - средние значения
> monthly <- period.apply(UsdtoRub, INDEX = month.end, FUN = mean)
> head(monthly, 5)
[,1]
2017-01-31 59.62986
2017-02-28 58.53936
2017-03-31 58.00663
2017-04-29 56.43561
2017-05-31 56.95007
> head(monthly, 5)
[,1]
2017-01-31 59.62986
2017-02-28 58.53936
2017-03-31 58.00663
2017-04-29 56.43561
2017-05-31 56.95007
Комментариев нет:
Отправить комментарий