4

我有一个看起来像这样的数据框“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 中的返回值。如果我只是做 plot(density(foo$Return)) 它给了我曲线,但是我希望将密度值附加到收益上。

@乔里斯:

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

计算一些东西,但似乎返回错误的密度值。

谢谢你帮助我!丹妮

4

4 回答 4

5

再想一想,忘记密度函数,我突然意识到你想做什么。大多数密度函数返回一个网格,所以不要给你精确点的评估。如果你想要,你可以使用这个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")
于 2010-12-20T10:56:54.250 回答
4

另一种方法sm.density是在比默认值更精细的网格上评估密度,并使用approxapproxfun给出所需的密度插值值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()进行插值,但我更喜欢which 做同样的事情,但返回一个函数,然后我们可以使用它来进行插值。首先,生成插值函数:xyapproxfun()

## 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"))

这给出了这样的东西: 密度(黑色)和插值版本(红色)

只要在一组点(上例中为 512*8)上对密度进行了足够精细的评估,您就不会有任何问题,并且很难区分插值版本和真实版本之间的差异。如果您的值中有“间隙”,Returns那么您可能会发现,正如lines()您要求它绘制的点一样,直线段可能不会跟随间隙位置处的黑色密度。这只是间隙和lines()工作原理的产物,而不是插值问题。

于 2010-12-20T13:32:01.437 回答
2

如果我们忽略density@Joris 专业回答的问题,您似乎还没有掌握如何设置循环。您从循环返回的是 value 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对于i1,...,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了一个足够长的 s 向量,以允许计算继续进行,这在 R-speak 中1称为循环。

有时,您可能需要使用循环或使用其中一个对象来迭代对象s|l|t|apply(),但大多数情况下,您会发现一个函数可以一次性处理整个数据向量。这是 R 相对于其他编程语言的优势之一,但确实需要您进入矢量化模式。

于 2010-12-20T13:04:54.390 回答
0

使用它来获取密度值。

foo$density <- density(foo$Return, n=length(foo$Return))$y
于 2020-10-05T15:33:46.557 回答