Точность, почему Matlab и Python numpy дают такие разные результаты? - PullRequest
18 голосов
/ 20 сентября 2011

Я знаю об основных типах данных и о том, что типы с плавающей точкой (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'.

Почему такая огромная разница?Какой из них более правильный?

Ответы [ 3 ]

27 голосов
/ 20 сентября 2011

Возможно, разница в вызовах mean и std. Сравните их в первую очередь.

Есть несколько определений для std, некоторые используют корень квадратный из

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)
14 голосов
/ 20 сентября 2011

Чтобы ответить на ваш вопрос, нет , это не проблема точности.Как указывает @ rockportrocker , для стандартного отклонения есть две популярные оценки.У MATLAB std есть и то, и другое, но стандартно используется тот, который вы использовали в 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.Прочитайте ответ rockpotrocker о том, какой из двух результатов больше подходит для того, что вы хотите сделать; -).

3 голосов
/ 03 января 2014

Согласно документации std при SciPy , он имеет параметр, называемый ddof:

ddof : int, необязательно
Означает Дельта Степени Свободы. Делитель используется в расчетах есть N - ddof, где N представляет количество элементов. По умолчанию ddof равен нулю.

В numpy ddof по умолчанию равен нулю, а в MATLAB - единице. Итак, я думаю, что это может решить проблему:

std(Z,ddof=1)
...