我的数据框“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
但它没有用。我真的很难将“功能”应用到每一行。但也许还有另一种方法可以做到这一点,而不是使用density()?
我基本上想要做的是从Dens()中提取拟合密度值到foo中的回报。如果我只是绘图(密度(foo $ Return))它会给我曲线,但是我希望将密度值附加到返回值。
@Joris:
foo$density <- density(foo$Return, n=nrow(foo$Return))$y
计算某些东西,但似乎返回错误的密度值。
感谢您帮助我! 达尼
答案 0 :(得分:4)
第二个想法,忘记密度函数,我突然意识到你想做什么。大多数密度函数返回一个网格,因此不要给出精确点的评估。如果您需要,可以使用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")
答案 1 :(得分:4)
sm.density
的替代方法是在比默认网格更精细的网格上评估密度,并使用approx
或approxfun
来提供{{1}处密度的插值} 你要。以下是虚拟数据的示例:
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
这给出了这样的东西:
只要在足够精细的一组点(上例中为512 * 8)中评估密度,就不应该有任何问题,并且很难说出内插版本和真实内容之间的区别。如果您的plot(dens)
with(foo, lines(sort(Returns), BAR(sort(Returns)), col = "red"))
值存在“差距”,那么您可能会发现,因为Returns
只是加入您要求它绘制的点,直线段可能不会跟随黑色密度间隙的位置。这只是间隙的假象以及lines()
的工作原理,而不是插值的问题。
答案 2 :(得分:2)
如果我们忽略@Joris熟练回答的density
问题,您似乎没有掌握如何设置循环。您从循环返回的是值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
如果要为循环的每次迭代插入返回值,则必须在循环中执行 赋值,这意味着在进入循环之前应预先分配存储空间,例如上面的循环,如果我们希望{1}} i + 1
在1,...,10中,我们可以这样做:
i
当然,你不会通过循环进行这样的计算,因为R是矢量化的并且可以使用数字向量,而不是像C或其他编程语言那样按元素编码每个计算元素。
> 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已将> bar <- 1:10 + 1
> bar
[1] 2 3 4 5 6 7 8 9 10 11
变为1
的足够长度的向量,以允许计算继续进行,在R-speak中称为 recycle 。< / p>
有时,您可能需要使用循环或使用1
系列之一迭代对象,但大多数情况下,您会发现一个函数可以一次性处理整个数据向量。这是R优于其他编程语言的优势之一,但确实需要您进入矢量化模式。
答案 3 :(得分:0)
使用它来获取密度值。
foo$density <- density(foo$Return, n=length(foo$Return))$y