Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sum a function over a specific range in R?

Tags:

r

sum

Here are three columns:

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

I want to create a new column called 'Smoothed Y' by applying the following formula: enter image description here

D=15, delta (triangular symbol) = 5, i = indx, x_alpha(tk) = LocalY, x_alpha(ti) = smoothed value

I have tried using following code for first calculating Z: (Kernel below means the exp function)

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)

NOTE: 'a' is the imported data frame containing the three columns above.

Although the values of computed function are fine but it doesn't sum up the values in variable z. How can I do summation over the range i-d to i+d for every indx value i?

like image 695
umair durrani Avatar asked Oct 08 '13 00:10

umair durrani


1 Answers

You can use the convolve function. One thing you need to decide is what to do for indices closer to either end of the array than width of the convolution kernel. One option is to simply use the partial kernel, rescaled so the weights still sum to 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
}

With your array as y, the result is this:

> 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

Of course, the problem with this is that the kernel ends up non-centered at the edges. This is a well-known problem, and there are ways to deal with it but it complicates the problem. Plotting the data will show you the effects of this non-centering:

plot(y)
lines(yy) 

enter image description here

like image 52
mrip Avatar answered Oct 22 '22 01:10

mrip