Autocorrélation Python vs Julia

19

J'essaie de faire une autocorrélation en utilisant Julia et de la comparer au résultat de Python. Comment se fait-il qu'ils donnent des résultats différents?

Code Julia

using StatsBase

t = range(0, stop=10, length=10)
test_data = sin.(exp.(t.^2))

acf = StatsBase.autocor(test_data)

donne

10-element Array{Float64,1}:
  1.0                   
  0.13254954979179642   
 -0.2030283419321465    
  0.00029587850872956104
 -0.06629381497277881   
  0.031309038331589614  
 -0.16633393452504994   
 -0.08482388975165675   
  0.0006905628640697538 
 -0.1443650483145533

Code Python

from statsmodels.tsa.stattools import acf
import numpy as np

t = np.linspace(0,10,10)
test_data = np.sin(np.exp(t**2))

acf_result = acf(test_data)

donne

array([ 1.        ,  0.14589844, -0.10412699,  0.07817509, -0.12916543,
       -0.03469143, -0.129255  , -0.15982435, -0.02067688, -0.14633346])
Ross Mariano
la source
1
Imprimer les données du test dans les deux cas
Mad Physicist

Réponses:

26

C'est parce que votre test_dataest différent:

Python:

array([ 0.84147098, -0.29102733,  0.96323736,  0.75441021, -0.37291918,
        0.85600145,  0.89676529, -0.34006519, -0.75811102, -0.99910501])

Julia:

[0.8414709848078965, -0.2910273263243299, 0.963237364649543, 0.7544102058854344,
 -0.3729191776326039, 0.8560014512776061, 0.9841238290665676, 0.1665709194875013,
 -0.7581110212957692, -0.9991050130774393]

Cela se produit parce que vous prenez sindes nombres énormes. Par exemple, le dernier chiffre tétant 10, exp(10^2)est ~ 2,7 * 10 ^ 43. À cette échelle, les inexactitudes en virgule flottante sont d'environ 3 * 10 ^ 9. Donc, même si le bit le moins significatif est différent pour Python et Julia, la sinvaleur sera bien différente.

En fait, nous pouvons inspecter les valeurs binaires sous-jacentes du tableau initial t. Par exemple, ils diffèrent dans l'avant-dernière valeur:

Julia:

julia> reinterpret(Int, range(0, stop=10, length=10)[end-2])
4620443017702830535

Python:

>>> import struct
>>> s = struct.pack('>d', np.linspace(0,10,10)[-3])
>>> struct.unpack('>q', s)[0]
4620443017702830536

Nous pouvons en effet voir qu'ils sont en désaccord avec exactement une machine epsilon. Et si nous utilisons Julia prendre sinla valeur obtenue par Python:

julia> sin(exp(reinterpret(Float64, 4620443017702830536)^2))
-0.3400651855865199

Nous obtenons la même valeur que Python.

Jakob Nissen
la source
9

Juste pour développer un peu la réponse (ajouter comme réponse car c'est trop long pour un commentaire). En Julia, vous avez les éléments suivants:

julia> t = collect(range(0, stop=10, length=10))
10-element Array{Float64,1}:
  0.0               
  1.1111111111111112
  2.2222222222222223
  3.3333333333333335
  4.444444444444445 
  5.555555555555555 
  6.666666666666667 
  7.777777777777778 
  8.88888888888889  
 10.0               

julia> t .- [10*i / 9 for i in 0:9]
10-element Array{Float64,1}:
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0

en Python:

>>> t = np.linspace(0,10,10)
>>> t - [10*i/9 for i in range(10)]
array([0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
       0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 8.8817842e-16,
       0.0000000e+00, 0.0000000e+00])

et vous voyez que le 8ème nombre en Python est une approximation inexacte de 70/9, tandis que dans Julia dans ce cas, vous obtenez la séquence d'approximations les plus proches de l' 10*i/9utilisation Float64.

Il semblerait donc que parce que les séquences originales diffèrent, le reste suit ce que @Jakob Nissen a commenté.

Mais les choses ne sont pas si simples. Comme les expfonctions de Julia et Python diffèrent un peu dans ce qu'elles produisent. Voir Python:

>>> from math import exp
>>> from mpmath import mp
>>> mp.dps = 1000
>>> float(mp.exp((20/3)**2) - exp((20/3)**2))
-1957.096392544307

à Julia:

julia> setprecision(1000)
1000

julia> Float64(exp(big((20/3)^2)) - exp((20/3)^2))
2138.903607455693

julia> Float64(exp(big((20/3)^2)) - nextfloat(exp((20/3)^2)))
-1957.096392544307

(vous pouvez vérifier que (20/3)^2c'est la même chose Float64dans Julia et Python).

Donc, dans ce cas, expPython est légèrement plus précis que Julia. Par conséquent, même la fixation t(ce qui est facile en utilisant une compréhension en Python au lieu de linspace) ne rendra pas l'ACF égal.

Dans l'ensemble, la conclusion est ce que @Jakob Nissen a commenté pour des valeurs aussi importantes, les résultats seront fortement influencés par les inexactitudes numériques.

Bogumił Kamiński
la source