Matrix averages in Haskell

I have a matrix, lets use this one for example:

[ [4.0, 2.0, 0.6],
  [4.2, 2.1, 0.59], 
  [3.9, 2.0, 0.58], 
  [4.3, 2.1, 0.62], 
  [4.1, 2.2, 0.63] ] 

Now, I take the average of each column, which results in this:

 [4.10, 2.08, 0.604]

All these I'm able to make, I have the informations.

What I'm having problem is at this part now. I'm looking a way to subtract each average element with his respective element on the first Matrix.

It should look like this:

[ [-0.1, -0.08, -0.004],
  [0.1, 0.02, -0.014],
  [-0.2, -0.08, -0.024],
  [0.2, 0.02, 0.016],
  [0.0, 0.12, 0.026]  ]

I have to make it viable for an arbitrary-sized matrix.

Upvotes: 0

Views: 143

Answers (2)

Emil
Emil

Reputation: 2167

Here's how I would do it:

mean l = sum l / (fromIntegral (length l))

getColumnMeans = map mean . transpose

normalizeMatrix m = map (zipWith subtract columnMeans) m
    where
        columnMeans = getColumnMeans m

mean does exactly what its name suggests and getColumnMeans is the function that you seem to have implemented yourself.

normalizeMatrix is the function that you are looking for. It takes in a matrix, computes its column means and then subtracts it from each of its rows via map.

subtract function is basically (-) but with its arguments flipped. I use it whenever I wanna map something like subtract 5 and it reads like regular English. So, subtract 5 10 would return 5. Here, zipWith subtract columnMeans does it on an entry-by-entry basis for a row. map does this for all rows. Hope this is useful.

Upvotes: 1

karakfa
karakfa

Reputation: 67507

something like this, without validations and formatting

colmean rs = let (a,c) = agg rs in map (/(fromIntegral c)) a

agg [r] = (r,1)
agg (r:rs) = let (a,c) = agg rs in (zipWith (+) a r, c+1)

minus = flip (zipWith (-))

demean x = map (minus $ colmean x) x

> demean media
[[-9.999999999999964e-2,-8.000000000000007e-2,-4.0000000000000036e-3],
 [0.10000000000000053,2.0000000000000018e-2,-1.4000000000000012e-2],
 [-0.19999999999999973,-8.000000000000007e-2,-2.400000000000002e-2],
 [0.20000000000000018,2.0000000000000018e-2,1.6000000000000014e-2],
 [0.0,0.1200000000000001,2.6000000000000023e-2]]

with this, the second dimension (number of columns) can be infinite

> map (take 10) $ demean [[1..], [2..]]
[[-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5],
 [0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5]]

Upvotes: 2

Related Questions