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

Другие вопросы по тегам