角度的均值与标准差(circular data/ directional statistics)

参考:

1. Directional statistics(Mardia)P14-19&29-30&47-50;

2. Biostatistical Analysis(2009 Zar)-5th edition P614-617;

3. CircStat: A MATLAB Toolbox for Circular Statistics(Philipp Berens);(这是一个MATLAB中实现的计算方向数据的一个工具包)

以上文献如有需要,可留下邮箱分享与你。

正文:

       最近因为做风的研究,需要衡量风向的一致性,就想转化到求角度的标准差。但是,当你去算得时候你就会发现,角度的标准差与平常的我们所算的标准差是不一样的。为行文方便,在本文中我把类似角度这样的数据(多是周期数据,如时间等)姑且称作——方向数据(directional statistics/ circular data),把其他数据(中学时就接触的那些算标准差的数据)称为——线性数据(data on the line)。

       为了直观表示方向数据,最简单的就是把它放在圆上:

图1 方向数据

       当我们想得到它的一些描述性数据(比如:均值、中位数、标准差等)时,最初的想法可能是在圆上的适当位置把圆断开,然后用惯常的线性数据方法去求取。这种方法非常依赖于断点的选择,为什么这样讲呢?比如,我们有一个数据集是:1°和359°,在0°处断开——得到均值是180°,标准差179°;在180°处断开——得到均值是0°,标准差1°。

 图2  一个简单的例子

         从上面例子中,我们看到这个断点的选择对我们描述性数据的影响是多么大。当然,我认为这种选断点来处理数据的方法,在一些情况下可能是简单而有用的——比如上面的例子中,我想大家都会同意断点在180°处是合理的。

         在Directional Statistics(Mardia&jupp, 2000)一书中,提出了一个适用更为广泛的方法,来求取方向数据的描述性数据。具体做法是将圆上的点,转化成平面上的单位向量,再进行后续处理。

数据预处理

         方向可以被视作单位向量x,或者等同于单位圆上的点。还有另外两种表示法:角度和单位复数。为单位圆指定初始方向和走向,就可以将单位圆上的点转化成角度θ或者单位复数z,以下是就是单位向量x的相关表示:

        (参看图3)

图3  方向 x用角θ和复数 z=cosθ+isinθ来表示

         方向用角度来表示可视作固有方法,因为方向本身就被当作圆上的点;方向用复数来表示可视作一种嵌入式的方法,因为这时方向被当作了平面上特殊的点。在嵌入式的方法中,原本在圆上的数据分布被认为是集中分布在平面的单位圆上。

         值得注意的是,方向用角度或者单位复数来表示时,数据的值依赖于初始方向和走向。一般情况下没有特别选定初始方向和走向,所以当你在处理同一数据集时,若选择了特殊的初始方向和走向,要注意数据的一致性。即是说,在方向数据领域,数据本身的属性——如离散性——与坐标无关。

方向数据的均值

         假设我们有单位向量,来表示对应角度。那么的平均方向就是的中心所指的方向。因为笛卡尔坐标系中的坐标是,因此数据集的中心就是,其中:

因此就是下式的结果:

其中平均值长度是:

值得注意的是时,是不存在的,或者说此种情况下我们没有定义样本的均值,当>0时,可这样求得:

其中‘arctan'是正切函数的反函数,取值范围是[-π/2, π/2],注意这里不等于

角度坐标系的问题

       罗盘的角度坐标系建立如图a,在Mardia的书中坐标系建立如图b,下面以分别以x,y指代a、b中的角度值:

在两坐标系中,x和y有如下关系:

 上面Mardia坐标系下求得的,其值的范围是(-π/2, -3π/2),所以在求得时候要注意下这个问题。下面是我在python中编写的求均值的程序:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
'''
@author: liucheng
created on 2018-10-16
Discription: This program is to calculate the discriptive measures --like variance, standard deviation, mean direction and so on-- of directional statistics

'''

import math
# import pandas as pd

