pedroelbanquero / geometric-extrapolation

Probnet - geometric extrapolation with error prediction
Other
4 stars 2 forks source link

How do you calculate the predicted value of the next error ? #1

Closed victorel-petrovich closed 2 months ago

victorel-petrovich commented 2 months ago

In next fragment:

err = zipWith subtract it (drop 2 fibo)
[-1.0,0.5,-0.3333333333333339,0.1999999999999993]

predict1 it
-0.1333333333333331

21.125 - 0.1333333333333331 = 20.991666666666667

how did you get the -0.1333333333333331 ? I could not obtain it by either adding or multiplying something to the last error in that sequence.

Thank you

pedroelbanquero commented 2 months ago

if you look at the source code you will see that we always use 4 consecutive values ​​of a sequence, we use the last value to calculate the error, we predict the 4th value and since we have the original 4th value we can calculate the difference by subtracting the prediction from the last value. this could be applied in consecutive layers with more values ​​of a sequence, the implementation is only one layer, but the same could be done recursively the more elements of the series we have. It works on practically any data sequence that does not involve prime numbers from OEIS.org. you can try it with hundreds of sequences from this website. for example https://oeis.org/A001318 image image

pedroelbanquero commented 2 months ago

Algorithm just use last 4 consecutive inputs of a sequence . I recommend use the code published https://github.com/pedroelbanquero/geometric-extrapolation/blob/main/Probnet.hs

victorel-petrovich commented 2 months ago

Thanks for replying, but it's still not clear at all. I'm not familiar with Haskell... So I just want to understand the idea of the algorithm.

I had understood how to get the predicted 21.125, as 13*(13/8). Also how to get the entire list of predicted values: [4.0,4.5,8.333333333333334,12.8,21.125] And how to get the list of errors as true-predicted: [-1.0,0.5,-0.3333333333333339,0.1999999999999993]

But what is not clear is how do you get next value for error: -0.1333333333333331 ? It seems to be -0.3333333333333339+0.1999999999999993 , but why would you add them ?

Trying to get it in same way as 21.125 was obtained, it fails: 0.199*(0.199/-0.33)= -0.12 , not -0.13333

Is it explained somewhere else? even in another language; I can translate.

victorel-petrovich commented 2 months ago

I also looked at https://github.com/pedroelbanquero/geometric-extrapolation?tab=readme-ov-file#conclusion and the numbers there at the end: round $ ((3*1.66)-5) + (5*1.6) = 8 appear to be wrong: d2=5/3=1.6666 not 1.6 and d1=3/2=1.5 not 1.666

More importantly, why is the formula: fnos (m,n,d1,d2) = round ( ( ( n * d1 ) - m ) + ( m * d2 ) ) ? prediction= m * d2, ok; error= true-prediction true=prediction+error = prediction + (true-prediction) So should not error be m-(n*d1) as opposed to ( n * d1 ) - m?

pedroelbanquero commented 2 months ago

The idea of ​​the algorithm is simple, we predict each next element of the sequence and compare it with the original series, generating a sequence of errors, then we predict what the next error would be, then we predict the next element of the series and subtract the error we have made from the prediction.

You're right, the formula example is wrong. Because example is 1,2,3,5,8,13 , i made wrong copy paste when i put as a math formula

https://hackage.haskell.org/package/Probnet

image

.... 5/3 = 1.666 8/5 = 1.6 13/8 = 1.625 ....

pedroelbanquero commented 2 months ago

Algo works fine i just made a bad math explanation sorry image I will correct it as soon as possible

victorel-petrovich commented 2 months ago

then we predict what the next error would be

how exactly? because the numbers in your 2 examples don't work out.

On the example that you have just corrected: round $ ((3*1.5)-5) + (5*1.66) = 8 eq (1)

(3*1.5)-5) + (5*1.66)=-0.5+8.333 = 7.833 , so round(7.833)= 8, you get the right value, but it seems to be an accident:

3*1.5-5 = old prediction - old true =4.5 -5 = -0.5, so error = true-prediction = 0.5 So to get true value, starting from prediction, you need to do: prediction -(prediction-true) = prediction + (true-prediction) = prediction + error

