
Matrix Utils, estendendo as matrizes e a funcionalidade da biblioteca padrão de vetores
“Você nunca alcançará a perfeição porque sempre há espaço para melhorias.
No entanto, percorrendo o caminho para a perfeição, você aprenderá a melhorar.
Introdução
A classe Utils em python é uma classe utilitária de propósito geral com funções e linhas de código que podemos reutilizar sem criar uma instância de uma classe.
A biblioteca padrão para as matrizes nos fornece alguns recursos e métodos muito importantes que podemos usar para inicializar, transformar, manipular matrizes e muito mais, mas como qualquer outra biblioteca já construída, ela pode ser estendida para executar coisas extras que podem ser necessárias em alguns dos aplicativos.
As funções e métodos apresentados abaixo não estão em nenhuma ordem específica;
Conteúdo:
- Lendo uma matriz de um arquivo CSV
- Ler os valores codificados do arquivo CSV
- Escrevendo uma matriz em um arquivo CSV
- Transformando uma matriz em vetor
- Transformando um vetor em matriz
- Transformando um array em vetor
- Vetor para Array
- Removendo uma única coluna da matriz
- Removendo várias colunas de uma matriz
- Removendo uma linha da matriz
- Remover um único valor de um vetor
- Divisão da matriz em matrizes de treinamento e teste
- Divisão de matrizes X e Y
- Criação de um modelo de matriz
- Matriz One Hot encoding
- Obtendo as classes de um vetor
- Criando um vetor de valores aleatórios
- Anexando um vetor ao outro
- Copiando um vetor para o outro
Lendo uma matriz de um arquivo CSV
Esta é uma função muito importante, pois nos permite carregar bancos de dados de um arquivo CSV e armazená-los em uma matriz sem esforço. Não há necessidade de enfatizar a importância desta função porque, durante a programação dos sistemas de negociação, muitas vezes precisamos carregar arquivos CSV contendo sinais de negociação ou histórico de negociação que queremos que o nosso programa possa acessar.
A primeira etapa na função (você adivinhou certo?) é ler um arquivo CSV. A primeira linha do arquivo CSV é considerada como tendo apenas strings, portanto, mesmo que haja valores na primeira linha, eles não serão incluídos na matriz já que a matriz não pode conter valores de string, em vez disso, os valores da primeira linha serão armazenados no array csv_header.while(!FileIsEnding(handle)) { string data = FileReadString(handle); //--- if(rows ==0) { ArrayResize(csv_header,column+1); csv_header[column] = data; } if(rows>0) //Avoid the first column which contains the column's header mat_[rows-1,column] = (double(data)); column++; //---
Essa matriz ajuda a acompanhar os nomes das colunas do arquivo CSV que acabamos de ler.
Código completo:
matrix CMatrixutils::ReadCsv(string file_name,string delimiter=",") { matrix mat_ = {}; int rows_total=0; int handle = FileOpen(file_name,FILE_READ|FILE_CSV|FILE_ANSI,delimiter); ResetLastError(); if(handle == INVALID_HANDLE) { printf("Invalid %s handle Error %d ",file_name,GetLastError()); Print(GetLastError()==0?" TIP | File Might be in use Somewhere else or in another Directory":""); } else { int column = 0, rows=0; while(!FileIsEnding(handle)) { string data = FileReadString(handle); //--- if(rows ==0) { ArrayResize(csv_header,column+1); csv_header[column] = data; } if(rows>0) //Avoid the first column which contains the column's header mat_[rows-1,column] = (double(data)); column++; //--- if(FileIsLineEnding(handle)) { rows++; mat_.Resize(rows,column); column = 0; } } rows_total = rows; FileClose(handle); } mat_.Resize(rows_total-1,mat_.Cols()); return(mat_); }
Uso:
Aqui está o arquivo CSV que queremos carregar em uma matrizCarregando o arquivo CSV em uma matriz;
Print("---> Reading a CSV file to Matrix\n"); Matrix = matrix_utils.ReadCsv("NASDAQ_DATA.csv"); ArrayPrint(matrix_utils.csv_header); Print(Matrix);Saída:
CS 0 06:48:21.228 matrix test (EURUSD,H1) "S&P500" "50SMA" "13RSI" "NASDAQ" CS 0 06:48:21.228 matrix test (EURUSD,H1) [[4173.8,13386.6,34.8,13067.5] CS 0 06:48:21.228 matrix test (EURUSD,H1) [4179.2,13396.7,36.6,13094.8] CS 0 06:48:21.228 matrix test (EURUSD,H1) [4182.7,13406.6,37.5,13108] CS 0 06:48:21.228 matrix test (EURUSD,H1) [4185.8,13416.8,37.1,13104.3] CS 0 06:48:21.228 matrix test (EURUSD,H1) [4180.8,13425.2,34.9,13082.2] CS 0 06:48:21.228 matrix test (EURUSD,H1) [4174.6,13432.2,31.8,13052] CS 0 06:48:21.228 matrix test (EURUSD,H1) [4174.9,13440.4,33.2,13082.2] CS 0 06:48:21.228 matrix test (EURUSD,H1) [4170.8,13447.6,32.2,13070.6] CS 0 06:48:21.228 matrix test (EURUSD,H1) [4182.2,13457.8,32.5,13078.8]
A razão pela qual eu decidi construir esta função é que eu não consegui encontrar uma maneira de ler um arquivo CSV da Biblioteca Padrão, eu esperava que este fosse o caminho a seguir para carregar os valores de um arquivo para um CSV Matrix.FromFile()
mas eu fiquei desapontado, se alguém souber como fazer isso nos documentos, informe-me na seção de discussão deste artigo.
Ler valores codificados do arquivo CSV
Muitas vezes, você pode precisar ler um arquivo CSV que contém valores de string, esses tipos de arquivos CSV que contêm strings são frequentemente encontrados quando se está procurando fazer algoritmos de classificação, dê uma olhada no conjunto de dados meteorológicos, que é bem popular;
Para poder codificar este arquivo csv, nós vamos ler todos os seus dados em uma única matriz de valores de string, porque as matrizes não podem carregar os valores de string dentro da função ReadCsvEncode(), a primeira coisa que temos a fazer é ler e conhecer as colunas presentes no arquivo CSV, em segundo lugar, fazemos um loop nessas colunas onde, a cada iteração, um csv é aberto e uma única coluna é lida inteiramente e os valores dessa coluna são obtidos e armazenados na matriz de todos os valores nomeados toArr[].
//--- Obtaining the columns matrix Matrix={}; //--- Loading the entire Matrix to an Array int csv_columns=0, rows_total=0; int handle = CSVOpen(file_name,delimiter); if (handle != INVALID_HANDLE) { while (!FileIsEnding(handle)) { string data = FileReadString(handle); csv_columns++; //--- if (FileIsLineEnding(handle)) break; } } FileClose(handle); ArrayResize(csv_header,csv_columns); //--- string toArr[]; int counter=0; for (int i=0; i<csv_columns; i++) { if ((handle = CSVOpen(file_name,delimiter)) != INVALID_HANDLE) { int column = 0, rows=0; while (!FileIsEnding(handle)) { string data = FileReadString(handle); column++; //--- if (column==i+1) { if (rows>=1) //Avoid the first column which contains the column's header { counter++; ArrayResize(toArr,counter); //array size for all the columns toArr[counter-1]=data; } else csv_header[column-1] = data; } //--- if (FileIsLineEnding(handle)) { rows++; column = 0; } } rows_total += rows-1; } FileClose(handle); } //---
Feito isso, o toArr[] fica assim quando impresso;
CS 0 06:00:15.952 matrix test (US500,D1) [ 0] "Sunny" "Sunny" "Overcast" "Rain" "Rain" "Rain" "Overcast" "Sunny" "Sunny" "Rain" "Sunny" "Overcast" CS 0 06:00:15.952 matrix test (US500,D1) [12] "Overcast" "Rain" "Hot" "Hot" "Hot" "Mild" "Cool" "Cool" "Cool" "Mild" "Cool" "Mild" CS 0 06:00:15.952 matrix test (US500,D1) [24] "Mild" "Mild" "Hot" "Mild" "High" "High" "High" "High" "Normal" "Normal" "Normal" "High" CS 0 06:00:15.952 matrix test (US500,D1) [36] "Normal" "Normal" "Normal" "High" "Normal" "High" "Weak" "Strong" "Weak" "Weak" "Weak" "Strong" CS 0 06:00:15.952 matrix test (US500,D1) [48] "Strong" "Weak" "Weak" "Weak" "Strong" "Strong" "Weak" "Strong" "No" "No" "Yes" "Yes" CS 0 06:00:15.952 matrix test (US500,D1) [60] "Yes" "No" "Yes" "No" "Yes" "Yes" "Yes" "Yes" "Yes" "No"
Se você prestar atenção a este array, notará que os valores de um arquivo CSV estão na ordem que foi obtido do arquivo CSV, do índice 0 ao 13 está a primeira coluna, do índice 14 ao 27 está a segunda coluna, etc. e assim por diante. A partir daí é fácil extrair os valores e codificá-los para finalmente armazená-los em uma matriz.
ulong mat_cols = 0,mat_rows = 0; if (ArraySize(toArr) % csv_columns !=0) printf("This CSV file named %s has unequal number of columns = %d and rows %d Its size = %d",file_name,csv_columns,ArraySize(toArr) / csv_columns,ArraySize(toArr)); else //preparing the number of columns and rows that out matrix needs { mat_cols = (ulong)csv_columns; mat_rows = (ulong)ArraySize(toArr)/mat_cols; } //--- Encoding the CSV Matrix.Resize(mat_rows,mat_cols); //--- string Arr[]; //temporary array to carry the values of a single column int start =0; vector v = {}; for (ulong j=0; j<mat_cols; j++) { ArrayCopy(Arr,toArr,0,start,(int)mat_rows); v = LabelEncoder(Arr); Matrix.Col(v, j); start += (int)mat_rows; } return (Matrix);
A função LabelEncoder() faz exatamente como o seu nome diz, ela coloca o mesmo rótulo para os recursos que são semelhantes na matriz de colunas, aqui está o que está dentro.
vector CMatrixutils::LabelEncoder(string &Arr[]) { string classes[]; vector Encoded((ulong)ArraySize(Arr)); Classes(Arr,classes); for (ulong A=0; A<classes.Size(); A++) for (ulong i=0; i<Encoded.Size(); i++) { if (classes[A] == Arr[i]) Encoded[i] = (int)A; } return Encoded; }
Esta função é fácil, ela faz um loop das classes fornecidas em todo o array para que ela possa encontrar os recursos semelhantes e colocar os rótulos neles, a maior parte do trabalho é feita dentro da função Classes() destacada em preto.
void CMatrixutils::Classes(const string &Array[],string &classes_arr[]) { string temp_arr[]; ArrayResize(classes_arr,1); ArrayCopy(temp_arr,Array); classes_arr[0] = Array[0]; for(int i=0, count =1; i<ArraySize(Array); i++) //counting the different neighbors { for(int j=0; j<ArraySize(Array); j++) { if(Array[i] == temp_arr[j] && temp_arr[j] != "nan") { bool count_ready = false; for(int n=0; n<ArraySize(classes_arr); n++) if(Array[i] == classes_arr[n]) count_ready = true; if(!count_ready) { count++; ArrayResize(classes_arr,count); classes_arr[count-1] = Array[i]; temp_arr[j] = "nan"; //modify so that it can no more be counted } else break; //Print("t vectors vector ",v); } else continue; } } }
Esta função obtém as classes presentes no array fornecido e passa para o array referenciado classes_arr[]. Esta função tem uma variante para localizar as classes em um vetor. Mais detalhes sobre esta função são encontrados aqui.
vector CMatrixutils::Classes(vector &v)
Abaixo está como usar esta função;
Matrix = matrix_utils.ReadCsvEncode("weather dataset.csv"); ArrayPrint(matrix_utils.csv_header); Print(Matrix);
Saída:
CS 0 06:35:10.798 matrix test (US500,D1) "Outlook" "Temperature" "Humidity" "Wind" "Play" CS 0 06:35:10.798 matrix test (US500,D1) [[0,0,0,0,0] CS 0 06:35:10.798 matrix test (US500,D1) [0,0,0,1,0] CS 0 06:35:10.798 matrix test (US500,D1) [1,0,0,0,1] CS 0 06:35:10.798 matrix test (US500,D1) [2,1,0,0,1] CS 0 06:35:10.798 matrix test (US500,D1) [2,2,1,0,1] CS 0 06:35:10.798 matrix test (US500,D1) [2,2,1,1,0] CS 0 06:35:10.798 matrix test (US500,D1) [1,2,1,1,1] CS 0 06:35:10.798 matrix test (US500,D1) [0,1,0,0,0] CS 0 06:35:10.798 matrix test (US500,D1) [0,2,1,0,1] CS 0 06:35:10.798 matrix test (US500,D1) [2,1,1,0,1] CS 0 06:35:10.798 matrix test (US500,D1) [0,1,1,1,1] CS 0 06:35:10.798 matrix test (US500,D1) [1,1,0,1,1] CS 0 06:35:10.798 matrix test (US500,D1) [1,0,1,0,1] CS 0 06:35:10.798 matrix test (US500,D1) [2,1,0,1,0]]
Escrevendo uma Matrix em um arquivo CSV
Esta é outra função importante que pode ajudar a gravar a matriz em um arquivo CSV sem a necessidade de codificar as coisas sempre que uma nova coluna é adicionada à matriz. Ser capaz de escrever de forma flexível em um arquivo CSV tem sido uma luta para muitas pessoas no fórum > Post1, Post2, Post3. Aqui está como fazer isso usando matrizes;row = Matrix.Row(i); for(ulong j=0, cols =1; j<row.Size(); j++, cols++) { concstring += (string)NormalizeDouble(row[j],digits) + (cols == Matrix.Cols() ? "" : ","); }
No final, isso se parecerá com um arquivo CSV escrito com diferentes colunas manualmente. Como a matriz não pode carregar os valores de string, eu tive que usar uma matriz de strings para nos permitir escrever o cabeçalho neste arquivo csv.
Vamos tentar escrever esta matriz que foi retirada de um arquivo CSV de volta para um novo arquivo CSV.
string csv_name = "matrix CSV.csv"; Print("\n---> Writing a Matrix to a CSV File > ",csv_name); string header[4] = {"S&P500","SMA","RSI","NASDAQ"}; matrix_utils.WriteCsv(csv_name,Matrix,header);
Abaixo está o arquivo CSV recém-escrito;
Legal.
Transformando uma matriz em vetor
Alguém pode se perguntar por que transformar uma matriz em um vetor? Isso é útil em muitas áreas, pois você pode não precisar de uma matriz o tempo todo, então o que esta função faz é converter a Matrix em um vetor, por exemplo, quando você lê a matriz de um arquivo CSV quando deseja fazer um modelo de regressão linear, a variável independente será uma matriz nx1 ou 1xn, ao tentar usar a função de perda como a MSE, você não pode usar a matriz para avaliar o modelo, em vez disso, você usará o vetor dessa variável independente e o vetor dos valores previstos pelo modelo.
Abaixo está o código para isso;vector CMatrixutils::MatrixToVector(const matrix &mat) { vector v = {}; if (!v.Assign(mat)) Print("Failed to turn the matrix to a vector"); return(v); }
Uso:
matrix mat = { {1,2,3}, {4,5,6}, {7,8,9} }; Print("\nMatrix to play with\n",mat,"\n"); //--- Print("---> Matrix to Vector"); vector vec = matrix_utils.MatrixToVector(mat); Print(vec);
Saída:
2022.12.20 05:39:00.286 matrix test (US500,D1) ---> Matrix to Vector 2022.12.20 05:39:00.286 matrix test (US500,D1) [1,2,3,4,5,6,7,8,9]
Transformando um vetor em matriz
Isso é exatamente o oposto da função que nós acabamos de ver acima, mas isso é mais importante do que você pode imaginar. Na maioria das vezes, em modelos de aprendizado de máquina, você precisa realizar operações de multiplicação entre diferentes matrizes. Como as variáveis independentes geralmente são armazenadas em um vetor, pode ser necessário transformá-las em uma matriz nx1 para fazer as operações, essas duas funções opostas são importantes pois elas fazem o nosso código para poucas variáveis ajustando as existentes.matrix CMatrixutils::VectorToMatrix(const vector &v) { matrix mat = {}; if (!mat.Assign(v)) Print("Failed to turn the vector to a 1xn matrix"); return(mat); }
Uso:
Print("\n---> Vector ",vec," to Matrix"); mat = matrix_utils.VectorToMatrix(vec); Print(mat);
Saída:
2022.12.20 05:50:05.680 matrix test (US500,D1) ---> Vector [1,2,3,4,5,6,7,8,9] to Matrix 2022.12.20 05:50:05.680 matrix test (US500,D1) [[1,2,3,4,5,6,7,8,9]]
Transformando um array em vetor
Quem precisa de muitos arrays dentro de programas de aprendizado de máquina? Arrays são muito úteis, mas são muito sensíveis ao tamanho. Ajustá-los com muita frequência e brincar com eles pode ajudar a plataforma a lançar seus programas fora do gráfico com esses tipos de erro de "array out of range", mesmo que os vetores façam a mesma coisa, mas são um pouco mais flexíveis que os arrays, sem mencionar que eles são orientados a objetos, você pode retornar um vetor de uma função, mas não uma matriz, a menos que queira esses erros e avisos de compilação de código.
vector CMatrixutils::ArrayToVector(const double &Arr[]) { vector v((ulong)ArraySize(Arr)); for(ulong i=0; i<v.Size(); i++) v[i] = Arr[i]; return (v); }
Uso:
Print("---> Array to vector"); double Arr[3] = {1,2,3}; vec = matrix_utils.ArrayToVector(Arr); Print(vec);
Saída:
CS 0 05:51:58.853 matrix test (US500,D1) ---> Array to vector CS 0 05:51:58.853 matrix test (US500,D1) [1,2,3]
Vetor para Array
Ainda não podemos abandonar as matrizes, pois pode haver momentos em que o vetor precisa ser convertido em uma matriz que precisa ser conectada a um argumento de função que aceita matrizes, ou podemos precisar fazer alguma classificação de matriz, definir como série, corte e muito mais manipulações que não poderíamos fazer com vetores. bool CMatrixutils::VectorToArray(const vector &v,double &arr[]) { ArrayResize(arr,(int)v.Size()); if(ArraySize(arr) == 0) return(false); for(ulong i=0; i<v.Size(); i++) arr[i] = v[i]; return(true); }
Uso:
Print("---> Vector to Array"); double new_array[]; matrix_utils.VectorToArray(vec,new_array); ArrayPrint(new_array);
Saída:
CS 0 06:19:14.647 matrix test (US500,D1) ---> Vector to Array CS 0 06:19:14.647 matrix test (US500,D1) 1.0 2.0 3.0
Remover a coluna de uma matriz
Só porque carregamos a coluna CSV em uma matriz, isso não significa que precisamos de todas as colunas dela. Ao criar o modelo de aprendizado de máquina supervisionado, precisamos descartar algumas colunas irrelevantes e sem mencionar que podemos precisar descartar a variável de resposta da matriz cheia de variáveis independentes.
Aqui está o código para fazê-lo:
void CMatrixutils::MatrixRemoveCol(matrix &mat, ulong col) { matrix new_matrix(mat.Rows(),mat.Cols()-1); //Remove the one Column for (ulong i=0, new_col=0; i<mat.Cols(); i++) { if (i == col) continue; else { new_matrix.Col(mat.Col(i),new_col); new_col++; } } mat.Copy(new_matrix); }
Não há nada de mágico dentro da função, criamos a nova matriz dimensionada com o mesmo número de linhas da matriz original, mas com uma coluna a menos.
matrix new_matrix(mat.Rows(),mat.Cols()-1); //Remove the one columnNa nova matriz, nós ignoramos a coluna que não é mais necessária da nossa nova matriz, todo o resto será armazenado e pronto.
No final da função, copiamos esta nova matriz para uma antiga.
mat.Copy(new_matrix);
Vamos descartar a coluna no índice 1 (segunda coluna) da matriz que acabamos de ler do arquivo CSV
Print("Col 1 ","Removed from Matrix"); matrix_utils.MatrixRemoveCol(Matrix,1); Print("New Matrix\n",Matrix);
Saída:
CS 0 07:23:59.612 matrix test (EURUSD,H1) Column of index 1 removed new Matrix CS 0 07:23:59.612 matrix test (EURUSD,H1) [[4173.8,34.8,13067.5] CS 0 07:23:59.612 matrix test (EURUSD,H1) [4179.2,36.6,13094.8] CS 0 07:23:59.612 matrix test (EURUSD,H1) [4182.7,37.5,13108] CS 0 07:23:59.612 matrix test (EURUSD,H1) [4185.8,37.1,13104.3] CS 0 07:23:59.612 matrix test (EURUSD,H1) [4180.8,34.9,13082.2] CS 0 07:23:59.612 matrix test (EURUSD,H1) [4174.6,31.8,13052] CS 0 07:23:59.612 matrix test (EURUSD,H1) [4174.9,33.2,13082.2] CS 0 07:23:59.612 matrix test (EURUSD,H1) [4170.8,32.2,13070.6] CS 0 07:23:59.612 matrix test (EURUSD,H1) [4182.2,32.5,13078.8]
Removendo várias colunas da Matrix
Esse foi o caso ao tentar remover uma única coluna, mas existem matrizes maiores que contêm muitas colunas que queremos descartar de uma vez, para conseguir isso, nós precisamos realizar algo complicado para evitar remover as colunas necessárias e também evitar tentando acessar valores que estão fora do intervalo, basicamente para remover as colunas com segurança.
O número/tamanho das colunas da nova matriz precisa ser igual ao número total de colunas subtraídas das colunas que queremos remover. O número de linhas para cada coluna é mantido constante (igual à matriz antiga).
A primeira coisa que temos que fazer é percorrer todas as colunas selecionadas que queremos remover versus todas as colunas disponíveis na matriz antiga, se as colunas devem ser removidas, definiremos todos os valores nessas colunas como zero. Esta é uma operação sábia a ser executada para finalizarmos com uma operação limpa.vector zeros(mat.Rows()); zeros.Fill(0); for(ulong i=0; i<size; i++) for(ulong j=0; j<mat.Cols(); j++) { if(cols[i] == j) mat.Col(zeros,j); }A última coisa que nós temos a fazer é percorrer a matriz novamente por duas vezes e verificar todas as colunas preenchidas com os valores iguais a zero e remover essas colunas uma a uma.
vector column_vector; for(ulong A=0; A<mat.Cols(); A++) for(ulong i=0; i<mat.Cols(); i++) { column_vector = mat.Col(i); if(column_vector.Sum()==0) MatrixRemoveCol(mat,i); }
Observou os loops duplos? eles são muito importantes porque esta matriz é ajustada em seu tamanho depois que cada coluna é removida, por isso é muito importante voltar novamente para verificar se nós pulamos alguma coluna.
Abaixo está o código completo da função;void CMatrixutils::MatrixRemoveMultCols(matrix &mat,int &cols[]) { ulong size = (int)ArraySize(cols); if(size > mat.Cols()) { Print(__FUNCTION__," Columns to remove can't be more than the available columns"); return; } vector zeros(mat.Rows()); zeros.Fill(0); for(ulong i=0; i<size; i++) for(ulong j=0; j<mat.Cols(); j++) { if(cols[i] == j) mat.Col(zeros,j); } //--- vector column_vector; for(ulong A=0; A<mat.Cols(); A++) for(ulong i=0; i<mat.Cols(); i++) { column_vector = mat.Col(i); if(column_vector.Sum()==0) MatrixRemoveCol(mat,i); } }
Vamos ver esta função em ação, vamos tentar remover a coluna no índice 0 e no índice 2;
Print("\nRemoving multiple columns"); int cols[2] = {0,2}; matrix_utils.MatrixRemoveMultCols(Matrix,cols); Print("Columns at 0,2 index removed New Matrix\n",Matrix);
Saída:
CS 0 07:32:10.923 matrix test (EURUSD,H1) Columns at 0,2 index removed New Matrix CS 0 07:32:10.923 matrix test (EURUSD,H1) [[13386.6,13067.5] CS 0 07:32:10.923 matrix test (EURUSD,H1) [13396.7,13094.8] CS 0 07:32:10.923 matrix test (EURUSD,H1) [13406.6,13108] CS 0 07:32:10.923 matrix test (EURUSD,H1) [13416.8,13104.3] CS 0 07:32:10.923 matrix test (EURUSD,H1) [13425.2,13082.2] CS 0 07:32:10.923 matrix test (EURUSD,H1) [13432.2,13052] CS 0 07:32:10.923 matrix test (EURUSD,H1) [13440.4,13082.2] CS 0 07:32:10.923 matrix test (EURUSD,H1) [13447.6,13070.6] CS 0 07:32:10.923 matrix test (EURUSD,H1) [13457.8,13078.8]
Removendo uma linha da matriz
Também pode ser necessário remover uma única linha do conjunto de dados porque ele é irrelevante ou porque se deseja reduzir o número de colunas apenas para ver o que funciona. Isso não é tão importante quanto remover a coluna da matriz, então só temos esta função para remover uma única linha, não veremos aquela para várias linhas, você pode programar por conta própria se quiser.
A mesma ideia foi aplicada ao tentar remover a linha da matriz., nós simplesmente ignoramos a linha indesejada na nova matriz que estamos fazendo.
void CMatrixutils::MatrixRemoveRow(matrix &mat, ulong row) { matrix new_matrix(mat.Rows()-1,mat.Cols()); //Remove the one Row for(ulong i=0, new_rows=0; i<mat.Rows(); i++) { if(i == row) continue; else { new_matrix.Row(mat.Row(i),new_rows); new_rows++; } } mat.Copy(new_matrix); }
Uso:
Print("Removing row 1 from matrix"); matrix_utils.MatrixRemoveRow(Matrix,1); printf("Row %d Removed New Matrix[%d][%d]",0,Matrix.Rows(),Matrix.Cols()); Print(Matrix);
Saída:
CS 0 06:36:36.773 matrix test (US500,D1) Removing row 1 from matrix CS 0 06:36:36.773 matrix test (US500,D1) Row 1 Removed New Matrix[743][4] CS 0 06:36:36.773 matrix test (US500,D1) [[4173.8,13386.6,34.8,13067.5] CS 0 06:36:36.773 matrix test (US500,D1) [4182.7,13406.6,37.5,13108] CS 0 06:36:36.773 matrix test (US500,D1) [4185.8,13416.8,37.1,13104.3] CS 0 06:36:36.773 matrix test (US500,D1) [4180.8,13425.2,34.9,13082.2] CS 0 06:36:36.773 matrix test (US500,D1) [4174.6,13432.2,31.8,13052] CS 0 06:36:36.773 matrix test (US500,D1) [4174.9,13440.4,33.2,13082.2] CS 0 06:36:36.773 matrix test (US500,D1) [4170.8,13447.6,32.2,13070.6]
Remover o índice do vetor
Este é curto, esta função ajuda a remover um único item em um índice específico de um vetor. Ele é capaz de alcançar tal resultado apenas ignorando o número localizado no índice dado do vetor, o restante dos valores é armazenado no novo vetor que é finalmente copiado para o vetor primário/referenciado do argumento da função.
void CMatrixutils::VectorRemoveIndex(vector &v, ulong index) { vector new_v(v.Size()-1); for(ulong i=0, count = 0; i<v.Size(); i++) if(i != index) { new_v[count] = v[i]; count++; } v.Copy(new_v); }
Abaixo está como usá-lo:
vector v= {0,1,2,3,4}; Print("Vector remove index 3"); matrix_utils.VectorRemoveIndex(v,3); Print(v);
Saída:
2022.12.20 06:40:30.928 matrix test (US500,D1) Vector remove index 3 2022.12.20 06:40:30.928 matrix test (US500,D1) [0,1,2,4]
Divisão da matriz em matrizes de treinamento e teste
Eu não posso enfatizar a importância dessa função ao criar um modelo de aprendizado de máquina supervisionado. Muitas vezes, precisamos dividir o conjunto de dados em conjuntos de dados de treinamento e teste para que possamos treinar o conjunto de dados em algum conjunto de dados e testá-lo em outro conjunto de dados que o modelo nunca viu antes.
Por padrão, essa função divide 70% do conjunto de dados na amostra de treinamento e os 30% restantes na amostra de teste. Não há estado aleatório. Os dados são selecionados na ordem cronológica da matriz, os primeiros 70% dos dados são armazenados na matriz de treinamento, enquanto os 30% restantes são armazenados na matriz de teste.
Print("---> Train / Test Split"); matrix TrainMatrix, TestMatrix; matrix_utils.TrainTestSplitMatrices(Matrix,TrainMatrix,TestMatrix); Print("\nTrain Matrix(",TrainMatrix.Rows(),",",TrainMatrix.Cols(),")\n",TrainMatrix); Print("\nTestMatrix(",TestMatrix.Rows(),",",TestMatrix.Cols(),")\n",TestMatrix);
Saída:
CS 0 07:38:46.011 matrix test (EURUSD,H1) Train Matrix(521,4) CS 0 07:38:46.011 matrix test (EURUSD,H1) [[4173.8,13386.6,34.8,13067.5] CS 0 07:38:46.011 matrix test (EURUSD,H1) [4179.2,13396.7,36.6,13094.8] CS 0 07:38:46.011 matrix test (EURUSD,H1) [4182.7,13406.6,37.5,13108] CS 0 07:38:46.011 matrix test (EURUSD,H1) [4185.8,13416.8,37.1,13104.3] CS 0 07:38:46.011 matrix test (EURUSD,H1) [4180.8,13425.2,34.9,13082.2] .... .... CS 0 07:38:46.012 matrix test (EURUSD,H1) TestMatrix(223,4) CS 0 07:38:46.012 matrix test (EURUSD,H1) [[4578.1,14797.9,65.90000000000001,15021.1] CS 0 07:38:46.012 matrix test (EURUSD,H1) [4574.9,14789.2,63.9,15006.2] CS 0 07:38:46.012 matrix test (EURUSD,H1) [4573.6,14781.4,63,14999] CS 0 07:38:46.012 matrix test (EURUSD,H1) [4571.4,14773.9,62.1,14992.6] CS 0 07:38:46.012 matrix test (EURUSD,H1) [4572.8,14766.3,65.2,15007.1]
Divisão das matrizes em X e Y
Ao tentar criar modelos de aprendizado supervisionado depois de carregarmos o conjunto de dados em uma matriz, a próxima coisa que precisamos é extrair as variáveis de destino da matriz e armazená-las independentemente da mesma forma que queremos que as variáveis independentes sejam armazenadas em sua matriz de valores, esta é a função para fazer isso:if(y_index == -1) value = matrix_.Cols()-1; //Last column in the matrix
Uso:
Print("---> X and Y split matrices"); matrix x; vector y; matrix_utils.XandYSplitMatrices(Matrix,x,y); Print("independent vars\n",x); Print("Target variables\n",y);
Saída:
CS 0 05:05:03.467 matrix test (US500,D1) ---> X and Y split matrices CS 0 05:05:03.467 matrix test (US500,D1) independent vars CS 0 05:05:03.468 matrix test (US500,D1) [[4173.8,13386.6,34.8] CS 0 05:05:03.468 matrix test (US500,D1) [4179.2,13396.7,36.6] CS 0 05:05:03.468 matrix test (US500,D1) [4182.7,13406.6,37.5] CS 0 05:05:03.468 matrix test (US500,D1) [4185.8,13416.8,37.1] CS 0 05:05:03.468 matrix test (US500,D1) [4180.8,13425.2,34.9] CS 0 05:05:03.468 matrix test (US500,D1) [4174.6,13432.2,31.8] CS 0 05:05:03.468 matrix test (US500,D1) [4174.9,13440.4,33.2] CS 0 05:05:03.468 matrix test (US500,D1) [4170.8,13447.6,32.2] CS 0 05:05:03.468 matrix test (US500,D1) [4182.2,13457.8,32.5] .... .... 2022.12.20 05:05:03.470 matrix test (US500,D1) Target variables 2022.12.20 05:05:03.470 matrix test (US500,D1) [13067.5,13094.8,13108,13104.3,13082.2,13052,13082.2,13070.6,13078.8,...]
Dentro da função de divisão em X e Y, a coluna selecionada como variáveis y é armazenada na matriz Y enquanto o restante das colunas restantes é armazenada na matriz X.
void CMatrixutils::XandYSplitMatrices(const matrix &matrix_,matrix &xmatrix,vector &y_vector,int y_index=-1) { ulong value = y_index; if(y_index == -1) value = matrix_.Cols()-1; //Last column in the matrix //--- y_vector = matrix_.Col(value); xmatrix.Copy(matrix_); MatrixRemoveCol(xmatrix, value); //Remove the y column }
Fazendo um modelo da matriz
A matriz modelo é essencial para o algoritmo dos mínimos quadrados, ele é apenas a matriz x (matriz de variáveis independentes) com a primeira coluna preenchida com os valores iguais a um. Esta matriz modelo nos ajuda a obter os coeficientes para o modelo de regressão linear. Dentro da função DesignMatrix() o vetor preenchido com valores iguais a um é criado, ele é inserido na primeira coluna da matriz, enquanto o restante das colunas é definido para seguir a ordem;Código completo:![]()
matrix CMatrixutils::DesignMatrix(matrix &x_matrix) { matrix out_matrix(x_matrix.Rows(),x_matrix.Cols()+1); vector ones(x_matrix.Rows()); ones.Fill(1); out_matrix.Col(ones,0); vector new_vector; for(ulong i=1; i<out_matrix.Cols(); i++) { new_vector = x_matrix.Col(i-1); out_matrix.Col(new_vector,i); } return (out_matrix); }
Uso:
Print("---> Design Matrix\n"); matrix design = matrix_utils.DesignMatrix(x); Print(design);
Saída:
CS 0 05:28:51.786 matrix test (US500,D1) ---> Design Matrix CS 0 05:28:51.786 matrix test (US500,D1) CS 0 05:28:51.786 matrix test (US500,D1) [[1,4173.8,13386.6,34.8] CS 0 05:28:51.786 matrix test (US500,D1) [1,4179.2,13396.7,36.6] CS 0 05:28:51.786 matrix test (US500,D1) [1,4182.7,13406.6,37.5] CS 0 05:28:51.786 matrix test (US500,D1) [1,4185.8,13416.8,37.1] CS 0 05:28:51.786 matrix test (US500,D1) [1,4180.8,13425.2,34.9] CS 0 05:28:51.786 matrix test (US500,D1) [1,4174.6,13432.2,31.8] CS 0 05:28:51.786 matrix test (US500,D1) [1,4174.9,13440.4,33.2] CS 0 05:28:51.786 matrix test (US500,D1) [1,4170.8,13447.6,32.2] CS 0 05:28:51.786 matrix test (US500,D1) [1,4182.2,13457.8,32.5]
Matriz One hot encoding
Vamos fazer uma One hot encoding. Esta é uma função muito importante que você precisará ao tentar fazer as redes neurais de classificação. Esta função se mostra de grande importância, pois ela deixa claro para a MLP para relacionar as saídas do neurônio na última camada com os valores reais.
Em uma matriz codificada a quente, o vetor para cada linha consiste em valores iguais a zero, exceto por um valor que é o valor correto que queremos atingir, que terá o valor igual a 1.
Para entender bem vamos ver o exemplo abaixo:
suponha que este seja o conjunto de dados que queremos treinar a rede neural, para poder classificar entre as três classes, Cachorro, Gato e Rato, com base na altura das pernas e no diâmetro do corpo.
O perceptron multicamadas terá 2 nós/neurônios de entrada, um para a altura das pernas e outro para o diâmetro do corpo na camada de entrada, enquanto a camada de saída terá 3 nós representando os 3 resultados Cachorro, Gato e Camundongos.
Agora digamos que alimentamos esta MLP com o valor de 12 e 20 para altura e diâmetro respectivamente, nós esperamos que a rede neural classifique isso como um cachorro, certo? o que a One hot encoding faz é colocar o valor igual a um em um nó que tem o valor correto para o conjunto de dados de treinamento fornecido, neste caso, no nó de um cachorro, o valor de 1 será colocado e o restante será carregado com os valores iguais a zero.
Como o restante dos valores tem zeros, podemos calcular a função de custo substituindo os valores de um vetor one hot encoding por cada uma das probabilidades que o modelo nos forneceu, esse erro será propagado de volta à rede em seus respectivos nós anteriores de uma camada anterior.
Ok, agora vamos ver o One hot Encoding em ação.
Esta é a nossa matriz no MetaEditor;
matrix dataset = { {12,28, 1}, {11,14, 1}, {7,8, 2}, {2,4, 3} };
Este é o mesmo conjunto de dados que você viu em um CSV, exceto que o destino é rotulado em números inteiros, pois não podemos ter strings em uma matriz, a propósito, quando e onde você pode usar strings em cálculos?
matrix dataset = { {12,28, 1}, {11,14, 1}, {7,8, 2}, {2,4, 3} }; vector y_vector = dataset.Col(2); //obtain the column to encode uint classes = 3; //number of classes in the column Print("One Hot encoded matrix \n",matrix_utils.OneHotEncoding(y_vector,classes));
Abaixo está a saída:
CS 0 08:54:04.744 matrix test (EURUSD,H1) One Hot encoded matrix CS 0 08:54:04.744 matrix test (EURUSD,H1) [[1,0,0] CS 0 08:54:04.744 matrix test (EURUSD,H1) [1,0,0] CS 0 08:54:04.744 matrix test (EURUSD,H1) [0,1,0] CS 0 08:54:04.744 matrix test (EURUSD,H1) [0,0,1]]
Obtendo as classes de um vetor
Esta função retorna o vetor contendo as classes disponíveis no vetor dado, por exemplo; um vetor com [1,2,3] tem 3 classes diferentes. Um vetor de [1,0,1,0] tem duas classes diferentes. O papel da função é retornar as classes distintas disponíveis.
vector v = {1,0,0,0,1,0,1,0}; Print("classes ",matrix_utils.Classes(v));
Saída:
2022.12.27 06:41:54.758 matrix test (US500,D1) classes [1,0]
Criando um vetor de valores aleatórios.
Existem diversas vezes que precisamos gerar um vetor cheio de variáveis aleatórias, essa função pode ajudar. O uso mais comum dessa função é gerar pesos e vetores de pesos e viés para a NN. Você também pode usá-lo para criar amostras de conjuntos de dados aleatórios.
vector Random(int min, int max, int size); vector Random(double min, double max, int size);
Uso:
v = matrix_utils.Random(1.0,2.0,10); Print("v ",v);
Saída:
2022.12.27 06:50:03.055 matrix test (US500,D1) v [1.717642750328074,1.276955473494675,1.346263008514664,1.32959990234077,1.006469924008911,1.992980742820521,1.788445692312387,1.218909268471328,1.732139042329173,1.512405774101993]
Anexando um vetor a outro.
Isso é algo como a concatenação de strings, mas, em vez disso, concatenamos vetores. Eu me vi querendo usar essa função em muitos casos. Abaixo está o que foi feito,
vector CMatrixutils::Append(vector &v1, vector &v2) { vector v_out = v1; v_out.Resize(v1.Size()+v2.Size()); for (ulong i=v2.Size(),i2=0; i<v_out.Size(); i++, i2++) v_out[i] = v2[i2]; return (v_out); }
Uso:
vector v1 = {1,2,3}, v2 = {4,5,6}; Print("Vector 1 & 2 ",matrix_utils.Append(v1,v2));
Saída:
2022.12.27 06:59:25.252 matrix test (US500,D1) Vector 1 & 2 [1,2,3,4,5,6]
Copiando um vetor para outro
Por último, mas não menos importante, vamos copiar um vetor para outro vetor, manipulando o vetor como a Arraycopy faz, geralmente não precisamos copiar o vetor inteiro para o outro, muitas vezes nós precisamos de apenas um pedaço dele, o método Copy fornecido pela biblioteca padrão falha em uma situação como esta.
bool CMatrixutils::Copy(const vector &src,vector &dst,ulong src_start,ulong total=WHOLE_ARRAY) { if (total == WHOLE_ARRAY) total = src.Size()-src_start; if ( total <= 0 || src.Size() == 0) { printf("Can't copy a vector | Size %d total %d src_start %d ",src.Size(),total,src_start); return (false); } dst.Resize(total); dst.Fill(0); for (ulong i=src_start, index =0; i<total+src_start; i++) { dst[index] = src[i]; index++; } return (true); }
Uso:
vector all = {1,2,3,4,5,6}; matrix_utils.Copy(all,v,3); Print("copied vector ",v);
Saída:
2022.12.27 07:15:41.420 matrix test (US500,D1) copied vector [4,5,6]
Pensamentos finais
Há muito que nós podemos fazer e muito mais funções que podemos adicionar ao arquivo utils, mas as funções e métodos apresentados neste artigo são os que eu acho que serão usados com maior frequência se estiver você usando matrizes há algum tempo e ao tentar criar sistemas de negociação complexos, como aquele inspirado no aprendizado de máquina.
Acompanhe o desenvolvimento desta da classe Utility Matrix no meu repositório do GitHub > https://github.com/MegaJoctan/MALE5
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/11858





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso