2010-10-01 5 views
3

Je dois calculer la matrice de corrélation sur les vecteurs contenus dans un fichier csv de 5 Go. Chaque ligne contient une observation pour chaque variable aléatoire. Pour ce faire, j'ai écrit ce qui suit:Calcul de matrice de corrélation paresseuse en F #

let getCorrMatrix data = 

    let getMatrixInfo nCol (count,crossProd:float array array,sumVector:float array,sqVector:float array) (newLine:float array) = 

     for i in 0..(nCol-1) do 
       sumVector.[i]<-sumVector.[i]+newLine.[i] 
       sqVector.[i]<-sqVector.[i]+(newLine.[i]*newLine.[i]) 
       for j in (i+1)..(nCol-1) do 
        crossProd.[i].[j-(i+1)]<-crossProd.[i].[j-(i+1)]+newLine.[i]*newLine.[j] 

     let newCount = count+1 
     //(newCount,newMatrix,newSumVector,newSqVector)  
     (newCount,crossProd,sumVector,sqVector)   

    //Get number of columns 
    let nCol = data|>Seq.head|>Seq.length 

    //Initialize objects for the fold 
    let matrixStart = Array.init nCol (fun i -> Array.create (nCol-i-1) 0.0)      
    let sumVector = Array.init nCol (fun _ -> 0.0) 
    let sqVector = Array.init nCol (fun _ -> 0.0) 

    let init = (0,matrixStart,sumVector,sqVector) 

    //Run the fold and obtain all the elements to build te correlation matrix 
    let (count,crossProd,sum,sq) = 
     data 
     |>PSeq.fold(getMatrixInfo nCol) init 

    //Compute averages standard deviations, and finally correlations 
    let averages = sum|>Array.map(fun s ->s/(float count)) 
    let std = Array.zip3 sum sq averages 
       |> Array.map(fun (elemSum,elemSq,av)-> let temp = elemSq-2.0*av*elemSum+float(count)*av*av 
                sqrt (temp/(float count-1.0))) 

    //Map allteh elements to correlation           
    let rec getCorr i j = 
     if i=j then 
      1.0 
     elif i<j then 
      (crossProd.[i].[j-(i+1)]-averages.[i]*sum.[j]-averages.[j]*sum.[i]+(float count*averages.[i]*averages.[j]))/((float count-1.0)*std.[i]*std.[j]) 
     else 
      getCorr j i 

    let corrMatrix = Array2D.init nCol nCol (fun i j -> getCorr i j) 

    corrMatrix 

Je l'ai testé contre le calcul de R et il correspond. Depuis que je prévois d'utiliser encore et encore si vous avez des commentaires (ou repérer une erreur), il serait grandement apprécié. (Notez que je poste cela parce que je pensais que cela pourrait être utile aux autres aussi).

Merci

Répondre

2

Le problème majeur est dans le code suivant:

//Update crossproduct 
    let newMatrix = 
     [| for i in 0..(nCol-1) do 
      yield [| for j in (i+1)..(nCol-1) -> crossProd.[i].[j-(i+1)]+newLine.[i]*newLine.[j] |] 
            |] 

Vous créez une nouvelle matrice pour chaque ligne de votre data. C'est inefficace, vous ne pouvez utiliser qu'une seule matrice.

Il y a une F # mineur à noter:

  1. Utilisez sqrt comme raccourci pour System.Math.Sqrt. Évitez d'utiliser la compréhension de liste pour initialiser des tableaux simples. Par exemple. votre code

    let matrixStart = [| for i in 0..(nCol-1) do 
            yield [| for j in (i+1)..(nCol-1) -> 0.0 |] 
               |] 
    

    pourrait être écrire en utilisant des procédures standard:

    let matrixStart = Array.init nCol (fun i -> Array.create (nCol-i-1) 0.0) 
    

    un autre exemple, pour

    let corrMatrix = 
        [| for i in 0..(nCol-1) do 
         yield [| for j in 0..(nCol-1) -> getCorr i j |] 
                |] 
    

    au lieu d'utiliser float [][] vous pouvez utiliser float [,] et écrire

    let corrMatrix = Array2D.init nCol nCol (fun i j -> getCorr i j) 
    
+0

Le code de remerciements est beaucoup plus rapide! (Juste découvert votre site Web, très cool!) – jlezard

+1

et 'fun i j -> getCorr i j' peut juste être' getCorr'. :-) –

Questions connexes