题
我有一个像这样的数据框“ 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 $返回)),它会给我曲线,但是我想将密度值附加到返回上。
@Joris:
foo$density <- density(foo$Return, n=nrow(foo$Return))$y
计算某些东西,但是似乎返回错误的密度值。
谢谢您帮助我!丹妮
解决方案
第二次思考,忘记了密度功能,我突然意识到您想做什么。大多数密度功能返回网格,因此请勿在确切点中给您评估。如果需要,可以使用 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")
其他提示
替代方案 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"))
给出这样的东西:
只要在足够细的一组点上评估密度(在上面的示例中为512*8),您就不应该遇到任何问题,并且很难说出插值版本与真实事物之间的差异。如果您的值中有“差距” Returns
然后,您可能会发现 lines()
只需加入您要求它绘制的要点,直线段可能不会遵循间隙位置的黑色密度。这只是差距的人工制品以及如何 lines()
作品,插值不是问题。
如果我们忽略了 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
足够长的s可以进行计算,这就是所谓的 回收 在r-steak中。
有时,您可能需要在一个循环或使用其中一个的物体上迭代对象 s|l|t|apply()
一家人,但通常您会发现一个适用于整个数据向量的函数。这是R比其他编程语言的优点之一,但确实要求您进入 矢量化 模式。