But in eq(1) above, you have contradiction: (old prediction - old true)+new prediction
-- which means you have: prediction - error

pedroelbanquero commented 2 months ago

yes , as the same way, you have the sequence of errors [-1.0,0.5,-0.3333333333333339,0.1999999999999993]

5 - 4.5 = 0.5 8 - 8.3333 = -0.333333 13 -12.8.... = 0.1999999

as we extrapolate the values with the function [4.0,4.5,8.333333333333334,12.8,21.125] we do the same with the errors

ghci> predict1 [-1.0,0.5,-0.3333333333333339,0.1999999999999993]
-0.1333333333333331

the result on this case fibbonacci sequence

ghci>  - 0.1333 + 21.125 
20.9917
ghci> round it
21

in the example of math function one part of the formula is the error and other the extrapolation as you comment before

error + extrapolation

error = ( n d1 ) - m ) extrapolation = ( m d2 )

anyway the best, is use the haskell code, I'm not really good on math , and i do that some years ago from a dream I had

to use the code just type in console after install haskell

ghci Probnet.hs

this will load the haskell script , and you can play with the functions . haskell functions have more cases to solve another things like cyclic patterns, anyway algo is not finished , just take in consideration 1 layer , and not have implemented yet frequency variation of the dataset , just pseudo cyclic patterns with same frequency for example 12345,12345,12345 but not 12345,123456,1234567 .... this is pending yet . i do the algorithm from logic's and after i was trying to explain in math terms , but I'm not really good on math ..... if you are, i can share my ideas to you or we can develop more over the repo . i really appreciate your interest , you are the first interested on that HAHA .

Thanks for the example correction , i corrected also on Wikipedia page https://en.wikipedia.org/wiki/Extrapolation

pedroelbanquero commented 2 months ago

is not an accident, you can apply that to many many sequence just test that on haskell and you can check , really crazy data sequences until infinite with no error of prediction let me show some

A049450

ghci> probnet 3 [2, 10, 24, 44, 70, 102, 140, 184, 234, 290, 352, 420, 494] [2,10,24,44,70,102,140,184,234,290,352,420,494,574,660,752]

https://oeis.org/A152743

ghci> probnet 3 [6, 30, 72, 132, 210, 306, 420, 552, 702] [6,30,72,132,210,306,420,552,702,870,1056,1260]

pedroelbanquero commented 2 months ago

thousands of sequences , incremental sequences for the algo now because is a simple version polynomials with different degree can be solved with the same function

pedroelbanquero commented 2 months ago

algo can be improved a lot yet, taking care of frequencies, and incremental and decrement , changes and combine , and also adding probability issues of the dataset , and recursion layer for error prediction, for example some sequence are not correct, but have another layer of errors, for example [0,1,0,1,0,1] this happens with many sequences also that not solve correctly but can be improved to solve with another layer of errors, i think is some kind of principle of AI for maths, another way to solve math functions , with no model, well the model is just the input data

pedroelbanquero commented 2 months ago

also can be used as notation of functions keeping the main points of sequence , many sequence starts with same numbers but in some point converges to another sequence, sometimes seems algo not works for a sequence but when you get the sample data more in the "future" of the dataset, at this "moment" / "index" , sequence will be solved until infinite with 100 % accuracy .

in reality i was trying to encode information as the functions who generate the information instead of encode the observable data, but i found that , i imagine information as a some point of a data sequence in the future and idea was try to encode the beginning points of a sequence and the moments to arrive to this future of information . this was the motivation, but as i said I'm just amateur on this things and no many academic knowledge , please share your discoverers if you find something more

victorel-petrovich commented 2 months ago

Thanks for your replies. I did not doubt that your program works. But just could not understand the explanations / numbers.

Yes, I find the whole idea interesting. Maybe later we can discuss future improvments for the algorithm.

But for now, let's finish correcting the explanation you have written for the shorter example. I think now I know what is going on:

For the example with extrapolating the value after 13, (21.125), you have produced the new error = -0.1333, by calling predict1 function on the sequence of (true) errors [-1.0,0.5,-0.3333333333333339,0.1999999999999993]

But for the example for extrapolating value after 5, (8.33), to get the new error= -0.5, you did not use predict1 on errors [-1.0,0.5] but instead you have implicitely written error= (3*1.5-5). Which is misleading.

Can you please test at your command line:

ghci> predict1 [-1.0 , 0.5 ]
pedroelbanquero commented 2 months ago

I can't because function need at least 4 consecutive points , reason because example with just 1,2,3,5 was not good example and example with haskell is until 13 of fibo sequence by this reason. i need to review the code to know how i solve that because works anyway, let me review

ghci> probnet 7 [1,2,3,5]
[1,2,3,5,8,13,21,34,55,89,144]

my apologies to be a disaster guy , let me a moment

victorel-petrovich commented 2 months ago

My understanding is this: the algorithm should extrapolate the sequence of (true) errors [-1.0 , 0.5 ] using same idea as it extrapolated from [1 2 3 5] : 5*(5/3) = 8.333 Thus, extrapolation for errors is : 0.5*(0.5/-1) = -0.25. And this works: round (8.333 + -0.25 ) = 8 = true value

But if I use same ideas for extrapolation beyond [-1.0,0.5,-0.3333333333333339,0.1999999999999993] , then get new error = 0.2*(0.2/-0.3333) = -0.12. This is different from -0.133333 you wrote earlier, but works: round (21.125 + -0.12 ) = round (21.005) = 21 = true value

pedroelbanquero commented 2 months ago
-- | Generate new prediction with error prediction 
probnet :: (Integral b, RealFrac a) => Int -> [a] -> [b]
probnet layers dat
   | layers > 1   = probnet (layers - 1) $ map (\x-> fromIntegral (round x)) out 
   | otherwise    = fmap round out
   where
   out = dat ++ [(predict1 dat + prerr dat)]

-- | This is the next prediction for the difference between each 
-- original element and its prediction based on previous elements
prerr :: RealFrac a => [a] -> a
prerr dat 
   | last err == 0   = 0 
   | otherwise       = predict1 $ drop 2 err
   where  
   err   = zipWith subtract pred dat -- differences between elements and its predictions
   pred  = fmap predict1 $ inits dat -- 2 first inits have 0 and 1 elements, will be dropped

This is what is doing exactly the haskell code, is right is not the good explanation in math form

ghci> prerr [1,2,3,5]
-0.25
ghci> predict
predict   predict1
ghci> predict1 [1,2,3,5]
8.333333333333334
ghci> it - 0.25
8.083333333333334
pedroelbanquero commented 2 months ago

prerr for [1,2,3,5] is -0.25 you are right

victorel-petrovich commented 2 months ago

and I guess if you check prerr [1,2,3,5, 8, 13] you will get about -0.12

pedroelbanquero commented 2 months ago

ghci> prerr [1,2,3,5,8,13] -0.1333333333333331

no in this case i get -0.1333333333333331

pedroelbanquero commented 2 months ago

maybe by number of decimals ?

pedroelbanquero commented 2 months ago
predict1 :: RealFrac a => [a] -> a
predict1 dat  
   -- | l1 == (eleml+1) = (ratio1 (dat) (eleml+1)) * last dat 
   | otherwise = (ratio1 dat eleml) * last dat
   where
   Just eleml = elemIndex ned dat
   ned = nearnum (last $ dat) (init dat)
   l1 = length dat
   l = last $ init dat
   lastper = last dat 

nearnum :: RealFrac a => a -> [a] -> a
nearnum n = minimumBy nearer
   where
   nearer x y = compare (abs (x - n)) (abs (y - n))
pedroelbanquero commented 2 months ago

nearnum compare if is LT or GT

victorel-petrovich commented 2 months ago

I got that -0.12 as explained in 2nd paragraph in https://github.com/pedroelbanquero/geometric-extrapolation/issues/1#issuecomment-2278952452