# calculate standard deviation of angles
def calc_angles_stddev(data_list):    
    m_sin, m_cos = calc_mean_sin_cos(data_list)

    stddev = math.sqrt(-math.log(m_sin**2 + m_cos**2))#calculate standard deviation
    return stddev

# mean angle calculation in Mardia's coordinates
def calc_angles_mean1(data_list):
    m_sin, m_cos = calc_mean_sin_cos(data_list)

    mean_angle = math.atan(m_sin/m_cos)*(180/math.pi)  #calculate mean angle
    arctan1 = math.atan(m_sin/m_cos)*(180/math.pi)
    if (m_cos >= 0 ):
        mean_angle = mean_angle
    elif (m_cos < 0):
        mean_angle = mean_angle + 180
    if mean_angle < 0 :
        mean_angle = 360 + mean_angle  # 将 (-pi/2, 0)这一段的值转换成正值
    return mean_angle


# # mean angle calculation in compass coordinates
def calc_angles_mean2(data_list):
    lst = []
    for elem in data_list:  # 坐标系转换,将罗盘坐标系的角度值,转换到Mardia的坐标系下
        if elem > 90:
            elem = 450 - elem
        else:
            elem = 90 - elem
        lst.append(elem)
    
    m_sin, m_cos = calc_mean_sin_cos(lst) # 算 sin 和 cos 均值

    mean_angle = math.atan(m_sin/m_cos)*(180/math.pi)  # 计算角度均值,
    arctan2 = math.atan(m_sin/m_cos)*(180/math.pi)

    if (m_cos >= 0 ): # 依据Mardia的方法,均值转换
        mean_angle = mean_angle
    elif (m_cos < 0):
        mean_angle = mean_angle + 180

    if mean_angle < 0:  # 上面计算得到的均值范围(-pi/2, 3pi/2),这里将负值转换成正值
        mean_angle = 360 + mean_angle

    if mean_angle < 90:  # 将均值再转换回风向本身坐标系下
        mean_angle = 90 - mean_angle
    else:
        mean_angle = 450 - mean_angle

    return mean_angle

# calculation of mean sine and cosine for a set of angles
def calc_mean_sin_cos(data_list):
    m_sin = 0
    m_cos = 0
    for data_elmt in data_list:
        m_sin += math.sin(math.radians(data_elmt))
        m_cos += math.cos(math.radians(data_elmt))
    m_sin /= len(data_list)  #average of list sin
    m_cos /= len(data_list)

    return m_sin, m_cos


if __name__ == '__main__':
    data_list = [43, 45, 52, 61, 75, 88, 88, 297, 357] # a data set of angles
    a1 = calc_angles_mean1(data_list) # calculate mean angles in Mardia's coordinates
    a2 = calc_angles_mean2(data_list) # calculate mean angles in Compass coordinates

    dev = calc_angles_stddev(data_list)
        
    print('a1 = ', a1, '\na2 = ', a2, '\ndev = ', dev)

举个例子,以罗盘坐标系为例,称作例1吧:

图4 例1

       现有数据:[43°,45°,52°,61°,75°,88°,88°,297°,357°],按照以上方法可以得到平均值和平均值长度

图5 例1的均值

 

方向数据的中位数

       中位数在统计中也很重要,可以更好地帮我们去描述和理解数据。在方向数据中,中位数要满足两个条件:1半数的数据点应该在[,+π]中;2大部分的数据点应该更接近而不是+π。

       根据以上两个条件,我们可以得到例1——[43°,45°,52°,61°,75°,88°,88°,297°,357°]——的中位数是52°,这个值接近他的均值。

图6  例1的中位数

方向数据方差

       上面说到方向平均值的长度是:

       因为都是单位向量,因此:

       这个值是很有意义的,它能反映数据的离散性。具体是:若都紧紧聚集在一起,那么就接近于1;若相互间都分散地很开,那么就接近于0。我们可以这么说吧——的变化与方向数据的离散性成反比——越小,数据越分散,反之亦反。

      的取值范围是[0, 1],当=1时,说明所有点集中分布于同一点上,但是当=0时不能说明点在圆上均匀分布——下图就是两个反例。

       关于能反映离散性这一点,参考书目没有细说,直接给出了这么个结论,我想稍稍持有点谨慎的人都会生发出怀疑——真的能反映离散性吗?这里给出稍解释一下,希望能帮助大家理解(之前做了一次展示,但是大家都没怎么明白。。)。

       请看下图:

