new-b question

D

David Newton

Hello all,

I am a ruby novice who would really appreciate some guidance with the
following:

I am trying to calculate a 5 day weighted moving average based on a set
of numbers in a data series. The most recent is given a * 5 weight, the
next * 4 etc etc. with the oldest (the 5th number) * 1.

n=5
dataset=[
25.0000,24.8750,24.7813,24.5938,24.5000,24.6250,25.2188,27.2500,26.2500,26.5938]

n.times do |period|
a = period+1
b = dataset[period]
c = a*b
puts c

end

output:

25.0
49.75
74.3439
98.3752
122.5

but what I now want it to do is add up the output and / 15, to give me
one number, approx 26.6646

Then using a loop, do the same again starting with the next number,
24.8750, and so on until it has gobe through the data series?

Many thanks for your time,

David
 
J

Joel VanderWerf

David said:
I am trying to calculate a 5 day weighted moving average based on a set
of numbers in a data series. The most recent is given a * 5 weight, the
next * 4 etc etc. with the oldest (the 5th number) * 1.

Does this help? You will need to handle the edge cases somehow...

$ ri Enumerable#each_cons | cat
--------------------------------------------------- Enumerable#each_cons
each_cons(n) {...}

From Ruby 1.8
------------------------------------------------------------------------
Iterates the given block for each array of consecutive <n>
elements.

e.g.:

(1..10).each_cons(3) {|a| p a}
# outputs below
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
[4, 5, 6]
[5, 6, 7]
[6, 7, 8]
[7, 8, 9]
[8, 9, 10]
 
J

John W Higgins

[Note: parts of this message were removed to make it a legal post.]

Hello all,

I am a ruby novice who would really appreciate some guidance with the
following:

I am trying to calculate a 5 day weighted moving average based on a set
of numbers in a data series. The most recent is given a * 5 weight, the
next * 4 etc etc. with the oldest (the 5th number) * 1.

This should do the trick for you

http://gist.github.com/131578

John
 
D

David Newton

thanks very much for the replies,

How would I do that using and amending the original code?

cheers
 
R

Robert Klemme

2009/6/18 John W Higgins said:
This should do the trick for you

http://gist.github.com/131578

Here's my suggestion

weights = (1..5).to_a
div = weights.inject(0){|s,x| s + x}.to_f

data = [
25.0000,
24.8750,
24.7813,
24.5938,
24.5000,
24.6250,
25.2188,
27.2500,
26.2500,
26.5938,
]

data.each_cons(weights.size).each_with_index do |c,i|
num = 0
c.zip(weights) {|a,b| num += a * b}
printf "period %2d: %8.3f\n", i, num / div
end

You only need to change 'weights' and the calculation will still.

Kind regards

robert
 
J

John W Higgins

[Note: parts of this message were removed to make it a legal post.]

thanks very much for the replies,

How would I do that using and amending the original code?

cheers
Are you still wishing to see all the intermediate steps (i.e. the value of
25*5, 24.857*4 etc etc etc)?

John
 
D

David Newton

John said:
Are you still wishing to see all the intermediate steps (i.e. the value
of
25*5, 24.857*4 etc etc etc)?

John

Hi John,

thanks for your patience.

In terms of the main objective, then no, they do not have to be there -
but I think it would help my understanding of what is happening if they
were there..
 
J

John W Higgins

[Note: parts of this message were removed to make it a legal post.]

...
Hi John,

thanks for your patience.

In terms of the main objective, then no, they do not have to be there -
but I think it would help my understanding of what is happening if they
were there..

Ok then lets remove some of the ruby tricks and just make the code work
because as most programmers do I've pushed you into the deep end and you are
looking to keep your feet solidly on the bottom of the pool while still
being able to breathe :)

Lets try this http://gist.github.com/132285 - a little more output at each
step. It's different then the first shot I took at it but it's also much
easier to digest each piece and see what it's doing.

John
 
D

David Newton

John said:
Ok then lets remove some of the ruby tricks and just make the code work
because as most programmers do I've pushed you into the deep end and you
are
looking to keep your feet solidly on the bottom of the pool while still
being able to breathe :)

Lets try this http://gist.github.com/132285 - a little more output at
each
step. It's different then the first shot I took at it but it's also much
easier to digest each piece and see what it's doing.

John

Hi John,

Thanks very much for that. It is very helpful. I think your summary is
pretty accurate of where I am right now - but I will get there!
 
R

Robert Klemme

2009/6/23 David Newton said:
Thanks very much for that. It is very helpful. I think your summary is
pretty accurate of where I am right now - but I will get there!

If it helps you I can also provide some commenting of the code I
posted. Just let me know.

Kind regards

robert
 
D

David Newton

Robert said:
If it helps you I can also provide some commenting of the code I
posted. Just let me know.

Kind regards

robert

Hi Again Robert,

I think I would find some comments on the code very helpful.

cheers

David
 
R

Robert Klemme

I think I would find some comments on the code very helpful.

Ok, here we go. The basic idea is to have a single definition of the
weight handling and separate the algorithm from that. That way we can
use the algorithm for whatever weighting schemes we want to apply. I
have "repackaged" the code into a method of module Enumerable which
seems appropriate considering the genericity of the approach.

Basically we have two inputs for the algorithm:
- enum of data
- weighting scheme

module Enumerable

def weighting(weights)
if block_given?
# input: weights
weights = weights.to_a

# derive the divisor once from the weights because
# it depends on the weights and does not change
# otherwise
div = weights.inject(0){|s,x| s + x}.to_f

# Now iterate through self using a sliding window
# of weights.size elements (this is done by each_cons)
# for each window we calculate the weighted average
# and yield it to the block passed to this method
# Array#zip is used to iterate the weights and the
# sliding window in lock step.
each_cons weights.size do |elements|
sum = 0
elements.zip(weights) {|n,w| sum += n * w}
yield sum / div
end

self
else
# create an Enumerator to allow for chaining.
enum_for:)weighting, weights)
end
end

end

# input to the calculation, weighting scheme:
weights = 1..5

# second input, our data
data = [
25.0000,
24.8750,
24.7813,
24.5938,
24.5000,
24.6250,
25.2188,
27.2500,
26.2500,
26.5938,
]

data.weighting(weights).each_with_index do |avg, i|
printf "period %2d: %8.3f\n", i, avg
end

Kind regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,175
Messages
2,570,942
Members
47,476
Latest member
blackwatermelon

Latest Threads

Top