Reputation: 1026
I've been working on a problem recently. The task seems easy to explain, but complex to code for me. I've tried many variations, but something in missing in all of them. Not sure what. Need someone for outside to have a say, as I get too deep in my way of thinking, and sometimes can not notice the simple stuff
I will try to simplify the problem here, to make it easier to understand.
So we have a list with objects in it
lst = [A0, A1, A2, A3, A4]
What I need to do is, run a method called predict()
, and from each element in lst
, get to the predicted element Ap
. This method has to run 3 times, so for A0
, I will get Ap1
, Ap2
, Ap3
. However, the calculations that predict()
performs rely on the previous element of the list, as well as on the result that it provides. So Ap1
is calculated only from A0
, but Ap2
is calculated from A0
and Ap1
(which are passed as input to predict()
, and Ap3
is calculated from A0, Ap1, Ap2
. And all these calculations are done fone A0
. The calculations become more complex as each subsequent element from lst
is considered, as the length of the initial input grows.
The "flowchart" below might be helpful.
========================================================
1) case A0
A0
---> predict([A0])
---> Ap1
A0, Ap1
---> predict([A0,Ap1])
---> Ap2
A0, Ap1, Ap2
---> predict([A0,Ap1,Ap2])
---> Ap3
=========================================================
2) case A1
- considers the previous element for the initial input as well
A0, A1
---> predict([A0,A1])
---> Ap2
A0, A1, Ap2
---> predict([A0,A1,Ap2])
---> Ap3
*|A0|* A1, Ap2, Ap3
---> predict([Ap1,Ap2,Ap3])
---> Ap4
[shortened input]
here is the tricky part, as you can notice the input data shifts one place on the right, when the input has more than 3 elements.
I decide to do this "sliding window" approach, because otherwise the input for calculating A17
, would include all AX
where X
< 17. So having 3 element at most as initial input is sufficient
============================================================
to further illustrate, I will also provide the case for A2
.
3) case A2
A0, A1, A2
---> predict([A0,A1,A2])
---> Ap3
*|A0|*, A1, A2, Ap3,
---> predict([A1,Ap2,Ap3])
---> Ap4
[shortened input]
*|A0|* *|A1|*, Ap2, Ap3, Ap4
---> predict([Ap2,Ap3,Ap4])
---> Ap5
[shortened input]
=============================================================
As you can see there is a general pattern when the initial input is longer than 3, and some "sliding window" approach has to be used. And there are specific cases when the initial input is smaller than 3
To simplify all these stuff I have used the following code:
current_trace = [[2,4,6,7,6,3],[1,2,5,7,2,7],[6,4,7,1,8,2]]
def predict(lst):
print "predicting for", lst
print "result", max(lst) + 0.0
return max(lst) + 0.0
approach 1:
for user_trace in current_trace:
y = 1
for counter in range(len(user_trace)):
while y <= 3:
x = 0
intermediate_list = user_trace[x:y]
while len(intermediate_list) <= 5:
next_prediction = predict(intermediate_list)
intermediate_list.append(next_prediction)
#predict(user_trace[x:y])
#print "@while" ,user_trace[x:y]
print "end of prediction \n"
y += 1
else:
print "\n"
x = y - 3
if len(user_trace[x:y]) == 3:
predict(user_trace[x:y])
#print "@else" ,user_trace[x:y]
else:
pass
y += 1
approach 2:
for user_trace in current_trace:
for slicer in range(len(user_trace)):
new_list = user_trace[:slicer+1]
if len(new_list) <= 3:
print "slicer:", slicer
print new_list
else:
print "slicer:", slicer
newer_list = new_list[-3:]
print newer_list
In both cases I am missing something, hope someone can give me a remark, or helpful suggestion, as I have occupied myself with this thing for couple of days now, and it is frustrating me!
Thanks in advance,
Best, W
Upvotes: 2
Views: 87
Reputation: 1026
Starting from the idea that @jonrsharpe suggested, I wrote a solution in this form
def predict(lst):
print "predicting for", lst
print "result", max(lst) + 0.0
return max(lst) + 0.0
def window(lst, n=3):
for x in range(1, len(lst)+1): # or len(l)+n to continue till the end
yield(lst[max(0, x-n):x])
def sliding_tristep(full_trace, future_step = 2, window_size = 3):
for user_trace in full_trace:
for current_input in window(user_trace):
counter = 0
trace = current_input
accumulator = []
while counter <= future_step: # this loop is used to define how many times you want to perform the given function (in this case predict())
next_prediction = predict(trace)
trace.append(next_prediction)
accumulator.append(next_prediction)
trace = trace[-window_size:] # slicing the next input happens here
counter += 1
print current_input, accumulator
Upvotes: 0
Reputation: 122150
I think what you want is a moving window, of length (up to) 3, on a list. You can do this as follows:
def windows(l, n=3):
for x in range(1, len(l)+n): # or len(l)+1 to stop at last full window
yield(l[max(0, x-n):x])
For example:
>>> list(windows([1,2,3,4,5]))
[[1], [1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5], [5]]
Upvotes: 3