Точност, защо Matlab и Python numpy дават толкова различни резултати?

Знам за основните типове данни и че плаващите типове (float,double) не могат да съдържат точно някои числа.

При пренасянето на някакъв код от Matlab към Python (Numpy) обаче открих някои значителни разлики в изчисленията и мисля, че се връща към прецизността.

Вземете следния код, z-нормализиращ 500-мерен вектор, като само първите два елемента имат ненулева стойност.

Matlab:

Z = repmat(0,500,1); Z(1)=3;Z(2)=1;
Za = (Z-repmat(mean(Z),500,1)) ./ repmat(std(Z),500,1);
Za(1)
>>> 21.1694

Python:

from numpy import zeros,mean,std
Z = zeros((500,))
Z[0] = 3
Z[1] = 1
Za = (Z - mean(Z)) / std(Z)
print Za[0]
>>> 21.1905669677

Освен че форматирането показва малко повече цифри в Python, има огромна разлика (imho), повече от 0,02

И Python, и Matlab използват 64-битов тип данни (afaik). Python използва 'numpy.float64', а Matlab 'double'.

Защо разликата е толкова голяма? Кое е по-правилно?


person Peter Smit    schedule 20.09.2011    source източник
comment
Може би би трябвало да пасне на Computational Science SE, ако бъде поискано в наши дни   -  person gerrit    schedule 16.02.2013


Отговори (3)


Може би разликата идва от извикванията mean и std. Първо ги сравнете.

Има няколко дефиниции за std, някои използват sqaure корен на

1 / n * sum((xi - mean(x)) ** 2)

други използват

1 / (n - 1) * sum((xi - mean(x)) ** 2)

вместо.

От математическа гледна точка: тези формули са оценки на дисперсията на нормално разпределена случайна променлива. Разпределението има два параметъра sigma и mu. Ако знаете mu точно, оптималната оценка за sigma ** 2 е

1 / n * sum((xi - mu) ** 2)

Ако трябва да оцените mu от данните, като използвате mu = mean(xi), оптималният оценител за sigma**2 е

1 / (n - 1) * sum((xi- mean(x))**2)
person rocksportrocker    schedule 20.09.2011

За да отговоря на въпроса ви,нетова не е проблем с точността. Като @rocksportrocker посочва, че има два популярни оценителя за стандартното отклонение. std на MATLAB има налични и двете, но като стандарт използва различен от какво сте използвали в Python.

Опитайте std(Z,1) вместо std(Z):

Za = (Z-repmat(mean(Z),500,1)) ./ repmat(std(Z,2),500,1);Za(1)
sprintf('%1.10f', Za(1))

води до

Za(1) = 21.1905669677

в MATLAB. Прочетете отговора на rockspotrocker за това кой от двата резултата е по-подходящ за това, което искате да правите ;-).

person Jonas Heidelberg    schedule 20.09.2011
comment
А, току-що видях, че @rocksportrocker ви дава предистория по математика за това :-). - person Jonas Heidelberg; 20.09.2011

Според документацията на std в SciPy, има параметър, наречен ddof:

ddof : int, незадължително
Означава делта степени на свобода. Делителят, използван при изчисленията, е N - ddof, където N представлява броя на елементите. По подразбиране ddof е нула.

В numpy ddof е нула по подразбиране, докато в MATLAB е едно. Така че мисля, че това може да реши проблема:

std(Z,ddof=1)
person cartoonist    schedule 03.01.2014