如何在R中针对特定区间求函数的总和?

5

这里有三列:

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

我希望创建一个名为“平滑Y”的新列,通过应用以下公式来实现:enter image description here 其中,D = 15,Δ(三角形符号)= 5,i = indx,x_alpha(tk)= LocalY,x_alpha(ti)= 平滑值。
我尝试使用以下代码首先计算Z:(下面的Kernel表示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 - Frank
你能否编写一个函数来返回Z(i,D)的值,另一个函数使用它来返回局部sum_i。然后在足够数据形成总和的“i”范围内计算该总和。 - IRTFM
保持D和i不变,Z和X是在k范围内变化的向量...其中对于Z,我指的是你的指数项。 - Frank
如果D是一个变量,那么请相应地编写您的函数。 - IRTFM
我已经尝试了很多代码的变化,但仍然没有成功。如果有人能写一些代码来指导我,我将不胜感激。 - umair durrani
显示剩余6条评论
1个回答

5
你可以使用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) 

enter image description here


1
@cryo111 我使用第二个卷积的原因仅仅是为了在核运行到数组末尾时正确地对其进行归一化。如果没有边缘,我们可以只对z进行一次归一化。我也可以只对z进行一次归一化,然后编写更多的代码来处理边缘附近的重新加权,但我很懒,所以我用了这种效率较低的方法。 - mrip
非常抱歉,我对您的解决方案一点也不理解。您能否指导我去哪里查看R文档,以便我能够理解卷积函数? - umair durrani
在 R 提示符下键入 ?convolve(或 ?filter)。 - mrip
@cryo111 谢谢。如果有一个选项可以进行“过滤”或“卷积”,即使在边缘也可以进行归一化,那就太好了。我相信某个库中有一个函数可以实现这个功能,但我不知道它是什么。 - mrip
对于可能有用的内置函数,请查看??'kernel'。 "np"包也可能有一些有用的东西... - Frank
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接