but now I guess that since we have a sequence of 4 (not just 2) values (of errors), [-1.0,0.5,-0.3333333333333339,0.1999999999999993] , the algo will apply recursively, just like in case of 4 values [ 1,2,3,5], and so it will attempt to improve on the -0.12 extrapolation.

I'll check on paper and let you know.

pedroelbanquero commented 2 months ago

Cool man , thanks so much, we will make corrections on Wikipedia, was wrong some years HAHAHA,

pedroelbanquero commented 2 months ago

feel free to pull request your modifications on README and i will merge

victorel-petrovich commented 2 months ago

I tested my guess above (that the algo does to the sequence of errors same thing as for initial sequence, recursively),doesn't work:

Below, 0.(3) means 0.33333...

1        2        3        5        8        13    
                  4        4.5      8.(3)    12.8     21.125      
-------------------------------------------------------------------
                  -1       0.5      -0.(3)   0.2
                                    -0.25    0.(2)    -0.12
-------------------------------------------------------------------
                                    -0.08(3) -0.0(2)
                                                      -0.0059(259)

-0.0059(259) + -0.12 + 21.125 = -0.1(259) + 21.125 = 20.999074                  

For extrapolated error, gives ~ -0.1259, not -0.13333 . So you code must be doing something different to predict / extrapolate the error values. Maybe another hint is that in Readme, you mentioned that you would not apply this algorithm to values that alternate in sign; the errors here do.

victorel-petrovich commented 2 months ago

Guess #2: on Readme, https://github.com/pedroelbanquero/geometric-extrapolation?tab=readme-ov-file#sequences-with-quasi-cyclic-pattern , you say " the ratio used for prediction will be the one of the element whose value is closest to the last element." -- perhaps in the algo you apply this idea to any sequence ?

If so, then the closest to 0.2 is 0.5, and the closest to -0.333 is -1, so we get:

1        2        3        5        8        13    
                  4        4.5      8.(3)    12.8     21.125      
-------------------------------------------------------------------
                  -1       0.5      -0.(3)   0.2
                                    -0.25    0.1(6)   -0.1(3)
-------------------------------------------------------------------
                                    -0.08(3)  0.0(3)
                                                      -0.01(3)

 -0.01(3) + -0.1(3) + 21.125 =~ -0.146666 + 21.125 = 20.97833                   

The predicted error is -0.146666, still not -0.13333. hmm

victorel-petrovich commented 2 months ago

Guess #3: your algo does not predict next error in exactly same way as predicting next value in sequence. Namely, it produces first extrapolation for error, and stops here, without trying to improve it recursively (by computing more past extrapolations and then again computing errors ) the way I describe above in guess # 2

To test this, please run the following:

ghci> probnet 1 [-1.0,0.5,-0.3333333333333339,0.1999999999999993]
pedroelbanquero commented 2 months ago

ghci> probnet 1 [-1.0,0.5,-0.3333333333333339,0.1999999999999993] [-1,0,0,0,0]

this not works by the rounds i think

ghci> probnet 1 [-1.0,0.5,-0.3333333333333339,0.1999999999999993] [-1,0,0,0,0] ghci> predict1 [-1.0,0.5,-0.3333333333333339,0.1999999999999993] -0.1333333333333331 ghci> prerr [-1.0,0.5,-0.3333333333333339,0.1999999999999993] -1.3333333333332434e-2

pedroelbanquero commented 2 months ago

take in consideration de nearest function , who get the LT or GT

victorel-petrovich commented 2 months ago

If you want, we can get to the bottom of this if you change a bit the program so that it doesn't round at the end , then run that probnet 1 [ [-1, 0.5, -1/3, 0.2 ]

or , even better, add in the program some print statements to print all the important lists: the values, the predicted (extrapolated) values, the errors the predictions for errors the errors from last predictions again

So that we get something similar to the "tables" in my replies above.

pedroelbanquero commented 2 months ago

let me prepare the debug

pedroelbanquero commented 2 months ago