图7  与离散性

       从图7中,可以看到:当点越来越分散的时候,平均值长度变得越来越小,这样也就证明了我们前面所说的结论。当然,你可能会说这不是一个严谨的证明,只不过是几个例子罢了。这样说当然没错,但这里我给不出严谨的数学证明,参考书上也没讲,举这个例子只是为了让大家明白确实有这样的趋势。

       值得注意的是当点均匀分布在单位圆上时,计算得到=(0,0),而前面我们知道,是这样求得:

       因此这时就不能得到平均角度值了,实际上这个时候也没有相应地平均值,或者说我们不好定义在这种情况下平均值应该是什么。

       所以我们可以直接拿这个值来反映数据的离散性,当然,我们可以也可以另V=1-来作为数据的方差,这样离散性与方差就是正相关的了。

       此外,Batschelet(1981)把“circular variance”(循环数据方差)定义为

方向数据的标准差

       用上面介绍的V和来衡量离散性当然可以,至少能够定性的说明一些问题,比如比较两组数据离散性的大小,或者一组数据变化之后,相应离散性是如何变化的。

       下面要介绍的是Mardia书中介绍的一个方向数据的标准差,他提出的这个标准差是为了得到一个类似于线性数据那样的标准差,即是说这个标准差求得的结果对应于角度值,而之前的V和对离散性而言可以认为是一个没有实际意义的量纲。先说结论,在directional statistics(Mardia&Jupp, 2000)一书中,给出的方向数据的标准差是这样的:

他又说对于比较小的,该式可变为(这里Mardia也未说明原因,不知道为什么,难道他以为读者很厉害?这些变换都不言自明,一看就明白了?):

       在CircStat: A MATLAB Toolbox for Circular Statistics(Philipp Berens)一文中,作者说上面两个式子中后者更常用,因为是有界的[0, ]。

这个标准差得来的原因是假设方向数据在圆上服从正态分布的,该式得来在directional statistics一书中是这样介绍的:

1关于Wrapped Distribution(下文简称WD,wrapped:包裹、包装、覆盖)

定义:给定线性分布(distribution on the line),我们可以把它包裹(wrap)在单位圆上。即是说,如果x是线上的一个随机变量,那么相应地WD的随机变量是:

若用一组具有单位模长的复数来表示圆,那么就是:

若x有分布函数F,那么的分布函数是:

特别的,若x有概率密度函数f,那么相应地的概率密度函数为:

有了以上关于Wrapped Distribution的介绍我们来看看Wrapped Normal Distribution:

2Wrapped Normal Distribution(姑且称之为:包裹正态分布)

Mardia在他的书中原话是这样的:

其中3.5.57即上述(2)式。书里里讲到这里就完了,我在书中并未看到关于截图中3.5.63是怎么来的。我是这样想的:

包裹正态分布就是把正态分布包裹(wraping )在圆上得到的,其中:

这个式子怎么来的呢?我以为是这样的来的——因为对应线性数据的方差,于是根据上面“包裹”的变换法有:

由(4)进一步得到:

但是(5)相比于(3)等是右边少了一个2倍的关系,这样讲说不通。

基于此我对Mardia提出的这个标准差有以下看法:

1.Mardia在书中也仅讲了摆出来上面那一点,完全没说清楚,就发明了这么个标准差出来,因此我认为这个数没多大参考意义。

2.用到这个数,首先你的数据还得满足正态分布,因此其适用范围有限。

3.既然并没有多大意义,我认为在衡量离散性时用平均值长度就行了:

猜你喜欢

转载自blog.csdn.net/liuchengzimozigreat/article/details/83068696