You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Covariance.hpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. ///-------------------------------------------------------------------------------------------------
  2. ///
  3. /// \file Covariance.hpp
  4. /// \brief All functions to estimate the Covariance Matrix.
  5. /// \author Thibaut Monseigne (Inria).
  6. /// \version 1.0.
  7. /// \date 26/10/2018.
  8. /// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
  9. /// \remarks
  10. /// - List of Estimator inspired by the work of Alexandre Barachant : <a href="https://github.com/alexandrebarachant/pyRiemann">pyRiemann</a> (<a href="https://github.com/alexandrebarachant/pyRiemann/blob/master/LICENSE">License</a>).
  11. /// - <a href="http://scikit-learn.org/stable/modules/generated/sklearn.covariance.LedoitWolf.html">Ledoit and Wolf Estimator</a> inspired by <a href="http://scikit-learn.org">sklearn</a> (<a href="https://github.com/scikit-learn/scikit-learn/blob/master/COPYING">License</a>).
  12. /// - <a href="http://scikit-learn.org/stable/modules/generated/sklearn.covariance.OAS.html">Oracle Approximating Shrinkage (OAS) Estimator</a> Inspired by <a href="http://scikit-learn.org">sklearn</a> (<a href="https://github.com/scikit-learn/scikit-learn/blob/master/COPYING">License</a>).
  13. /// - <b>Minimum Covariance Determinant (MCD) Estimator isn't implemented. </b>
  14. ///
  15. ///-------------------------------------------------------------------------------------------------
  16. #pragma once
  17. #include "geometry/Basics.hpp"
  18. #include <Eigen/Dense>
  19. namespace Geometry {
  20. //***************************************************
  21. //******************** CONSTANTS ********************
  22. //***************************************************
  23. /// <summary> Enumeration of the covariance matrix estimator. Inspired by the work of Alexandre Barachant : <a href="https://github.com/alexandrebarachant/pyRiemann">pyRiemann</a>. </summary>
  24. enum class EEstimator
  25. {
  26. COV, ///< The Simple Covariance Estimator.
  27. SCM, ///< The Normalized Spatial Covariance Matrix (SCM) Estimator.
  28. LWF, ///< The Ledoit and Wolf Estimator.
  29. OAS, ///< The Oracle Approximating Shrinkage (OAS) Estimator.
  30. MCD, ///< The Minimum Covariance Determinant (MCD) Estimator.
  31. COR, ///< The Pearson Correlation Estimator.
  32. IDE ///< The Identity Matrix.
  33. };
  34. /// <summary> Convert estimators to string. </summary>
  35. /// <param name="estimator"> The estimator. </param>
  36. /// <returns> <c>std::string</c> </returns>
  37. inline std::string toString(const EEstimator estimator)
  38. {
  39. switch (estimator)
  40. {
  41. case EEstimator::COV: return "Covariance";
  42. case EEstimator::SCM: return "Normalized Spatial Covariance Matrix (SCM)";
  43. case EEstimator::LWF: return "Ledoit and Wolf";
  44. case EEstimator::OAS: return "Oracle Approximating Shrinkage (OAS)";
  45. case EEstimator::MCD: return "Minimum Covariance Determinant (MCD)";
  46. case EEstimator::COR: return "Pearson Correlation";
  47. case EEstimator::IDE: return "Identity";
  48. }
  49. return "Invalid";
  50. }
  51. /// <summary> Convert string to estimators. </summary>
  52. /// <param name="estimator"> The estimator. </param>
  53. /// <returns> <see cref="EEstimator"/> </returns>
  54. inline EEstimator StringToEstimator(const std::string& estimator)
  55. {
  56. if (estimator == "Covariance") { return EEstimator::COV; }
  57. if (estimator == "Normalized Spatial Covariance Matrix (SCM)") { return EEstimator::SCM; }
  58. if (estimator == "Ledoit and Wolf") { return EEstimator::LWF; }
  59. if (estimator == "Oracle Approximating Shrinkage (OAS)") { return EEstimator::OAS; }
  60. if (estimator == "Minimum Covariance Determinant (MCD)") { return EEstimator::MCD; }
  61. if (estimator == "Pearson Correlation") { return EEstimator::COR; }
  62. return EEstimator::IDE;
  63. }
  64. //***********************************************************
  65. //******************** COVARIANCES BASES ********************
  66. //***********************************************************
  67. /// <summary> Calculation of the Variance of a double dataset \f$\vec{X}\f$.\n
  68. /// \f[ V(X) = \left(\frac{1}{n} \sum_{i=1}^{N}x_{i}^{2}\right) - \left(\frac{1}{n} \sum_{i=1}^{N}x_{i}\right)^{2} \f]
  69. /// </summary>
  70. /// <param name="x"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Samples. </param>
  71. /// <returns> The Variance. </returns>
  72. double Variance(const Eigen::RowVectorXd& x);
  73. /// <summary> Calculation of the Covariance between two double dataset \f$\vec{X}, \vec{Y}\f$.\n
  74. /// \f[ \operatorname{Cov}\left(x,y\right) = \frac{\sum_{i=1}^{N}{x_{i}y_{i}} - \left(\sum_{i=1}^{N}{x_{i}}\sum_{i=1}^{N}{y_{i}}\right)/N}{N}\f]
  75. /// </summary>
  76. /// <param name="x"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Samples. </param>
  77. /// <param name="y"> The dataset \f$\vec{Y}\f$. With \f$ N \f$ Samples. </param>
  78. /// <returns> The Covariance. </returns>
  79. double Covariance(const Eigen::RowVectorXd& x, const Eigen::RowVectorXd& y);
  80. /// <summary> Shrunks the Covariance Matrix \f$ M \f$ (destructive operation).\n
  81. /// \f[ (1 - \text{shrinkage}) \times M_{\operatorname{Cov}} + \frac{\text{shrinkage} \times \operatorname{trace}(M_{Cov})}{N} \times I_N \f]
  82. /// </summary>
  83. /// <param name="cov"> The Covariance Matrix to shrink. </param>
  84. /// <param name="shrinkage"> (Optional) The shrinkage coefficient : \f$ 0\leq \text{shrinkage} \leq 1\f$. </param>
  85. /// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
  86. bool ShrunkCovariance(Eigen::MatrixXd& cov, double shrinkage = 0.1);
  87. /// <summary> Shrunks the Covariance Matrix \f$ M \f$ (non destructive operation).\n
  88. /// \f[ (1 - \text{shrinkage}) \times M_{\operatorname{Cov}} + \frac{\text{shrinkage} \times \operatorname{trace}(M_{Cov})}{N} \times I_N \f]
  89. /// </summary>
  90. /// <param name="in"> The covariance matrix to shrink. </param>
  91. /// <param name="out"> The shrunk covariance matrix. </param>
  92. /// <param name="shrinkage"> (Optional) The shrinkage coefficient : \f$ 0\leq \text{shrinkage} \leq 1\f$. </param>
  93. /// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
  94. bool ShrunkCovariance(const Eigen::MatrixXd& in, Eigen::MatrixXd& out, double shrinkage = 0.1);
  95. /// <summary> Select the function to call for the covariance matrix.\n
  96. /// - centralizing the data is useless for <c><see cref="EEstimator::COV"/></c> and <c><see cref="EEstimator::COR"/></c>.\n
  97. /// - centralizing the data is not usual for <c><see cref="EEstimator::SCM"/></c>.
  98. /// </summary>
  99. /// <param name="in"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Rows (features) and \f$ S \f$ columns (samples). </param>
  100. /// <param name="out"> The Covariance Matrix. </param>
  101. /// <param name="estimator"> (Optional) The selected estimator (see <see cref="EEstimator"/>). </param>
  102. /// <param name="standard"> (Optional) Standardize the data (see <see cref="EStandardization"/>). </param>
  103. /// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
  104. bool CovarianceMatrix(const Eigen::MatrixXd& in, Eigen::MatrixXd& out, EEstimator estimator = EEstimator::COV,
  105. EStandardization standard = EStandardization::Center);
  106. //***********************************************************
  107. //******************** COVARIANCES TYPES ********************
  108. //***********************************************************
  109. /// <summary> Calculation of the covariance matrix.\n
  110. /// \f[ M_{\operatorname{Cov}} =
  111. /// \begin{pmatrix}
  112. /// V\left(x_1\right) & \operatorname{Cov}\left(x_1,x_2\right) &\cdots & \operatorname{Cov}\left(x_1,x_N\right)\\
  113. /// \operatorname{Cov}\left(x_2,x_1\right) &\ddots & \ddots & \vdots \\
  114. /// \vdots & \ddots & \ddots & \vdots \\
  115. /// \operatorname{Cov}\left(x_N,x_1\right) &\cdots & \cdots & V\left(x_N\right)
  116. /// \end{pmatrix}
  117. /// \quad\quad \text{with } x_i \text{ the feature } i
  118. /// \f]\n
  119. /// With the <see cref="Variance"/> and <see cref="Covariance"/> function.
  120. /// </summary>
  121. /// <param name="samples"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Rows (features) and \f$ S \f$ columns (samples). </param>
  122. /// <param name="cov"> The Covariance Matrix. </param>
  123. /// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
  124. bool CovarianceMatrixCOV(const Eigen::MatrixXd& samples, Eigen::MatrixXd& cov);
  125. /// <summary> Calculation of the covariance matrix by the method : Normalized Spatial Covariance Matrix (SCM).\n
  126. /// \f[ M_{\operatorname{Cov_{SCM}}} = \frac{XX^{\mathsf{T}}}{\operatorname{trace}{\left(XX^{\mathsf{T}}\right)}} \f]
  127. /// </summary>
  128. /// <param name="samples"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Rows (features) and \f$ S \f$ columns (samples). </param>
  129. /// <param name="cov"> The Covariance Matrix. </param>
  130. /// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
  131. bool CovarianceMatrixSCM(const Eigen::MatrixXd& samples, Eigen::MatrixXd& cov);
  132. /// <summary> Calculation of the covariance matrix and shrinkage by the method : Ledoit and Wolf.\n
  133. /// -# Compute the Covariance Matrix (see <see cref="CovarianceMatrixCOV"/>) \f$ M_{\operatorname{Cov}} \f$
  134. /// -# Compute the Ledoit and Wolf Shrinkage
  135. /// -# Shrunk the Matrix (see <see cref="ShrunkCovariance"/>)
  136. ///
  137. /// Ledoit and Wolf Shrinkage (from <a href="http://scikit-learn.org/stable/modules/generated/sklearn.covariance.LedoitWolf.html">Sklearn LedoitWolf Estimator</a>)
  138. /// described in "A Well-Conditioned Estimator for Large-Dimensional Covariance Matrices", Ledoit and Wolf, Journal of Multivariate Analysis, Volume 88, Issue 2, February 2004, pages 365-411. : \n
  139. /// \f[
  140. /// \begin{aligned}
  141. /// \vec{X}^2 &= \begin{pmatrix}x_{0,0}^2 & \cdots & x_{0,S}^2 \\ \vdots & \ddots &\vdots \\ x_{N,0}^2 & \cdots & x_{N,S}^2\end{pmatrix} \quad \text{with } x_{i,j} \in \vec{X}\\
  142. /// M_{\mu} &= \mu\times I_N = \begin{pmatrix} \mu & 0 & \cdots & 0 \\ 0 & \ddots &\ddots & \vdots \\ \vdots & \ddots &\ddots & 0 \\ 0 & \cdots & 0 & \mu\end{pmatrix}
  143. /// \quad \text{with } \mu = \frac{\operatorname{trace}(M_{\operatorname{Cov}})}{N}\\
  144. /// M_{\delta} &= M_{\operatorname{Cov}}-M_{\mu}\\
  145. /// M_{\delta}^2 &= M_{\delta} * M_{\delta}\\
  146. /// M_{\beta} &= \frac{1}{S} \times \left(\vec{X}^2 * \vec{X}^{2\mathsf{T}}\right) - M_{Cov} * M_{Cov}\\
  147. /// \Sigma\left( M \right) &=\text{ the sum of the elements of the matrix } M\\
  148. /// \end{aligned}
  149. /// \f]
  150. /// \f[ \text{Shrinkage}_\text{LWF} = \frac{\beta}{\delta} \quad \text{with } \delta = \frac{\Sigma\left( M_{\delta}^2 \right)}{N} \quad\text{and}\quad
  151. /// \beta = \operatorname{min}\left(\frac{\Sigma\left( M_{\beta}^2 \right)}{N \times S},~ \delta\right)\f]
  152. /// </summary>
  153. /// <param name="samples"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Rows (features) and \f$ S \f$ columns (samples). </param>
  154. /// <param name="cov"> The Covariance Matrix. </param>
  155. /// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
  156. bool CovarianceMatrixLWF(const Eigen::MatrixXd& samples, Eigen::MatrixXd& cov);
  157. /// <summary> Calculation of the covariance matrix and shrinkage by the method : Oracle Approximating Shrinkage (OAS).\n
  158. /// -# Compute the Covariance Matrix (see <see cref="CovarianceMatrixCOV"/>) \f$ M_{\operatorname{Cov}} \f$
  159. /// -# Compute the Oracle Approximating Shrinkage
  160. /// -# Shrunk the Matrix (see <see cref="ShrunkCovariance"/>)
  161. ///
  162. /// Oracle Approximating Shrinkage (from <a href="http://scikit-learn.org/stable/modules/generated/sklearn.covariance.OAS.html">Sklearn Oracle Approximating Shrinkage Estimator</a>)
  163. /// describe in "Shrinkage Algorithms for MMSE Covariance Estimation" Chen et al., IEEE Trans. on Sign. Proc., Volume 58, Issue 10, October 2010. : \n
  164. /// \f[
  165. /// \begin{aligned}
  166. /// \mu &= \frac{\operatorname{trace}(M_{\operatorname{Cov}})}{N}\\
  167. /// \mu \left( M \right) &=\text{ the mean of the elements of the matrix } M\\
  168. /// \alpha &= \mu \left( M_{\operatorname{Cov}} * M_{\operatorname{Cov}} \right)\\
  169. /// \text{num} &= \alpha + \mu^2\\
  170. /// \text{den} &= (S + 1) \times \frac{\alpha - \mu^2}{N}\\
  171. /// \end{aligned}
  172. /// \f]
  173. /// \f[
  174. /// \text{Shrinkage}_\text{OAS} = \begin{cases}
  175. /// 1, & \text{if}\ \text{den} = 0 \text{ or num} > \text{den} \\
  176. /// \frac{\text{num}}{\text{den}}, & \text{otherwise}
  177. /// \end{cases}
  178. /// \f]
  179. /// </summary>
  180. /// <param name="samples"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Rows (features) and \f$ S \f$ columns (samples). </param>
  181. /// <param name="cov"> The Covariance Matrix. </param>
  182. /// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
  183. bool CovarianceMatrixOAS(const Eigen::MatrixXd& samples, Eigen::MatrixXd& cov);
  184. /// <summary>Calculation of the covariance matrix and shrinkage by the method : Minimum Covariance Determinant (MCD). </summary>
  185. /// <param name="samples"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Rows (features) and \f$ S \f$ columns (samples). </param>
  186. /// <param name="cov"> The Covariance Matrix. </param>
  187. /// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
  188. /// \todo Not implemented.
  189. bool CovarianceMatrixMCD(const Eigen::MatrixXd& samples, Eigen::MatrixXd& cov);
  190. /// <summary> Calculation of the covariance matrix by the method : Pearson Correlation.\n
  191. /// \f[
  192. /// M_{\operatorname{Cov_{COR}}}\left(i,j\right)
  193. /// = \frac{ M_{\operatorname{Cov}}\left(i,j\right) } { \sqrt{ M_{\operatorname{Cov}}\left(i,i\right) * M_{\operatorname{Cov}}\left(j,j\right) } }
  194. /// \f]
  195. /// </summary>
  196. /// <param name="samples"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Rows (features) and \f$ S \f$ columns (samples). </param>
  197. /// <param name="cov"> The Covariance Matrix. </param>
  198. /// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
  199. bool CovarianceMatrixCOR(const Eigen::MatrixXd& samples, Eigen::MatrixXd& cov);
  200. /// <summary> Return the Identity matrix \f$ I_N \f$. </summary>
  201. /// <param name="samples"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Rows (features) and \f$ S \f$ columns (samples). </param>
  202. /// <param name="cov"> The Covariance Matrix. </param>
  203. /// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
  204. bool CovarianceMatrixIDE(const Eigen::MatrixXd& samples, Eigen::MatrixXd& cov);
  205. } // namespace Geometry