【问题标题】:How to sum a function over a specific range in R?如何对R中特定范围内的函数求和?
【发布时间】:2013-10-08 00:09:28
【问题描述】:

这里有三列:

indx    vehID   LocalY
1   2   35.381
2   2   39.381
3   2   43.381
4   2   47.38
5   2   51.381
6   2   55.381
7   2   59.381
8   2   63.379
9   2   67.383
10  2   71.398
11  2   75.401
12  2   79.349
13  2   83.233
14  2   87.043
15  2   90.829
16  2   94.683
17  2   98.611
18  2   102.56
19  2   106.385
20  2   110.079
21  2   113.628
22  2   117.118
23  2   120.6
24  2   124.096
25  2   127.597
26  2   131.099
27  2   134.595
28  2   138.081
29  2   141.578
30  2   145.131
31  2   148.784
32  2   152.559
33  2   156.449
34  2   160.379
35  2   164.277
36  2   168.15
37  2   172.044
38  2   176
39  2   179.959
40  2   183.862
41  2   187.716
42  2   191.561
43  2   195.455
44  2   199.414
45  2   203.417
46  2   207.43
47  2   211.431
48  2   215.428
49  2   219.427
50  2   223.462
51  2   227.422
52  2   231.231
53  2   235.001
54  2   238.909
55  2   242.958
56  2   247.137
57  2   251.247
58  2   255.292
59  2   259.31
60  2   263.372
61  2   267.54
62  2   271.842
63  2   276.256
64  2   280.724
65  2   285.172

我想通过应用以下公式创建一个名为“Smoothed Y”的新列:

D=15,delta(三角形符号)= 5,i = indx,x_alpha(tk) = LocalY,x_alpha(ti) = 平滑值

我尝试使用以下代码首先计算 Z:(下面的内核表示 exp 函数)

t <- 0.5
dt <- 0.1
delta <- t/dt
d <- 3*delta
indx <- a$indx
for (i in indx) {
initial <- i-d
end <- i+d
k <- c(initial:end)
for (n in k) {
kernel <- exp(-abs(i-n)/delta)
z <- sum(kernel)
}
}
a$z <- z
print (a)

注意:“a”是包含上述三列的导入数据框。

虽然计算函数的值很好,但它并没有总结变量 z 中的值。如何对每个索引值 i 在 i-d 到 i+d 范围内求和?

【问题讨论】:

  • 您正在“n”循环内覆盖“z”和“kernel”。试试z = z + kernel
  • 您能否编写一个返回 Z(i,D) ​​值的函数和另一个使用它返回本地 sum_i 的函数。然后在“i”的范围内计算该总和,您将有足够的数据来形成总和。
  • z=z+kernel 如果您真的想循环播放,可能会起作用。但是,考虑到问题的结构,使提到的两个向量 DWin 更有意义。你的结束值只是Z'X/sum(Z)
  • @DWin 我不明白你的建议。您可以看到函数 Z 包含需要求和的项 i 和 k
  • 保持 D 和 i 不变,Z 和 X 是范围超过 k 的向量...其中 Z 是指指数项。

标签: r sum


【解决方案1】:

您可以使用convolve 函数。您需要决定的一件事是,对于比卷积核宽度更接近数组两端的索引要做什么。一种选择是简单地使用部分内核,重新调整后权重之和仍为 1。

smooth<-function(x,D,delta){
  z<-exp(-abs(-D:D)/delta)
  r<-convolve(x,z,type="open")/convolve(rep(1,length(x)),z,type="open")  
  r<-head(tail(r,-D),-D)
  r
}

如果你的数组是y,结果是这样的:

> yy<-smooth(y,15,5)
> yy
 [1]  50.70804  52.10837  54.04788  56.33651  58.87682  61.61121  64.50214
 [8]  67.52265  70.65186  73.87197  77.16683  80.52193  83.92574  87.36969
[15]  90.84850  94.35809  98.15750 101.93317 105.67833 109.38989 113.06889
[22] 116.72139 120.35510 123.97707 127.59293 131.20786 134.82720 138.45720
[29] 142.10507 145.77820 149.48224 153.21934 156.98794 160.78322 164.60057
[36] 168.43699 172.29076 176.15989 180.04104 183.93127 187.83046 191.74004
[43] 195.66223 199.59781 203.54565 207.50342 211.46888 215.44064 219.41764
[50] 223.39908 227.05822 230.66813 234.22890 237.74176 241.20236 244.60039
[57] 247.91917 251.14346 254.25876 257.24891 260.09121 262.74910 265.16057
[64] 267.21598 268.70276

当然,这样做的问题是内核最终在边缘不居中。这是一个众所周知的问题,有办法解决它,但它使问题复杂化。绘制数据将显示这种非居中的影响:

plot(y)
lines(yy) 

【讨论】:

  • filter 也可以使用。 @mrip BTW:转到相对坐标\tau=k-i 可以看到Z 是一个常数。因此,您可以规范化您的(小写)z,而不是使用第二个convolve.
  • @cryo111 我使用第二个卷积的原因只是为了让内核在边缘正确归一化,其中部分内核从数组的末端跑出。如果不是边缘,我们可以将z 标准化一次。我也可以只对z 进行一次标准化,然后编写更多代码来处理边缘附近的重新加权,但我很懒,所以我这样做了,效率较低。
  • 好的!我明白。非常好的答案顺便说一句。
  • 我真的很抱歉我对你的解决方案有点理解。您能否指导我阅读任何我可以理解卷积函数的 R 文档?
  • 在 R 提示符下输入?convolve(或?filter)。
猜你喜欢
  • 2020-11-17
  • 1970-01-01
  • 1970-01-01
  • 2016-09-11
  • 2018-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-11
相关资源
最近更新 更多