2026-08-13 23:48:47 +03:00 | | | //+------------------------------------------------------------------+
|
| | | //| pca.mqh |
|
| | | //| Copyright 2022, Dmitriy Gizlyk |
|
| | | //| https://www.mql5.com/ru/users/dng |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | #property copyright "Copyright 2022, Dmitriy Gizlyk"
|
| | | #property link "https://www.mql5.com/ru/users/dng"
|
| | | #property version "1.00"
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | #include "..\\K-means\\kmeans.mqh"
|
| | | //+------------------------------------------------------------------+
|
| | | //| Defines |
|
| | | //+------------------------------------------------------------------+
|
| | | #define defUnsupervisedPCA 0x7902
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | class CPCA : public CObject
|
| | | {
|
| | | private:
|
| | | bool b_Studied;
|
| | | matrixf m_Ureduce;
|
| | | vectorf v_Means;
|
| | | vectorf v_STDs;
|
| | | //---
|
| | | CBufferFloat *FromMatrix(matrixf &data);
|
| | | CBufferFloat *FromVector(vectorf &data);
|
| | | matrixf FromBuffer(CBufferFloat *data, ulong vector_size);
|
| | | vectorf FromBuffer(CBufferFloat *data);
|
| | | public:
|
| | | CPCA();
|
| | | ~CPCA();
|
| | | //---
|
| | | bool Study(CBufferFloat *data, int vector_size);
|
| | | bool Study(matrixf &data);
|
| | | CBufferFloat *Reduce(CBufferFloat *data);
|
| | | CBufferFloat *Reduce(matrixf &data);
|
| | | matrixf ReduceM(CBufferFloat *data);
|
| | | matrixf ReduceM(matrixf &data);
|
| | | //---
|
| | | bool Studied(void) { return b_Studied; }
|
| | | ulong VectorSize(void) { return m_Ureduce.Cols();}
|
| | | ulong Inputs(void) { return m_Ureduce.Rows(); }
|
| | | //---
|
| | | virtual bool Save(const int file_handle);
|
| | | virtual bool Load(const int file_handle);
|
| | | //---
|
| | | virtual int Type(void) { return defUnsupervisedPCA; }
|
| | | };
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | C PC A implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | CPCA::CPCA() : b_Studied(false)
|
| | | {
|
| | | m_Ureduce.Init(0, 0);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | CPCA::~CPCA()
|
| | | {
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | F ro mB uf fe r implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | matrixf CPCA::FromBuffer(CBufferFloat *data, ulong vector_size)
|
| | | {
|
| | | matrixf result;
|
| | | if(CheckPointer(data) == POINTER_INVALID)
|
| | | {
|
| | | result.Init(0, 0);
|
| | | return result;
|
| | | }
|
| | | //---
|
| | | if((data.Total() % vector_size) != 0)
|
| | | {
|
| | | result.Init(0, 0);
|
| | | return result;
|
| | | }
|
| | | //---
|
| | | ulong rows = data.Total() / vector_size;
|
| | | if(!result.Init(rows, vector_size))
|
| | | {
|
| | | result.Init(0, 0);
|
| | | return result;
|
| | | }
|
| | | for(ulong r = 0; r < rows; r++)
|
| | | {
|
| | | ulong shift = r * vector_size;
|
| | | for(ulong c = 0; c < vector_size; c++)
|
| | | result[r, c] = data[(int)(shift + c)];
|
| | | }
|
| | | //---
|
| | | return result;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | F ro mB uf fe r implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | vectorf CPCA::FromBuffer(CBufferFloat *data)
|
| | | {
|
| | | vectorf result;
|
| | | result.Init(0);
|
| | | if(CheckPointer(data) == POINTER_INVALID)
|
| | | return result;
|
| | | //---
|
| | | ulong rows = data.Total();
|
| | | if(!result.Init(rows))
|
| | | return result;
|
| | | for(ulong r = 0; r < rows; r++)
|
| | | result[r] = data[(int)r];
|
| | | //---
|
| | | return result;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CPCA::FromMatrix(matrixf &data)
|
| | | {
|
| | | CBufferFloat *result = new CBufferFloat();
|
| | | if(CheckPointer(result) == POINTER_INVALID)
|
| | | return result;
|
| | | //---
|
| | | ulong rows = data.Rows();
|
| | | ulong cols = data.Cols();
|
| | | if(!result.Reserve((int)(rows * cols)))
|
| | | {
|
| | | delete result;
|
| | | return result;
|
| | | }
|
| | | //---
|
| | | for(ulong r = 0; r < rows; r++)
|
| | | for(ulong c = 0; c < cols; c++)
|
| | | if(!result.Add(data[r, c]))
|
| | | {
|
| | | delete result;
|
| | | return result;
|
| | | }
|
| | | //---
|
| | | return result;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CPCA::FromVector(vectorf &data)
|
| | | {
|
| | | CBufferFloat *result = new CBufferFloat();
|
| | | if(CheckPointer(result) == POINTER_INVALID)
|
| | | return result;
|
| | | //---
|
| | | ulong rows = data.Size();
|
| | | if(!result.Reserve((int)rows))
|
| | | {
|
| | | delete result;
|
| | | return result;
|
| | | }
|
| | | //---
|
| | | for(ulong r = 0; r < rows; r++)
|
| | | if(!result.Add(data[r]))
|
| | | {
|
| | | delete result;
|
| | | return result;
|
| | | }
|
| | | //---
|
| | | return result;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CPCA::Reduce(CBufferFloat *data)
|
| | | {
|
| | | matrixf result = ReduceM(data);
|
| | | //---
|
| | | return FromMatrix(result);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CPCA::Reduce(matrixf &data)
|
| | | {
|
| | | matrixf result = ReduceM(data);
|
| | | //---
|
| | | return FromMatrix(result);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | R ed uc eM implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | matrixf CPCA::ReduceM(CBufferFloat *data)
|
| | | {
|
| | | matrixf result;
|
| | | result.Init(0, 0);
|
| | | if(!b_Studied || (data.Total() % m_Ureduce.Rows()) != 0)
|
| | | return result;
|
| | | result = FromBuffer(data, m_Ureduce.Rows());
|
| | | //---
|
| | | return ReduceM(result);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | R ed uc eM implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | matrixf CPCA::ReduceM(matrixf &data)
|
| | | {
|
| | | matrixf result;
|
| | | if(!b_Studied || data.Cols() != m_Ureduce.Rows())
|
| | | {
|
| | | result.Init(0, 0);
|
| | | return result;
|
| | | }
|
| | | //---
|
| | | ulong total = data.Rows();
|
| | | if(!result.Init(total, data.Cols()))
|
| | | {
|
| | | result.Init(0, 0);
|
| | | return result;
|
| | | }
|
| | | for(ulong r = 0; r < total; r++)
|
| | | {
|
| | | vectorf temp = data.Row(r) - v_Means;
|
| | | temp /= v_STDs;
|
| | | result.Row(temp, r);
|
| | | }
|
| | | //---
|
| | | return result.MatMul(m_Ureduce);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | S tu dy implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | bool CPCA::Study(matrixf &data)
|
| | | {
|
| | | matrixf X;
|
| | | ulong total = data.Rows();
|
| | | if(!X.Init(total, data.Cols()))
|
| | | return false;
|
| | | v_Means = data.Mean(0);
|
| | | v_STDs = data.Std(0) + 1e-8;
|
| | | for(ulong i = 0; i < total; i++)
|
| | | {
|
| | | vectorf temp = data.Row(i) - v_Means;
|
| | | temp /= v_STDs;
|
| | | X.Row(temp, i);
|
| | | }
|
| | | //---
|
| | | X = X.Transpose().MatMul(X / total);
|
| | | matrixf U, V;
|
| | | vectorf S;
|
| | | if(!X.SVD(U, V, S))
|
| | | return false;
|
| | | //---
|
| | | double sum_total = S.Sum();
|
| | | if(sum_total <= 0)
|
| | | return false;
|
| | | S = S.CumSum() / sum_total;
|
| | | int k = 0;
|
| | | while(S[k] < 0.99)
|
| | | k++;
|
| | | if(!U.Resize(U.Rows(), k + 1))
|
| | | return false;
|
| | | //---
|
| | | m_Ureduce = U;
|
| | | b_Studied = true;
|
| | | return true;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | S tu dy implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | bool CPCA::Study(CBufferFloat *data, int vector_size)
|
| | | {
|
| | | matrixf d = FromBuffer(data, vector_size);
|
| | | return Study(d);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | S av e implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | bool CPCA::Save(const int file_handle)
|
| | | {
|
| | | if(file_handle == INVALID_HANDLE)
|
| | | return false;
|
| | | //---
|
| | | if(FileWriteInteger(file_handle, (int)b_Studied) < INT_VALUE)
|
| | | return false;
|
| | | if(!b_Studied)
|
| | | return true;
|
| | | //---
|
| | | CBufferFloat *temp = FromMatrix(m_Ureduce);
|
| | | if(CheckPointer(temp) == POINTER_INVALID)
|
| | | return false;
|
| | | if(FileWriteLong(file_handle, (long)m_Ureduce.Cols()) <= 0)
|
| | | {
|
| | | delete temp;
|
| | | return false;
|
| | | }
|
| | | if(!temp.Save(file_handle))
|
| | | {
|
| | | delete temp;
|
| | | return false;
|
| | | }
|
| | | delete temp;
|
| | | //---
|
| | | temp = FromVector(v_Means);
|
| | | if(CheckPointer(temp) == POINTER_INVALID)
|
| | | return false;
|
| | | if(!temp.Save(file_handle))
|
| | | {
|
| | | delete temp;
|
| | | return false;
|
| | | }
|
| | | delete temp;
|
| | | //---
|
| | | temp = FromVector(v_STDs);
|
| | | if(CheckPointer(temp) == POINTER_INVALID)
|
| | | return false;
|
| | | if(!temp.Save(file_handle))
|
| | | {
|
| | | delete temp;
|
| | | return false;
|
| | | }
|
| | | delete temp;
|
| | | //---
|
| | | return true;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | L oa d implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | bool CPCA::Load(const int file_handle)
|
| | | {
|
| | | if(file_handle == INVALID_HANDLE)
|
| | | return false;
|
| | | //---
|
| | | b_Studied = (bool)FileReadInteger(file_handle);
|
| | | if(!b_Studied)
|
| | | return true;
|
| | | //---
|
| | | CBufferFloat *temp = new CBufferFloat();
|
| | | if(CheckPointer(temp) == POINTER_INVALID)
|
| | | return false;
|
| | | long cols = FileReadLong(file_handle);
|
| | | if(!temp.Load(file_handle))
|
| | | {
|
| | | delete temp;
|
| | | return false;
|
| | | }
|
| | | m_Ureduce = FromBuffer(temp, cols);
|
| | | //---
|
| | | if(!temp.Load(file_handle))
|
| | | {
|
| | | delete temp;
|
| | | return false;
|
| | | }
|
| | | v_Means = FromBuffer(temp);
|
| | | //---
|
| | | if(!temp.Load(file_handle))
|
| | | {
|
| | | delete temp;
|
| | | return false;
|
| | | }
|
| | | v_STDs = FromBuffer(temp);
|
| | | //---
|
| | | delete temp;
|
| | | //---
|
| | | return true;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | |
|