上半部分转载于:http://blog.codinglabs.org/articles/pca-tutorial.html
PCA(Principal Component Analysis,主成分分析)是一种常用的数据分析方法。PCA通过线性变换将原始数据变换为一组各维度线性无关的表示,可用于提取数据的主要特征分量,常用于高维数据的降维。网上关于PCA的文章有很多,但是大多数只描述了PCA的分析过程,而没有讲述其中的原理。这篇文章的目的是介绍PCA的基本数学原理,帮助读者了解PCA的工作机制是什么。
当然我并不打算把文章写成纯数学文章,而是希望用直观和易懂的方式叙述PCA的数学原理,所以整个文章不会引入严格的数学推导。希望读者在看完这篇文章后能更好的明白PCA的工作原理。
1.数据的向量表示及降维问题
一般情况下,在数据挖掘和机器学习中,数据被表示为向量。例如某个淘宝店2012年全年的流量及交易情况可以看成一组记录的集合,其中每一天的数据是一条记录,格式如下:
(日期, 浏览量, 访客数, 下单数, 成交数, 成交金额)
其中“日期”是一个记录标志而非度量值,而数据挖掘关心的大多是度量值,因此如果我们忽略日期这个字段后,我们得到一组记录,每条记录可以被表示为一个五维向量,其中一条看起来大约是这个样子:
注意这里我用了转置,因为习惯上使用列向量表示一条记录(后面会看到原因),本文后面也会遵循这个准则。不过为了方便有时我会省略转置符号,但我们说到向量默认都是指列向量。
我们当然可以对这一组五维向量进行分析和挖掘,不过我们知道,很多机器学习算法的复杂度和数据的维数有着密切关系,甚至与维数呈指数级关联。当然,这里区区五维的数据,也许还无所谓,但是实际机器学习中处理成千上万甚至几十万维的情况也并不罕见,在这种情况下,机器学习的资源消耗是不可接受的,因此我们必须对数据进行降维。
降维当然意味着信息的丢失,不过鉴于实际数据本身常常存在的相关性,我们可以想办法在降维的同时将信息的损失尽量降低。
举个例子,假如某学籍数据有两列M和F,其中M列的取值是如何此学生为男性取值1,为女性取值0;而F列是学生为女性取值1,男性取值0。此时如果我们统计全部学籍数据,会发现对于任何一条记录来说,当M为1时F必定为0,反之当M为0时F必定为1。在这种情况下,我们将M或F去掉实际上没有任何信息的损失,因为只要保留一列就可以完全还原另一列。
当然上面是一个极端的情况,在现实中也许不会出现,不过类似的情况还是很常见的。例如上面淘宝店铺的数据,从经验我们可以知道,“浏览量”和“访客数”往往具有较强的相关关系,而“下单数”和“成交数”也具有较强的相关关系。这里我们非正式的使用“相关关系”这个词,可以直观理解为“当某一天这个店铺的浏览量较高(或较低)时,我们应该很大程度上认为这天的访客数也较高(或较低)”。后面的章节中我们会给出相关性的严格数学定义。
这种情况表明,如果我们删除浏览量或访客数其中一个指标,我们应该期待并不会丢失太多信息。因此我们可以删除一个,以降低机器学习算法的复杂度。
上面给出的是降维的朴素思想描述,可以有助于直观理解降维的动机和可行性,但并不具有操作指导意义。例如,我们到底删除哪一列损失的信息才最小?亦或根本不是单纯删除几列,而是通过某些变换将原始数据变为更少的列但又使得丢失的信息最小?到底如何度量丢失信息的多少?如何根据原始数据决定具体的降维操作步骤?
要回答上面的问题,就要对降维问题进行数学化和形式化的讨论。而PCA是一种具有严格数学基础并且已被广泛采用的降维方法。下面我不会直接描述PCA,而是通过逐步分析问题,让我们一起重新“发明”一遍PCA。
2向量的表示及基变换
既然我们面对的数据被抽象为一组向量,那么下面有必要研究一些向量的数学性质。而这些数学性质将成为后续导出PCA的理论基础。
2.1内积与投影
下面先来看一个高中就学过的向量运算:内积。两个维数相同的向量的内积被定义为:
内积运算将两个向量映射为一个实数。其计算方式非常容易理解,但是其意义并不明显。下面我们分析内积的几何意义。假设A和B是两个n维向量,我们知道n维向量可以等价表示为n维空间中的一条从原点发射的有向线段,为了简单起见我们假设A和B均为二维向量,则A=(x1,y1),B=(x2,y2)。则在二维平面上A和B可以用两条发自原点的有向线段表示,见下图:
好,现在我们从A点向B所在直线引一条垂线。我们知道垂线与B的交点叫做A在B上的投影,再设A与B的夹角是a,则投影的矢量长度为|A|cos(a),其中 是向量A的模,也就是A线段的标量长度。
注意这里我们专门区分了矢量长度和标量长度,标量长度总是大于等于0,值就是线段的长度;而矢量长度可能为负,其绝对值是线段长度,而符号取决于其方向与标准方向相同或相反。
到这里还是看不出内积和这东西有什么关系,不过如果我们将内积表示为另一种我们熟悉的形式:
现在事情似乎是有点眉目了:A与B的内积等于A到B的投影长度乘以B的模。再进一步,如果我们假设B的模为1,即让|B|=1,那么就变成了:
也就是说,设向量B的模为1,则A与B的内积值等于A向B所在直线投影的矢量长度!这就是内积的一种几何解释,也是我们得到的第一个重要结论。在后面的推导中,将反复使用这个结论。
2.2基
下面我们继续在二维空间内讨论向量。上文说过,一个二维向量可以对应二维笛卡尔直角坐标系中从原点出发的一个有向线段。例如下面这个向量:
在代数表示方面,我们经常用线段终点的点坐标表示向量,例如上面的向量可以表示为(3,2),这是我们再熟悉不过的向量表示。
不过我们常常忽略,只有一个(3,2)本身是不能够精确表示一个向量的。我们仔细看一下,这里的3实际表示的是向量在x轴上的投影值是3,在y轴上的投影值是2。也就是说我们其实隐式引入了一个定义:以x轴和y轴上正方向长度为1的向量为标准。那么一个向量(3,2)实际是说在x轴投影为3而y轴的投影为2。注意投影是一个矢量,所以可以为负。
更正式的说,向量(x,y)实际上表示线性组合:
不难证明所有二维向量都可以表示为这样的线性组合。此处(1,0)和(0,1)叫做二维空间中的一组基。
所以,要准确描述向量,首先要确定一组基,然后给出在基所在的各个直线上的投影值,就可以了。只不过我们经常省略第一步,而默认以(1,0)和(0,1)为基。
我们之所以默认选择(1,0)和(0,1)为基,当然是比较方便,因为它们分别是x和y轴正方向上的单位向量,因此就使得二维平面上点坐标和向量一一对应,非常方便。但实际上任何两个线性无关的二维向量都可以成为一组基,所谓线性无关在二维平面内可以直观认为是两个不在一条直线上的向量。
例如,(1,1)和(-1,1)也可以成为一组基。一般来说,我们希望基的模是1,因为从内积的意义可以看到,如果基的模是1,那么就可以方便的用向量点乘基而直接获得其在新基上的坐标了!实际上,对应任何一个向量我们总可以找到其同方向上模为1的向量,只要让两个分量分别除以模就好了。例如,上面的基可以变为 和。
现在,我们想获得(3,2)在新基上的坐标,即在两个方向上的投影矢量值,那么根据内积的几何意义,我们只要分别计算(3,2)和两个基的内积,不难得到新的坐标为 。下图给出了新的基以及(3,2)在新基上坐标值的示意图:
另外这里要注意的是,我们列举的例子中基是正交的(即内积为0,或直观说相互垂直),但可以成为一组基的唯一要求就是线性无关,非正交的基也是可以的。不过因为正交基有较好的性质,所以一般使用的基都是正交的。
2.3基变换的矩阵表示
下面我们找一种简便的方式来表示基变换。还是拿上面的例子,想一下,将(3,2)变换为新基上的坐标,就是用(3,2)与第一个基做内积运算,作为第一个新的坐标分量,然后用(3,2)与第二个基做内积运算,作为第二个新坐标的分量。实际上,我们可以用矩阵相乘的形式简洁的表示这个变换:
太漂亮了!其中矩阵的两行分别为两个基,乘以原向量,其结果刚好为新基的坐标。可以稍微推广一下,如果我们有m个二维向量,只要将二维向量按列排成一个两行m列矩阵,然后用“基矩阵”乘以这个矩阵,就得到了所有这些向量在新基下的值。例如(1,1),(2,2),(3,3),想变换到刚才那组基上,则可以这样表示:
于是一组向量的基变换被干净的表示为矩阵的相乘。
一般的,如果我们有M个N维向量,想将其变换为由R个N维向量表示的新空间中,那么首先将R个基按行组成矩阵A,然后将向量按列组成矩阵B,那么两矩阵的乘积AB就是变换结果,其中AB的第m列为A中第m列变换后的结果。
数学表示为:
其中pi是一个行向量,表示第i个基,aj是一个列向量,表示第j个原始数据记录。
特别要注意的是,这里R可以小于N,而R决定了变换后数据的维数。也就是说,我们可以将一N维数据变换到更低维度的空间中去,变换后的维度取决于基的数量。因此这种矩阵相乘的表示也可以表示降维变换。
最后,上述分析同时给矩阵相乘找到了一种物理解释:两个矩阵相乘的意义是将右边矩阵中的每一列列向量变换到左边矩阵中每一行行向量为基所表示的空间中去。更抽象的说,一个矩阵可以表示一种线性变换。很多同学在学线性代数时对矩阵相乘的方法感到奇怪,但是如果明白了矩阵相乘的物理意义,其合理性就一目了然了。
3.协方差矩阵及优化目标
上面我们讨论了选择不同的基可以对同样一组数据给出不同的表示,而且如果基的数量少于向量本身的维数,则可以达到降维的效果。但是我们还没有回答一个最最关键的问题:如何选择基才是最优的。或者说,如果我们有一组N维向量,现在要将其降到K维(K小于N),那么我们应该如何选择K个基才能最大程度保留原有的信息?
要完全数学化这个问题非常繁杂,这里我们用一种非形式化的直观方法来看这个问题。
为了避免过于抽象的讨论,我们仍以一个具体的例子展开。假设我们的数据由五条记录组成,将它们表示成矩阵形式:
其中每一列为一条数据记录,而一行为一个字段。为了后续处理方便,我们首先将每个字段内所有值都减去字段均值,其结果是将每个字段都变为均值为0(这样做的道理和好处后面会看到)。
我们看上面的数据,第一个字段均值为2,第二个字段均值为3,所以变换后:
我们可以看下五条数据在平面直角坐标系内的样子:
现在问题来了:如果我们必须使用一维来表示这些数据,又希望尽量保留原始的信息,你要如何选择?
通过上一节对基变换的讨论我们知道,这个问题实际上是要在二维平面中选择一个方向,将所有数据都投影到这个方向所在直线上,用投影值表示原始记录。这是一个实际的二维降到一维的问题。
那么如何选择这个方向(或者说基)才能尽量保留最多的原始信息呢?一种直观的看法是:希望投影后的投影值尽可能分散。
以上图为例,可以看出如果向x轴投影,那么最左边的两个点会重叠在一起,中间的两个点也会重叠在一起,于是本身四个各不相同的二维点投影后只剩下两个不同的值了,这是一种严重的信息丢失,同理,如果向y轴投影最上面的两个点和分布在x轴上的两个点也会重叠。所以看来x和y轴都不是最好的投影选择。我们直观目测,如果向通过第一象限和第三象限的斜线投影,则五个点在投影后还是可以区分的。
下面,我们用数学方法表述这个问题。
3.1方差
方差(Variance)是度量一组数据的分散程度。方差是各个样本与样本均值的差的平方和的均值:
上文说到,我们希望投影后投影值尽可能分散,而这种分散程度,可以用数学上的方差来表述。此处,一个字段的方差可以看做是每个元素与字段均值的差的平方和的均值,即:
由于上面我们已经将每个字段的均值都化为0了,因此方差可以直接用每个元素的平方和除以元素个数表示:
于是上面的问题被形式化表述为:寻找一个一维基,使得所有数据变换为这个基上的坐标表示后,方差值最大。
3.2协方差
协方差(Covariance)是度量两个变量的变动的同步程度,也就是度量两个变量线性相关性程度。如果两个变量的协方差为0,则统计学上认为二者线性无关。注意两个无关的变量并非完全独立,只是没有线性相关性而已。
如果协方差大于0表示一个变量增大是另一个变量也会增大,即正相关,协方差小于0表示一个变量增大是另一个变量会减小,即负相关。
对于上面二维降成一维的问题来说,找到那个使得方差最大的方向就可以了。不过对于更高维,还有一个问题需要解决。考虑三维降到二维问题。与之前相同,首先我们希望找到一个方向使得投影后方差最大,这样就完成了第一个方向的选择,继而我们选择第二个投影方向。
如果我们还是单纯只选择方差最大的方向,很明显,这个方向与第一个方向应该是“几乎重合在一起”,显然这样的维度是没有用的,因此,应该有其他约束条件。从直观上说,让两个字段尽可能表示更多的原始信息,我们是不希望它们之间存在(线性)相关性的,因为相关性意味着两个字段不是完全独立,必然存在重复表示的信息。
数学上可以用两个字段的协方差表示其相关性,由于已经让每个字段均值为0,则:
可以看到,在字段均值为0的情况下,两个字段的协方差简洁的表示为其内积除以元素数m。
当协方差为0时,表示两个字段完全独立。为了让协方差为0,我们选择第二个基时只能在与第一个基正交的方向上选择。因此最终选择的两个方向一定是正交的。
至此,我们得到了降维问题的优化目标:将一组N维向量降为K维(K大于0,小于N),其目标是选择K个单位(模为1)正交基,使得原始数据变换到这组基上后,即变化之后的数据各字段两两间协方差为0,而字段的方差则尽可能大,(在正交的约束下,取最大的K个方差)。
3.3协方差矩阵
上面我们导出了优化目标,但是这个目标似乎不能直接作为操作指南(或者说算法),因为它只说要什么,但根本没有说怎么做。所以我们要继续在数学上研究计算方案。
我们看到,最终要达到的目的与字段内方差及字段间协方差有密切关系。因此我们希望能将两者统一表示,仔细观察发现,两者均可以表示为内积的形式,而内积又与矩阵相乘密切相关。于是我们来了灵感:
假设我们只有a和b两个字段,那么我们将它们按行组成矩阵X:
然后我们用X乘以X的转置,并乘上系数1/m:
奇迹出现了!这个矩阵对角线上的两个元素分别是两个字段的方差,而其它元素是a和b的协方差。两者被统一到了一个矩阵的。
根据矩阵相乘的运算法则,这个结论很容易被推广到一般情况:
设我们有m个n维数据记录,将其按列排成n乘m的矩阵X,设C=1mXXT,则C是一个对称矩阵,其对角线分别个各个字段的方差,而第i行j列和j行i列元素相同,表示i和j两个字段的协方差。
3.4协方差矩阵对角化
根据上述推导,我们发现要达到优化目前,等价于将协方差矩阵对角化:即除对角线外的其它元素化为0,并且在对角线上将元素按大小从上到下排列,这样我们就达到了优化目的。这样说可能还不是很明晰,我们进一步看下原矩阵与基变换后矩阵协方差矩阵的关系:
设原始数据矩阵X对应的协方差矩阵为C,而P是一组基按行组成的矩阵,设Y=PX,则Y为X对P做基变换后的数据。设Y的协方差矩阵为D,我们推导一下D与C的关系:
现在事情很明白了!我们要找的P不是别的,而是能让原始协方差矩阵对角化的P。换句话说,优化目标变成了寻找一个矩阵P,满足PCPT是一个对角矩阵,这样才能满足变化之后的数据各字段两两间协方差为0,而字段的方差则尽可能大,并且应该选择D中特征值大的数对应的P中的特征向量,并且对角元素按从大到小依次排列,那么P的前K行就是要寻找的基,用P的前K行组成的矩阵乘以X就使得X从N维降到了K维并满足上述优化条件。
至此,我们离“发明”PCA还有仅一步之遥!
现在所有焦点都聚焦在了协方差矩阵对角化问题上,有时,我们真应该感谢数学家的先行,因为矩阵对角化在线性代数领域已经属于被玩烂了的东西,所以这在数学上根本不是问题。
由上文知道,协方差矩阵C是一个是对称矩阵,在线性代数上,实对称矩阵有一系列非常好的性质:
1)实对称矩阵不同特征值对应的特征向量必然正交。
2)设特征向量λ重数为r,则必然存在r个线性无关的特征向量对应于λ,因此可以将这r个特征向量单位正交化。
由上面两条可知,一个n行n列的实对称矩阵一定可以找到n个单位正交特征向量,设这n个特征向量为 ,我们将其按列组成矩阵:
则对协方差矩阵C有如下结论:
其中Λ为对角矩阵,其对角元素为各特征向量对应的特征值(可能有重复)。
以上结论不再给出严格的数学证明,对证明感兴趣的朋友可以参考线性代数书籍关于“实对称矩阵对角化”的内容。
到这里,我们发现我们已经找到了需要的矩阵P:
P是协方差矩阵的特征向量单位化后按行排列出的矩阵,其中每一行都是C的一个特征向量。如果设P按照Λ中特征值的从大到小,将特征向量从上到下排列,则用P的前K行组成的矩阵乘以原始数据矩阵X,就得到了我们需要的降维后的数据矩阵Y。
至此我们完成了整个PCA的数学原理讨论。在下面的一节,我们将给出PCA的一个实例。
4.算法及实例
为了巩固上面的理论,我们在这一节给出一个具体的PCA实例。
4.1PCA算法
总结一下PCA的算法步骤:
设有m条n维数据。
1)将原始数据按列组成n行m列矩阵X
2)将X的每一行(代表一个属性字段)进行零均值化,即减去这一行的均值
3)求出协方差矩阵
4)求出协方差矩阵的特征值及对应的特征向量
5)将特征向量按对应特征值大小从上到下按行排列成矩阵,取前k行组成矩阵P
6)Y=PX即为降维到k维后的数据
4.2实例
这里以上文提到的
为例,我们用PCA方法将这组二维数据其降到一维。
因为这个矩阵的每行已经是零均值,这里我们直接求协方差矩阵:
然后求其特征值和特征向量,具体求解方法不再详述,可以参考相关资料。求解后特征值为:
其对应的特征向量分别是:
其中对应的特征向量分别是一个通解,c1和c2可取任意实数。那么标准化后的特征向量为:
因此我们的矩阵P是:
可以验证协方差矩阵C的对角化:
最后我们用P的第一行乘以数据矩阵,就得到了降维后的表示:
降维投影结果如下图:
5.进一步讨论
根据上面对PCA的数学原理的解释,我们可以了解到一些PCA的能力和限制。PCA本质上是将方差最大的方向作为主要特征,并且在各个正交方向上将数据“离相关”,也就是让它们在不同正交方向上没有相关性。
因此,PCA也存在一些限制,例如它可以很好的解除线性相关,但是对于高阶相关性就没有办法了,对于存在高阶相关性的数据,可以考虑Kernel PCA,通过Kernel函数将非线性相关转为线性相关,关于这点就不展开讨论了。另外,PCA假设数据各主特征是分布在正交方向上,如果在非正交方向上存在几个方差较大的方向,PCA的效果就大打折扣了。
最后需要说明的是,PCA是一种无参数技术,也就是说面对同样的数据,如果不考虑清洗,谁来做结果都一样,没有主观参数的介入,所以PCA便于通用实现,但是本身无法个性化的优化。
希望这篇文章能帮助朋友们了解PCA的数学理论基础和实现原理,借此了解PCA的适用场景和限制,从而更好的使用这个算法。
6.机器学习实战——PCA代码实现
import numpy
def loadDataSet(fileName, delim='\t'):
fr = open(fileName)#打开文件
stringArr = [line.strip().split(delim) for line in fr.readlines()]#去掉首尾的空格和以Tab键划分每行的数据
datArr = [list(map(float,line)) for line in stringArr]#把每个数据变为float形式
return numpy.mat(datArr)
def pca(dataMat, topNfeat=9999999):
meanVals = numpy.mean(dataMat, axis=0)#axis = 0:压缩行,对各列求均值,返回 1* n 矩阵,对每个特征值的数据求平均值
meanRemoved = dataMat - meanVals #remove mean#每个数据减平均值
covMat = numpy.cov(meanRemoved, rowvar=0)#计算数据的协方差,np.cov(X)其实就是把np.cov(x,y)中两个变量所有的维度纵向拼接在一起作为X参与运算
eigVals,eigVects = numpy.linalg.eig(numpy.mat(covMat))#求特征值,特征向量
eigValInd = numpy.argsort(eigVals) #对特征值进行排序从小到大 排列,得到的是排列好的原下标 #sort, sort goes smallest to largest
# x = np.array([3, 1, 2])
# np.argsort(x)
# array([1, 2, 0])
# 从小到大依次是1,2,3, 1对应的索引是1,2对应的索引是2,3对应的索引是0
# 逆序,从最大到最小的前topNfeat个
# 除去不需要的特征向量
eigValInd = eigValInd[:-(topNfeat+1):-1] #cut off unwanted dimensions,a[start:stop:step] 最后一位数是变化的幅度,即每次增加或者减小的值
redEigVects = eigVects[:,eigValInd] #reorganize eig vects largest to smallest得到相应的特征向量
lowDDataMat = meanRemoved * redEigVects #transform data into new dimensions转化数据到新的维度
reconMat = (lowDDataMat * redEigVects.T) + meanVals #降维后的数据再次映射到原来空间中,用于与原始数据进行比较 redEigVects*redEigVects.T=1
return lowDDataMat, reconMat
命令行:
import pca
import numpy
import matplotlib
import matplotlib.pyplot as plt
dataMat=pca.loadDataSet('testSet13.txt')
lowDMat,reconMat=pca.pca(dataMat,1)
print(numpy.shape(lowDMat))
fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(dataMat[:,0].flatten().A[0],dataMat[:,1].flatten().A[0],marker='^',s=90)#即返回一个折叠成一维的数组
ax.scatter(reconMat[:,0].flatten().A[0],reconMat[:,1].flatten().A[0],marker='o',s=50,c='red')
plt.show()
结果显示:
def replaceNanWithMean():
datMat = loadDataSet('secom.data', ' ')
numFeat = numpy.shape(datMat)[1]
for i in range(numFeat):
meanVal = numpy.mean(datMat[ numpy.nonzero(~ numpy.isnan(datMat[:,i].A))[0],i]) #values that are not NaN (a number)
#非NAN,非0的数求平均值
## numpy.isnan 判断是不是NAN,获得一个bool数组
datMat[ numpy.nonzero(numpy.isnan(datMat[:,i].A))[0],i] = meanVal #set NaN values to mean
return datMat
命令行:
dataMat=pca.replaceNanWithMean()
meanVals=numpy.mean(dataMat,axis=0)
meanRemoved=dataMat-meanVals
covMat=numpy.cov(meanRemoved,rowvar=0)
eigVals,eigVects=numpy.linalg.eig(numpy.mat(covMat))
print(eigVals)
结果:
[ 5.34151979e+07 2.17466719e+07 8.24837662e+06 2.07388086e+06
1.31540439e+06 4.67693557e+05 2.90863555e+05 2.83668601e+05
2.37155830e+05 2.08513836e+05 1.96098849e+05 1.86856549e+05
1.52422354e+05 1.13215032e+05 1.08493848e+05 1.02849533e+05
1.00166164e+05 8.33473762e+04 8.15850591e+04 7.76560524e+04
6.66060410e+04 6.52620058e+04 5.96776503e+04 5.16269933e+04
5.03324580e+04 4.54661746e+04 4.41914029e+04 4.15532551e+04
3.55294040e+04 3.31436743e+04 2.67385181e+04 1.47123429e+04
1.44089194e+04 1.09321187e+04 1.04841308e+04 9.48876548e+03
8.34665462e+03 7.22765535e+03 5.34196392e+03 4.95614671e+03
4.23060022e+03 4.10673182e+03 3.41199406e+03 3.24193522e+03
2.74523635e+03 2.35027999e+03 2.16835314e+03 1.86414157e+03
1.76741826e+03 1.70492093e+03 1.66199683e+03 1.53948465e+03
1.33096008e+03 1.25591691e+03 1.15509389e+03 1.12410108e+03
1.03213798e+03 1.00972093e+03 9.50542179e+02 9.09791361e+02
8.32001551e+02 8.08898242e+02 7.37343627e+02 6.87596830e+02
5.64452104e+02 5.51812250e+02 5.37209115e+02 4.93029995e+02
4.13720573e+02 3.90222119e+02 3.37288784e+02 3.27558605e+02
3.08869553e+02 2.46285839e+02 2.28893093e+02 1.96447852e+02
1.75559820e+02 1.65795169e+02 1.56428052e+02 1.39671194e+02
1.28662864e+02 1.15624070e+02 1.10318239e+02 1.08663541e+02
1.00695416e+02 9.80687852e+01 8.34968275e+01 7.53025397e+01
6.89260158e+01 6.67786503e+01 6.09412873e+01 5.30974002e+01
4.71797825e+01 4.50701108e+01 4.41349593e+01 4.03313416e+01
3.95741636e+01 3.74000035e+01 3.44211326e+01 3.30031584e+01
3.03317756e+01 2.88994580e+01 2.76478754e+01 2.57708695e+01
2.44506430e+01 2.31640106e+01 2.26956957e+01 2.16925102e+01
2.10114869e+01 2.00984697e+01 1.86489543e+01 1.83733216e+01
1.72517802e+01 1.60481189e+01 1.54406997e+01 1.48356499e+01
1.44273357e+01 1.42318192e+01 1.35592064e+01 1.30696836e+01
1.28193512e+01 1.22093626e+01 1.15228376e+01 1.12141738e+01
1.02585936e+01 9.86906139e+00 9.58794460e+00 9.41686288e+00
9.20276340e+00 8.63791398e+00 8.20622561e+00 8.01020114e+00
7.53391290e+00 7.33168361e+00 7.09960245e+00 7.02149364e+00
6.76557324e+00 6.34504733e+00 6.01919292e+00 5.81680918e+00
5.44653788e+00 5.12338463e+00 4.79593185e+00 4.47851795e+00
4.50369987e+00 4.27479386e+00 3.89124198e+00 3.56466892e+00
3.32248982e+00 2.97665360e+00 2.61425544e+00 2.31802829e+00
2.17171124e+00 1.99239284e+00 1.96616566e+00 1.88149281e+00
1.79228288e+00 1.71378363e+00 1.68028783e+00 1.60686268e+00
1.47158244e+00 1.40656712e+00 1.37808906e+00 1.27967672e+00
1.22803716e+00 1.18531109e+00 9.38857180e-01 9.18222054e-01
8.26265393e-01 7.96585842e-01 7.74597255e-01 7.14002770e-01
6.79457797e-01 6.37928310e-01 6.24646758e-01 5.34605353e-01
4.60658687e-01 4.24265893e-01 4.08634622e-01 3.70321764e-01
3.67016386e-01 3.35858033e-01 3.29780397e-01 2.94348753e-01
2.84154176e-01 2.72703994e-01 2.63265991e-01 2.45227786e-01
2.25805135e-01 2.22331919e-01 2.13514673e-01 1.93961935e-01
1.91647269e-01 1.83668491e-01 1.82518017e-01 1.65310922e-01
1.57447909e-01 1.51263974e-01 1.39427297e-01 1.32638882e-01
1.28000027e-01 1.13559952e-01 1.12576237e-01 1.08809771e-01
1.07136355e-01 8.60839655e-02 8.50467792e-02 8.29254355e-02
7.03701660e-02 6.44475619e-02 6.09866327e-02 6.05709478e-02
5.93963958e-02 5.22163549e-02 4.92729703e-02 4.80022983e-02
4.51487439e-02 4.30180504e-02 4.13368324e-02 4.03281604e-02
3.91576587e-02 3.54198873e-02 3.31199510e-02 3.13547234e-02
3.07226509e-02 2.98354196e-02 2.81949091e-02 2.49158051e-02
2.36374781e-02 2.28360210e-02 2.19602047e-02 2.00166957e-02
1.86597535e-02 1.80415918e-02 1.72261012e-02 1.60703860e-02
1.49566735e-02 1.40165444e-02 1.31296856e-02 1.21358005e-02
1.07166503e-02 1.01045695e-02 9.76055340e-03 9.16740926e-03
8.67465278e-03 8.78108857e-03 8.30918514e-03 8.05104488e-03
7.56152126e-03 7.31508852e-03 7.26347037e-03 6.65728354e-03
6.50769617e-03 6.28009879e-03 6.19160730e-03 5.64130272e-03
5.30195373e-03 5.07453702e-03 4.47372286e-03 4.32543895e-03
4.22006582e-03 3.97065729e-03 3.75292740e-03 3.64861290e-03
3.38915810e-03 3.27965962e-03 3.06633825e-03 2.99206786e-03
2.83586784e-03 2.74987243e-03 2.31066313e-03 2.26782347e-03
1.82206662e-03 1.74955624e-03 1.69305161e-03 1.66624597e-03
1.55346749e-03 1.51278404e-03 1.47296801e-03 1.33617458e-03
1.30517592e-03 1.24056353e-03 1.19823961e-03 1.14381059e-03
1.13027458e-03 1.11081803e-03 1.08359152e-03 1.03517496e-03
1.00164593e-03 9.50024604e-04 8.94981182e-04 8.74363843e-04
7.98497545e-04 7.51612220e-04 6.63964302e-04 6.21097647e-04
6.18098604e-04 5.72611404e-04 5.57509231e-04 5.47002382e-04
5.27195078e-04 5.11487997e-04 4.87787872e-04 4.74249071e-04
4.52367688e-04 4.24431102e-04 4.19119025e-04 3.72489906e-04
3.38125455e-04 3.34002144e-04 2.97951371e-04 2.84845901e-04
2.79038288e-04 2.77054476e-04 2.67962796e-04 2.54815126e-04
2.29230595e-04 1.99245436e-04 1.90381389e-04 1.84497913e-04
1.77415682e-04 1.68160613e-04 1.63992030e-04 1.58025552e-04
1.54226003e-04 1.46890640e-04 1.46097434e-04 1.40079891e-04
1.35736724e-04 1.22704035e-04 8.60212632e-05 9.07003473e-05
9.16166335e-05 9.60766569e-05 9.66039062e-05 9.90265101e-05
1.04252870e-04 1.14080847e-04 1.16752515e-04 8.32654023e-05
7.70526077e-05 7.36470021e-05 7.24998301e-05 6.68682699e-05
6.80209909e-05 6.14500422e-05 5.99843177e-05 5.49918004e-05
5.24646953e-05 5.13403847e-05 5.02336260e-05 4.89288500e-05
4.51104478e-05 4.29823770e-05 4.18869719e-05 4.14341560e-05
3.94822852e-05 3.80307291e-05 3.57776533e-05 3.43901592e-05
2.98089202e-05 2.72388357e-05 2.42608885e-05 2.30962279e-05
2.27807559e-05 2.14440814e-05 1.96208174e-05 1.91217362e-05
1.88276186e-05 1.66549051e-05 1.39779892e-05 1.46846459e-05
1.43753346e-05 1.21760519e-05 1.20295835e-05 7.36188586e-06
1.13426750e-05 8.34247956e-06 1.09258905e-05 8.93991857e-06
9.23630203e-06 1.02782989e-05 1.01021807e-05 9.64538291e-06
9.72678792e-06 7.20354827e-06 6.69282813e-06 6.49477814e-06
3.48065950e-06 3.65202836e-06 3.77558984e-06 4.11265577e-06
4.45482133e-06 4.65422046e-06 5.09342483e-06 5.31392220e-06
5.67034892e-06 5.91044557e-06 6.00244890e-06 2.78847699e-06
2.57492503e-06 2.66299627e-06 2.39210233e-06 2.06298821e-06
2.00824521e-06 1.76373602e-06 1.58273269e-06 1.32211395e-06
1.49813697e-06 1.42489429e-06 1.44003524e-06 1.10002716e-06
8.49881106e-07 9.01008863e-07 7.62521870e-07 6.57641103e-07
5.85636641e-07 5.33937361e-07 4.16077216e-07 3.33765858e-07
2.95575265e-07 2.54744632e-07 2.20144574e-07 1.86314527e-07
1.77370969e-07 1.54794345e-07 1.47331687e-07 1.39738552e-07
1.04110968e-07 1.00786519e-07 9.38635091e-08 9.10853311e-08
8.71546320e-08 7.48338889e-08 5.24576913e-08 5.66479200e-08
6.06817433e-08 4.57020635e-08 2.89942625e-08 2.60449438e-08
2.10987989e-08 2.17618743e-08 1.75542294e-08 1.34637029e-08
1.27167437e-08 1.23258200e-08 1.04987515e-08 9.86367951e-09
8.49422307e-09 9.33428172e-09 7.42189900e-09 6.46870737e-09
6.84633806e-09 5.76455970e-09 5.01137910e-09 3.48686487e-09
2.91267184e-09 2.77880636e-09 1.73093440e-09 1.42391203e-09
9.24976964e-10 1.11815958e-09 1.16455041e-09 6.95075385e-10
6.13281879e-10 5.27555841e-10 1.80003616e-10 1.97062770e-10
2.61933230e-10 -4.32778209e-15 5.13857900e-16 -1.98252726e-16
-6.89465294e-17 -8.13691657e-19 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00]