3

I have a matrix containing angles and I need to compute the mean and the variance. for the mean I procede in this way: for each angles compute sin and cos and sum all sin and all cos the mean is given by the atan2(sin, cos) and it works my question is how to compute the variance of angles knowing the mean?

thank you for the answers

I attach my matlab code:

for i=1:size(im2,1)

    for j=1:size(im2,2)
        y=y+sin(hue(i, j));
        x=x+cos(hue(i, j));
    end
end
mean=atan2(y, x);

if mean<0

    mean=mean+(2*pi);
end
Lucas
  • 13,679
  • 13
  • 62
  • 94
andrea
  • 1,326
  • 7
  • 31
  • 60

4 Answers4

4

In order to compute variance of an angle you can not use standard variance. This is the formulation to compute var of an angles:

R = 1 - sqrt((sum(sin(angle)))^2 + (sum(cos(angle)))^2)/n;

There is similar other formulation as well:

var(angle) = var(sin(angle)) + var(cos(angle));

Ref: http://www.ebi.ac.uk/thornton-srv/software/PROCHECK/nmr_manual/man_cv.html

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
3

I am not 100% sure what you are doing, but maybe this would achieve the same thing with the build in MATLAB functions mean and var.

>> [file path] = uigetfile;
>> someImage = imread([path file]);
>> hsv = rgb2hsv(someImage);
>> hue = hsv(:,:,1);
>> m = mean(hue(:))

m =

    0.5249

>> v = var(hue(:))

v =

    0.2074

EDIT: I am assuming you have an image because of your variable name hue. But it would be the same for any matrix.

EDIT 2: Maybe that is what you are looking for:

>> sumsin = sum(sin(hue(:)));
>> sumcos = sum(cos(hue(:)));
>> meanvalue = atan2(sumsin,sumcos)

meanvalue =

    0.5276

>> sumsin = sum(sin((hue(:)-meanvalue).^2));
>> sumcos = sum(cos((hue(:)-meanvalue).^2));
>> variance = atan2(sumsin,sumcos)

variance =

    0.2074
Lucas
  • 13,679
  • 13
  • 62
  • 94
  • well my problem is that I can't use just the mean: if I have 2 angles like 30° and 60° the mean should be 45° like with the normal mean, but if I have 30° and 330° I need the mean to be 0° that's why I had to calculate the mean in a different way – andrea Feb 11 '11 at 13:47
  • bte you're right with the fact I'm working on image, the problem of the mean is if the image has a majority of red pixels (so around 0-30° or 330°-360°) – andrea Feb 11 '11 at 13:54
  • @andrea: Ah, very good, I understand what you are doing. I added something. Not sure if it's working. I eliminated the loops though. – Lucas Feb 11 '11 at 14:12
  • thanks a lot, it works this time!! just have to see if the variance for my work is better in the way tou told me or in this one, but is just a matter of try and see the results. variance=sum((hue(:)-meanvalue).^2)-meanvalue^2; and thanks for eliminate the loops – andrea Feb 11 '11 at 15:35
  • **This is not the correct way to compute mean and variance over angles.** – Cris Luengo May 14 '21 at 13:37
3

The variance of circular data can not be treated like the variance of unbounded data on the real line. (For very small variances, they are effectively equivalent, but for large variances the equivalence breaks down. It should be clear to you why this is.) I recommend Statistical Analysis of Circular Data by N.I. Fisher. This book contains a widely-used definition of circular variance that is computed from the mean resultant length of the unit vectors that correspond to the angles.

>> sumsin = sum(sin((hue(:)-meanvalue).^2));
>> sumcos = sum(cos((hue(:)-meanvalue).^2));

is wrong. You can't subtract angles like that.

By the way, this question really has nothing to do with MATLAB. You can probably get more/better answers posting on the statistics stack exchange

chairmanK
  • 91
  • 4
0

We had the same problem and in python, we could fix that with using scipy.cirvar which computes the circular variance for samples assumed to be in a range. For example:

from scipy.stats import circvar
circvar([0, 2*np.pi/3, 5*np.pi/3])
# 2.19722457734

circvar([0, 2*np.pi])
# -0.0

The problem with the proposed MATLAB code is that the variance of [0, 6.28] should be zero. By looking at the implementation of scipy.circvar it is like:


# Recast samples as radians that range between 0 and 2 pi and calculate the sine and cosine
samples, sin_samp, cos_samp, nmask = _circfuncs_common(samples, high, low)

sin_mean = sin_samp.mean()
cos_mean = cos_samp.mean()

R = np.minimum(1, hypot(sin_mean, cos_mean))
circular_variance = ((high - low)/2.0/pi)**2 * -2 * np.log(R)
aminrd
  • 4,300
  • 4
  • 23
  • 45