Kristof Pal
Kristof Pal

Reputation: 1026

Some complex list calculations and slicing; How to make it work?

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

Answers (2)

Kristof Pal
Kristof Pal

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

jonrsharpe
jonrsharpe

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

Related Questions