Как правильно сделать выборку из numpy.random.multivariate_normal (проблема положительно-полуопределенной ковариационной матрицы)
Я надеюсь создать новые "поддельные" данные из данных, которые у меня уже есть с numpy.random.multivariate_normal
,
С n сэмплами и d функциями в nFD pandas DataFrame:
means = data.mean(axis=0)
covariances = data.cov()
variances = data.var()
means.shape, covariances.shape, variances.shape
>>> ((16349,), (16349, 16349), (16349,))
Это выглядит хорошо, но ковариационная матрица covariances
не является положительным полуопределенным, что является требованием numpy.random.multivariate_normal
,
x = np.linalg.eigvals(covariances)
np.all(x >= 0)
>>> False
len([y for y in x if y < 0]) # negative eigenvalues
>>> 4396
len([y for y in x if y > 0]) # positive eigenvalues
>>> 4585
len([y for y in x if y == 0]) # zero eigenvalues.
>>> 7368
Тем не менее, Википедия говорит
Кроме того, каждая ковариационная матрица является положительно-полуопределенной.
Что заставляет меня задуматься о том, дает ли pandas.DataFrame.cov реальную ковариационную матрицу. Вот реализация функции. Похоже, что он в основном откладывается на numpy.cov, который также обещает ковариационную матрицу.
Может кто-нибудь прояснить это для меня? Почему pandas.DataFrame.covs()
не положительный полуопределенный?
Обновленный вопрос:
Из первого ответа кажется, что все отрицательные собственные значения крошечные. Автор этого ответа предлагает отсечь эти собственные значения, но мне все еще неясно, как разумно генерировать правильную ковариационную матрицу с этой информацией.
Я могу представить, используя pd.DataFrame.cov()
выполнение собственной декомпозиции для получения собственных векторов и значений, отсечение значений, а затем умножение этих матриц для получения новой ковариационной матрицы, но это кажется довольно ненадежным. Это делается на практике или есть лучший способ?
1 ответ
Вероятно, происходит то, что результат является положительно-полуопределенным, с точностью до вычисления. Например:
In [71]: np.linalg.eigvals(np.cov(np.random.random((5,5))))
Out[71]:
array([ 1.87557170e-01, 9.98250875e-02, 6.85211153e-02,
1.01062281e-02, -5.99164839e-18])
имеет отрицательное собственное значение, но величина мала.
Так что на вашем месте я бы проверил, что величина нарушений была мала, а затем обрезал до нуля.