numpy положительное полуопределенное предупреждение
В скрипте Python, который я пишу, я моделирую многовариантные нормальные случайные векторы с помощью выражения
np.random.multivariate_normal(np.zeros(dim_obs), y_cov)
Мой скрипт выполняется, но выдает следующее предупреждение:
RuntimeWarning: covariance is not positive-semidefinite.
Также маленькие отладочные операторы печати я добавляю туда печать False
большую часть времени
print( np.all(np.linalg.eigvals(y_cov) > 0) )
Почему это бросает ложные срабатывания? мой y_cov
является положительным полуопределенным, потому что это (извините за отсутствие разметки TeX) B x x'B' + y y', где B - матрица, а остальные - случайные векторы с каждым положительным элементом.
В этом конкретном прогоне B на самом деле просто один вектор размера 9. Могу ли я просто проигнорировать это предупреждение? Из документации:
Обратите внимание, что ковариационная матрица должна быть положительной полуопределенной (или неотрицательно определенной). В противном случае поведение этого метода не определено и обратная совместимость не гарантируется.
Редактировать: вот работоспособная вещь в целом. Спасибо за совет @user2357112.
import numpy as np
num_factors = 1
dim_obs = 9
u = np.random.normal(size = num_factors)
v = np.random.normal(size = dim_obs)
y_cov = np.dot(np.ones((9,1)), np.exp(u.reshape((num_factors,1))/2))
y_cov = np.dot(y_cov, np.exp(u.reshape((1,num_factors))/2)) #transpose
y_cov = np.dot(y_cov, np.transpose(np.ones((9,1))))
y_cov += np.dot(np.exp( v.reshape((dim_obs,1)) / 2),
np.exp( v.reshape((1,dim_obs)) / 2))
print( np.random.multivariate_normal(np.zeros(dim_obs), y_cov) )
print( np.all(np.linalg.eigvals(y_cov) > 0) )
print( np.linalg.eigvals(y_cov) )
2 ответа
Теоретически, ваша матрица является положительной полуопределенной, с несколькими собственными значениями, равными нулю. Но вычисления с числами с плавающей точкой вводят ошибки усечения, которые приводят к тому, что некоторые из этих собственных значений очень малы, но отрицательны; следовательно, матрица не является положительной полуопределенной.
В настоящее время похоже, что предупреждение может быть проигнорировано; но документация NumPy говорит, что поведение в не-psd случае не определено, поэтому я не хотел бы полагаться на это. Чтобы исправить ошибки с плавающей запятой, нужно добавить крошечное число единичной матрицы к y_cov
, Например, вот так:
min_eig = np.min(np.real(np.linalg.eigvals(y_cov)))
if min_eig < 0:
y_cov -= 10*min_eig * np.eye(*y_cov.shape)
Добавление фиксированного кратного идентификатора, такого как 1e-12, будет работать для всех матриц разумного размера и все равно не будет иметь значения для результатов.
Для полноты, более простой способ воспроизвести проблему:
import numpy as np
x = np.random.normal(size=(5,))
y = np.outer(x, x)
z = np.random.multivariate_normal(np.zeros(5), y)
Это бросает то же самое предупреждение (с высокой вероятностью).
Более эффективный способ генерирования гауссовых выборок в вашем случае, который также не подвержен численным проблемам, идентифицированным @zaq, состоит в том, чтобы наблюдать, что многомерный случайный вектор с нулевым средним Гауссом и ковариационная матрица равны a*a.T + b*b.T
(a
, b
: векторы столбцов) по распределению равен случайному вектору a*w1 + b*w2
где w1
а также w2
являются независимыми гауссовыми скалярными случайными величинами с нулевым средним и дисперсией 1