ghci> probnet 1 [-1, 0.5, -1/3, 0.2 ] [-1.0,0.5,-0.3333333333333333,0.2,-0.1466666666666667] ghci> probnet 1 [-1.0,0.5,-0.3333333333333339,0.1999999999999993] [-1.0,0.5,-0.3333333333333339,0.1999999999999993,-0.14666666666666556]

pedroelbanquero commented 2 months ago
predict1 :: RealFrac a => [a] -> a
predict1 dat  
   -- | l1 == (eleml+1) = (ratio1 (dat) (eleml+1)) * last dat 
   | otherwise = (ratio1 dat eleml) * last dat
   where
   Just eleml = elemIndex ned dat
   ned = nearnum (last $ dat) (init dat)
   l1 = length dat
   l = last $ init dat
   lastper = last dat 

nearnum :: RealFrac a => a -> [a] -> a
nearnum n = minimumBy nearer
   where
   nearer x y = compare (abs (x - n)) (abs (y - n))

let me debug also this function, and nearest function

pedroelbanquero commented 2 months ago

ghci> ratio1 [1,2,3,5,8,13,21] 2 1.6666666666666667 ghci> ratio1 [1,2,3,5,8,13,21] 3 1.6 ghci> ratio1 [1,2,3,5,8,13,21] 4 1.625 ghci> ratio1 [1,2,3,5,8,13,21] 5 1.6153846153846154

pedroelbanquero commented 2 months ago

Guess #2: on Readme, https://github.com/pedroelbanquero/geometric-extrapolation?tab=readme-ov-file#sequences-with-quasi-cyclic-pattern , you say " the ratio used for prediction will be the one of the element whose value is closest to the last element." -- perhaps in the algo you apply this idea to any sequence ?

If so, then the closest to 0.2 is 0.5, and the closest to -0.333 is -1, so we get:

1        2        3        5        8        13    
                  4        4.5      8.(3)    12.8     21.125      
-------------------------------------------------------------------
                  -1       0.5      -0.(3)   0.2
                                    -0.25    0.1(6)   -0.1(3)
-------------------------------------------------------------------
                                    -0.08(3)  0.0(3)
                                                      -0.01(3)

 -0.01(3) + -0.1(3) + 21.125 =~ -0.146666 + 21.125 = 20.97833                 

The predicted error is -0.146666, still not -0.13333. hmm

ghci> probnet 1 [-1, 0.5, -1/3, 0.2 ] [-1.0,0.5,-0.3333333333333333,0.2,-0.1466666666666667] ghci> probnet 1 [-1.0,0.5,-0.3333333333333339,0.1999999999999993] [-1.0,0.5,-0.3333333333333339,0.1999999999999993,-0.14666666666666556]

pedroelbanquero commented 2 months ago

predict1 not add the error, probnet function add the error

victorel-petrovich commented 2 months ago

Hi, thank you , yes your computation with probnet 1 confirmed that guess #3 is probably correct

If I'm right, then it makes sense not to recursively "improve" on the predicted error as that would make the algo less efficient.

take in consideration de nearest function , who get the LT or GT

I don't understand what you meant about that (I find Haskell very hard to read if you don't know the lang)

pedroelbanquero commented 2 months ago

Just explai

Hi, thank you , yes your computation with probnet 1 confirmed that guess #3 is probably correct

If I'm right, then it makes sense not to recursively "improve" on the predicted error as that would make the algo less efficient.

take in consideration de nearest function , who get the LT or GT

I don't understand what you meant about that (I find Haskell very hard to read if you don't know the lang)

Just explaining what does compare function inside nearest function

ghci> compare 5 8 LT ghci> compare 8 5 GT

pedroelbanquero commented 2 months ago

tell me when you have better math explanation please, to upload readme and wikipedia

pedroelbanquero commented 2 months ago

I'm really glad you made an effort to understand the algorithm, thank you very much, I really appreciate it.

victorel-petrovich commented 2 months ago

tell me when you have better math explanation please, to upload readme and wikipedia

I'll help improve Readme, but let's run one more check to confirm my guess #3:

