Значение плотности для каждого возврата - PullRequest
3 голосов
/ 20 декабря 2010

У меня есть датафрейм "foo", похожий на этот

Date       Return
1998-01-01  0.02
1998-01-02  0.04
1998-01-03 -0.02
1998-01-04 -0.01
1998-01-05  0.02
...
1998-02-01  0.1
1998-02-02 -0.2
1998-02-03 -0.1
etc.

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

foo$density <- for(i in 1:length(foo$Return)) density(foo$Return, 
from = foo$Return[i], to = foo$Return[i], n = 1)$y

Но это не сработало. У меня действительно есть трудности с применением "функции" для каждой строки. Но, может быть, есть и другой способ сделать это, не используя плотность ()?

Что я, по сути, хотел бы сделать, это извлечь значения плотности из плотности () для возвращаемых значений в foo. Если я просто сделаю график (плотность (foo $ Return)), он даст мне кривую, однако я бы хотел, чтобы значения плотности были прикреплены к результатам.

@ Йорис:

foo$density <- density(foo$Return, n=nrow(foo$Return))$y 

что-то вычисляет, но, похоже, возвращает неправильные значения плотности.

Спасибо, что помогли мне! Dani

Ответы [ 3 ]

4 голосов
/ 20 декабря 2010

Альтернативой sm.density является оценка плотности на более тонкой сетке, чем по умолчанию, и используйте approx или approxfun для получения интерполированных значений плотности на желаемом Returns. Вот пример с фиктивными данными:

set.seed(1)
foo <- data.frame(Date = seq(as.Date("2010-01-01"), as.Date("2010-12-31"),
                             by = "days"),
                  Returns = rnorm(365))
head(foo)
## compute the density, on fin grid (512*8 points)
dens <- with(foo, density(Returns, n = 512 * 8))

На этом этапе мы могли бы использовать approx() для интерполяции x и y компонентов возвращаемой плотности, но я предпочитаю approxfun(), который делает то же самое, но возвращает функцию, которую мы затем можем использовать сделать интерполяцию. Сначала сгенерируйте функцию интерполяции:

## x and y are components of dens, see str(dens)
BAR <- with(dens, approxfun(x = x, y = y))

Теперь вы можете использовать BAR(), чтобы вернуть интерполированную плотность в любой точке, которую вы хотите, например, за первый Returns:

> with(foo, BAR(Returns[1]))
[1] 0.3268715

Чтобы завершить пример, добавьте плотность для каждого элемента в Returns:

> foo <- within(foo, Density <- BAR(Returns))
> head(foo)
        Date    Returns   Density
1 2010-01-01 -0.6264538 0.3268715
2 2010-01-02  0.1836433 0.3707068
3 2010-01-03 -0.8356286 0.2437966
4 2010-01-04  1.5952808 0.1228251
5 2010-01-05  0.3295078 0.3585224
6 2010-01-06 -0.8204684 0.2490127

Чтобы увидеть, насколько хорошо работает интерполяция, мы можем построить плотность и интерполированную версию и сравнить. Обратите внимание, что мы должны отсортировать Returns, потому что для достижения желаемого эффекта, lines необходимо просматривать данные в порядке по возрастанию:

plot(dens)
with(foo, lines(sort(Returns), BAR(sort(Returns)), col = "red"))

Что дает что-то вроде этого: Density (in black) and interpolated version (in red)

Пока плотность оценивается при достаточно точном наборе точек (512 * 8 в приведенном выше примере), у вас не должно быть никаких проблем, и вам будет трудно сказать разницу между интерполированной версией и реальной вещью , Если у вас есть «пробелы» в значениях вашего Returns, то вы можете обнаружить, что, поскольку lines() просто соединяет точки, которые вы просите построить, сегменты прямых линий могут не следовать плотности черного в местах расположения пробелов , Это просто артефакт пробелов и того, как работает lines(), а не проблема с интерполяцией.

4 голосов
/ 20 декабря 2010

Подумав, забудь о функции плотности, я вдруг понял, что ты хотел сделать.Большинство функций плотности возвращают сетку, поэтому не давайте оценку в точных точках.Если вы хотите этого, вы можете, например, использовать пакет sm:

require(sm)
foo <- data.frame(Return=rpois(100,5))
foo$density <- sm.density(foo$Return,eval.points=foo$Return)$estimate
# the plot
id <- order(foo$Return)
hist(foo$Return,freq=F)
lines(foo$Return[id],foo$density[id],col="red")

Если число различных значений не так велико, вы можете использовать ave ():

foo$counts <- ave(foo$Return,foo$Return,FUN=length)

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

plot(density(foo$Return))

Или, чтобы добавить гистограмму внизу (обратите внимание на опцию freq=F)

hist(foo$Return,freq=F)
lines(density(foo$Return),col="red")
2 голосов
/ 20 декабря 2010

Если мы игнорируем проблему density, на которую @Joris опытно отвечает, вы, похоже, не поняли, как настроить цикл.То, что вы возвращаете из цикла, это значение NULL.Это значение, которое вставляется в foo$density, и оно не будет работать, потому что это NULL, что означает, что он является пустым компонентом, то есть он не существует в отношении R.Подробнее см. ?'for'.

> bar <- for(i in 1:10) {
+     i + 1
+ }
> bar
NULL

> foo <- data.frame(A = 1:10, B = LETTERS[1:10])
> foo$density <- for(i in seq_len(nrow(foo))) {
+     i + 1
+ }
> head(foo) ## No `density`
  A B
1 1 A
2 2 B
3 3 C
4 4 D
5 5 E
6 6 F

Если вы хотите вставить возвращаемое значение для каждой итерации цикла, вы должны выполнить присваивание внутри цикла, а это означаетВы должны предварительно выделить место для хранения перед входом в цикл, например, в приведенном выше цикле, если мы хотим получить i + 1 для i в 1, ..., 10, мы могли бы сделать это:

> bar <- numeric(length = 10)
> for(i in seq_along(bar)) {
+     bar[i] <- i + 1
+ }
> bar
 [1]  2  3  4  5  6  7  8  9 10 11

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

> bar <- 1:10 + 1
> bar
 [1]  2  3  4  5  6  7  8  9 10 11

Обратите внимание, что R превратил 1 в вектор 1 с достаточной длины, чтобы можно было продолжить вычисления, что известно как recycling в R-говорить.

Иногда вам может понадобиться перебрать объект с помощью цикла или с использованием одного из семейств s|l|t|apply(), но чаще всего вы найдете функцию, которая работает для всего вектора данных в одномидти.Это одно из преимуществ R по сравнению с другими языками программирования, но оно требует, чтобы вы погрузились в режим векторизация .

...