Кластеризация среднего сдвига Python для массива комплексных чисел
Я унаследовал некоторый код, который был написан около года назад, поэтому я думаю, что тогда он использовал numpy 1.13 (сейчас v1.15.2), scipy 1.00rc (сейчас v1.1.0) и sklearn 0.19 (сейчас v.0.20).0).
Он реализует LDA Фишера, чтобы уменьшить n- мерное пространство до 1… n- 1-мерного пространства, которое в результате приводит к массиву массивов комплексных чисел (из-за неточности с плавающей запятой). Этот массив затем подбирается и подается в sklearn.cluster.MeanShift
который сразу выбрасывает исключение:
File "/…/lib/python3.6/site-packages/sklearn/cluster/mean_shift_.py", line 416, in fit
X = check_array(X)
File "/…/lib/python3.6/site-packages/sklearn/utils/validation.py", line 531, in check_array
_ensure_no_complex_data(array)
File "/…/lib/python3.6/site-packages/sklearn/utils/validation.py", line 354, in _ensure_no_complex_data
"{}\n".format(array))
ValueError: Complex data not supported
Я все еще изучаю математические детали того, что здесь происходит, но мне кажется странным, что этот код был объявлен "работоспособным".
Я что-то здесь упускаю? Произошли ли изменения версии в результате этой регрессии, или есть более фундаментальный недостаток кода? Как бы я решил эту проблему?
1 ответ
В комментариях / чате мы определили, по крайней мере, одну проблему, которая заключается в том, что численное собственное разложение
(cov_w + I)^-1 @ cov_b (1)
не является реальным, как следует, но возвращает значительные мнимые компоненты. Здесь @ - умножение матриц, cov_w и cov_b - ковариационные матрицы, а I - единичная матрица. Это можно исправить, вычислив квадратный корень из матрицы (cov_w + I)^-1, назовем его SQ, а затем используем тот факт, что (1) аналогично
SQ @ cov_b @ SQ (2)
следовательно, имеет те же собственные значения, и если V являются собственными векторами (2), то (правые) собственные векторы (1) равны SQ @ V.
Мы получили то, что, поскольку (2) является симметричной матрицей, ее собственное разложение может быть вычислено с использованием numpy.linalg.eigh
что гарантирует чисто реальные результаты. eigh
также может использоваться для вычисления SQ, см. здесь. Обязательно обходите обратное и применяйте eigh
прямо на cov_w + I
или даже cov_w
,