Please run the following without any rounding, and I will do on paper/python based on my understanding:

seq = [ 1, 3, 5, 7, 9, 11 ] 
probnet 1  seq
prerr seq
drop 2 (inits seq)
preds = fmap predict1 it
errs = zipWith subtract preds (drop 2 seq)
predict1 errs
probnet 1 errs
pedroelbanquero commented 2 months ago
ghci> seq = [ 1, 3, 5, 7, 9, 11 ] 
ghci> probnet 1  seq
[1.0,3.0,5.0,7.0,9.0,11.0,13.03628117913832]
ghci> prerr seq
-0.4081632653061252
ghci> drop 2 (inits seq)
[[1,3],[1,3,5],[1,3,5,7],[1,3,5,7,9],[1,3,5,7,9,11]]
ghci> preds = fmap predict1 it
ghci> errs = zipWith subtract preds (drop 2 seq)
ghci> predict1 errs
-0.4081632653061252
ghci> probnet 1 errs
[-4.0,-1.333333333333334,-0.7999999999999989,-0.571428571428573,-0.43167346938775947]
ghci> 
victorel-petrovich commented 2 months ago

OK, It's confirmed, to find prediction of error, your alg stops after finding first prediction for errors

>>> seq = [ 1, 3, 5, 7, 9, 11 ]
>>> seq
[1, 3, 5, 7, 9, 11]
>>> preds= [seq[i]**2/seq[i-1] for i in range(1,len(seq))]
>>> preds
[9.0, 8.333333333333334, 9.8, 11.571428571428571, 13.444444444444445]
>>> errs=[seq[i+2]-preds[i] for i in range(len(preds)-1)]
>>> errs
[-4.0, -1.333333333333334, -0.8000000000000007, -0.5714285714285712]
>>> prederrs= [errs[i]**2/errs[i-1] for i in range(1,len(errs))]
>>> prederrs
[-0.44444444444444486, -0.48000000000000065, -0.4081632653061217]
>>> errserrs=[errs[i+2]-prederrs[i] for i in range(len(prederrs)-1)]
>>> errserrs
[-0.35555555555555585, -0.09142857142857053]
>>> prederrserrs= [errserrs[i]**2/errserrs[i-1] for i in range(1,len(errserrs))]
>>> prederrserrs
[-0.02351020408163217]
>>> prederrserrs[-1]+prederrs[-1]
-0.43167346938775386
>>> next1=preds[-1]+prederrs[-1]
>>> next1
13.036281179138323
>>> next2=preds[-1]+prederrs[-1]+prederrserrs[-1]
>>> next2
13.012770975056691
pedroelbanquero commented 2 months ago

do yo have final math formula ? math explanation ?

victorel-petrovich commented 2 months ago

The only thing I have is the following pics with some formulas on scratch papers. V0 is the value to be predicted, V1 with line on top means initial predictions; e1, e2 are the errors. IMG_20240811_104209 1 IMG_20240811_104218 1

victorel-petrovich commented 2 months ago

Your method reminded me of "predictor-corrector" method in solving differential equations that I learned about in graduate school (see wikipedia). However, your approach is still very different from that, as you construct the sequence of errors and predict that. Which might be original. Bravo!

victorel-petrovich commented 2 months ago

One potential issue I can think about for now is that that sequence of errors can have positive and negative and 0 values even if the sequence of values to predict has only positive values. So algorithm has to deal with the special case when one of the error values is very close to 0. Because otherwise, if you have to divide by such value, you can get big numerical error.

One way to deal with it is: when the algo needs to divide by a error value that is too close to 0 , and only in such cases, it can switch to predict the next error using not ratios but differences method.

pedroelbanquero commented 2 months ago

For my part, I will try to improve some things in the future, such as the change in frequency of a data set, the curves, more error prediction layers with more than 4 points. Also, what you say about values ​​close to 0 or 0. Thank you very much for your attention and effort to understand it, it makes me very happy that someone is interested.

Thank you for your review, I am very grateful. I really appreciate the effort you took to review it. Feel free to use what you need or improve what you see fit.