一、主成分分析(Principal Component Analysis,PCA)简介
在数据挖掘中经常会遇到多个变量的问题,而且在多数情况下,多个变量之间常常存在一定的相关性。例如,网站的“浏览量”和“访客数”往往具有较强的相关关系,而电商应用中的“下单数”和“成交数”也具有较强的相关关系。这里的相关关系可以直观理解为当浏览量较高(或较低)时,应该很大程度上认为访客数也较高(或较低)。这个简单的例子中只有两个变量,当变量个数较多且变量之间存在复杂关系时,会显著增加分析问题的复杂性。主成分分析方法可以将多个变量综合为少数几个代表性变量,使这些变量既能够代表原始变量的绝大多数信息又互不相关,这种方法有助于对问题的分析和建模。
Madlib提供了两个主成分分析函数:训练函数与投影函数。训练函数以原始数据为输入,输出主成分。投影函数将原始数据投影到主成分上,实现线性无关降维,输出降维后的数据矩阵。
1. PCA的基本思想
主成分分析采取一种数学降维的方法,其所要做的就是设法将原来众多具有一定相关性的变量,重新组合为一组新的相互无关的综合变量来代替原来变量。通常,数学上的处理方法就是将原来的变量做正交变换,作为新的综合变量,转换后的变量叫主成分。变换的定义方法是用F1(选取的第一个线性组合,即第一个综合指标)的方差来表达,即Var(F1)越大,表示F1包含的信息越多。因此在所有的线性组合中选取的F1应该是方差最大的,故称F1为第一主成分。如果第一主成分不足以代表原来P个指标的信息,再考虑选取F2即选第二个线性组合,为了有效地反映原来信息,F1已有的信息就不需要再出现在F2中,用数学语言表达就是要求Cov(F1, F2)=0,称F2为第二主成分,依此类推可以构造出第三、第四,……,第P个主成分。Cov表示统计学中的协方差。
2. PCA的计算步骤
下面简单介绍一下PCA的典型计算步骤。
(1)对原始数据进行标准化处理
(2)计算样本相关系数矩阵
(3)计算相关矩阵的特征值和相应的特征向量
(4)选择重要的主成分,并写出主成分表达式
(5)计算主成分得分
(6)依据主成分得分数据,进一步对问题进行后续的分析和建模
3. 主成分投影
主成分投影是指在主成分分析的基础上,通过正交变换将原有的指标转换为彼此正交的综合指标,消除了指标间的信息重叠问题,并利用各主成分设计一个理想决策变量,以各被评价对象相应的决策向量在该理想决策向量方向上的投影作为一维的综合评价指标。主成分投影法的基本步骤为:
(1)确定评价矩阵。
(2)指标的无量纲化。
(3)指标权重的确定。
(4)指标的正交变换。
(5)理想评价向量的构造和投影值计算。
(6)比较分析及评价标准。
二、Madlib中的PCA训练函数
1. 技术背景
Madlib中PCA的实现是使用一种分布式的SVD(奇异值分解)找出主成分,而不是直接计算方差矩阵的特征向量。设为数据矩阵,为的列平均值向量。PCA首先将原始矩阵标准化为矩阵:
其中是所有的向量。
Madlib PCA对矩阵进行SVD分解:
其中是对角矩阵,特征值为的条目,主成分是的行。Bessel's correction用N-1代替N计算协方差。
这种实现的重要前提是假设用户只使用具有非零特征值的主成分,因为SVD计算用的是Lanczos算法,它并不保证含有零特征值的奇异向量的正确性。通常这不成问题,除非用户希望使用全部特征值的集合作为主成分。
2. 训练函数
(1)语法
稠密矩阵和稀疏矩阵的训练函数有所不同。稠密矩阵训练函数为:
pca_train( source_table, out_table, row_id, components_param, grouping_cols, lanczos_iter, use_correlation, result_summary_table )
稀疏矩阵训练函数为:
pca_sparse_train( source_table, out_table, row_id, col_id, -- Sparse matrices only val_id, -- Sparse matrices only row_dim, -- Sparse matrices only col_dim, -- Sparse matrices only components_param, grouping_cols, lanczos_iter, use_correlation, result_summary_table )
(2)参数
source_table:TEXT类型,存储PCA训练数据的输入表名。输入的数据矩阵应该具有N行M列,N为数据点的数量,M为每个数据点的特征数。
稠密输入表可以使用两种标准的Madlib稠密矩阵格式:
{TABLE|VIEW} source_table ( row_id INTEGER, row_vec FLOAT8[], )
或
{TABLE|VIEW} source_table ( row_id INTEGER, col1 FLOAT8, col2 FLOAT8, ... )
注意row_id作为入参是输入矩阵的行标识,必须是从1开始且连续的整数。PCA的稀疏矩阵输入表的格式为:
{TABLE|VIEW} source_table ( ... row_id INTEGER, col_id INTEGER, val_id FLOAT8, ... )
row_id和col_id列指示矩阵下标,是正整数,val_id列定义非0的矩阵元素值。
out_table:TEXT类型,输出表的名称。有三种可能的输出表。
主输出表(out_table)包含特征值最高的k个主成分的特征向量,k值直接由用户参数指定,或者根据方差的比例计算得出。主输出表包含以下四列:
row_id:特征值倒序排名。
principal_components:包含主成分元素的向量(特征向量)。
std_dev:每个主成分的标准差。
proportion:主成分方差的比例。
out_table_mean表包含列的均值,只有一列:
column_mean:包含输入矩阵的列的均值。
可选的result_summary_table表包含PCA的性能信息。
row_id:TEXT类型,源输入表中表示行ID的列名。该列应该为整型,值域为1到N,对于稠密矩阵格式,该列应该包含从1到N的连续整数。
col_id:TEXT类型,稀疏矩阵中表示列ID的列名。列应为整型,值域为1到M。该参数只用于稀疏矩阵。
val_id:TEXT类型,稀疏矩阵中表示非零元素值的列名。该参数只用于稀疏矩阵。
row_dim:INTEGER类型,矩阵的实际行数,指的是当矩阵转换为稠密矩阵时所具有的行数。该参数只用于稀疏矩阵。
col_dim:INTEGER类型,矩阵的实际列数,指的是当矩阵转换为稠密矩阵时所具有的列数。该参数只用于稀疏矩阵。row_dim和col_dim实际上可以从稀疏矩阵推断出,当前是为了向后兼容而存在,将来会被移除。这两个值大于矩阵的实际值时会补零。
components_param:INTEGER或FLOAT类型,该参数控制如何从输入数据确定主成分的数量。如果为INTEGER类型,代表需要计算的主成分的个数。如果为FLOAT类型,算法将返回足够的主成分向量,使得累积特征值大于此参数(方差比例)。‘components_param’的值域为正整数或(0.0,1.0]。这里要注意整型和浮点数的区别,如果components_param指定为1,则返回一个主成分,而指定为1.0时,返回所有的主成分,因为此时方差比例为100%。还要注意一点,主成分数量是全局的。在分组时(由grouping_cols参数指定)可能选择方差比例更好,因为这可以使不同分组有不同的主成分数量。
grouping_cols(可选):TEXT类型,缺省值为NULL。指定逗号分隔的列名,使用此参数的所有列分组,对每个分组独立计算PCA。稠密矩阵的各个分组大小可能不同,而稀疏矩阵的每个分组大小都一样,因为稀疏矩阵的‘row_dim’和‘col_dim’是跨所有组的全局参数。
lanczos_iter(可选):INTEGER类型,缺省值为k+40与最小矩阵维度的较小者,k是主成分数量。此参数定义计算SVD时的Lanczos迭代次数,迭代次数越大精度越高,同时计算越花时间。迭代次数不能小于k值,也不能大于最小矩阵维度。如果此参数设置为0,则使用缺省值。如果‘lanczos_iter’和‘components_param’参数同时设置,在确定主成分数量时,优先考虑‘lanczos_iter’。
use_correlation(可选):BOOLEAN类型,缺省值为FALSE。指定在计算主成分时,是否使用相关矩阵代替协方差矩阵。当前该参数仅用于向后兼容,因此必须设置为false。
result_summary_table(可选):TEXT类型,缺省值为NULL。指定概要表的名称,NULL时不生成概要表。概要表具有下面的列:
rows_used:INTEGER类型,输入数据点的个数。
exec_time (ms):FLOAT8类型,函数执行的毫秒数。
iter:INTEGER类型,SVD计算时的迭代次数。
recon_error:FLOAT8类型,SVD近似值的绝对误差。
relative_recon_error:FLOAT8类型,SVD近似值的相对误差。
use_correlation:BOOLEAN类型,表示使用的是相关矩阵。
3. 查看联机帮助
select madlib.pca_train('usage'); select madlib.pca_sparse_train('usage');
三、Madlib中的PCA投影函数
1. 技术背景
给定包含主成分的输入数据矩阵,则对应的降维后的低维度矩阵为,其计算公式为:
其中是的列平均值,是所有的向量。这步计算的结果近似于原始数据,保留了绝大部分的原始信息。
残余表用于估量降维后的矩阵与原始输入数据的近似程度,计算公式为:
如果残余矩阵的元素接近于零,则表示降维后的信息丢失很少,基本相当于原始数据。
残差范数表示为:
其中是Frobenius范数。相对残差范数为:
2. 投影函数
(1)语法
稠密矩阵和稀疏矩阵的投影函数有所不同。稠密矩阵投影函数为:
madlib.pca_project( source_table, pc_table, out_table, row_id, residual_table, result_summary_table )
稀疏矩阵的投影函数为:
madlib.pca_sparse_project( source_table, pc_table, out_table, row_id, col_id, -- Sparse matrices only val_id, -- Sparse matrices only row_dim, -- Sparse matrices only col_dim, -- Sparse matrices only residual_table, result_summary_table )
(2)参数
source_table:TEXT类型,等同于PCA训练函数,指定源表名称。输入数据矩阵应该有N行M列,N为数据点个数,M为每个数据点的特征数。与PCA训练函数类似,pca_project函数的输入表格式,应该为Madlib两种标准稠密矩阵格式之一,而pca_sparse_project函数的输入表应该为Madlib的标准稀疏矩阵格式。
pc_table:TEXT类型,主成分表名,使用中通常为PCA训练函数的主输出表。
out_table:TEXT类型,输入数据降维后的输出表名称。out_table是一个投影到主成分上的稠密矩阵,具有以下两列:
row_id:输出矩阵的行ID。
row_vec:矩阵行中所含的向量。
row_id:同PCA训练函数。
col_id:同PCA训练函数。
val_id:同PCA训练函数。
row_dim:同PCA训练函数。
col_dim:同PCA训练函数。
residual_table(可选):TEXT类型,缺省值为NULL,残余表的名称。residual_table表现为一个稠密矩阵,具有以下两列:
row_id:输出矩阵的行ID。
row_vec:包含残余矩阵行元素的向量。
result_summary_table(可选):TEXT类型,可选值为NULL,概要表的名称。result_summary_table中含有PCA投影函数的性能信息,具有以下三列:
exec_time:函数执行所用的时间(毫秒)。
residual_norm:绝对误差。
relative_residual_norm:相对误差。
3. 查看联机帮助
select madlib.pca_project('usage'); select madlib.pca_sparse_project('usage');
四、PCA应用示例:企业综合实力排序
为了系统地分析某IT类企业的经济效益,选择了8个不同的利润指标,对15家企业进行了调研,并得到如表1所示的数据。现在需要根据根据这些数据对15家企业进行综合示例排序。
企业编号 |
净利润率(%) |
固定资产利润率(%) |
总产值利润率(%) |
销售收入利润率(%) |
产品成本利润率(%) |
物耗利润率(%) |
人均利润(千元/人) |
流动资产利润率(%) |
1 |
40.4 |
24.7 |
7.2 |
6.1 |
8.3 |
8.7 |
2.442 |
20 |
2 |
25 |
12.7 |
11.2 |
11 |
12.9 |
20.2 |
3.542 |
9.1 |
3 |
13.2 |
3.3 |
3.9 |
4.3 |
4.4 |
5.5 |
0.578 |
3.6 |
4 |
22.3 |
6.7 |
5.6 |
3.7 |
6 |
7.4 |
0.176 |
7.3 |
5 |
34.3 |
11.8 |
7.1 |
7.1 |
8 |
8.9 |
1.726 |
27.5 |
6 |
35.6 |
12.5 |
16.4 |
16.7 |
22.8 |
29.3 |
3.017 |
26.6 |
7 |
22 |
7.8 |
9.9 |
10.2 |
12.6 |
17.6 |
0.847 |
10.6 |
8 |
48.4 |
13.4 |
10.9 |
9.9 |
10.9 |
13.9 |
1.772 |
17.8 |
9 |
40.6 |
19.1 |
19.8 |
19 |
29.7 |
39.6 |
2.449 |
35.8 |
10 |
24.8 |
8 |
9.8 |
8.9 |
11.9 |
16.2 |
0.789 |
13.7 |
11 |
12.5 |
9.7 |
4.2 |
4.2 |
4.6 |
6.5 |
0.874 |
3.9 |
12 |
1.8 |
0.6 |
0.7 |
0.7 |
0.8 |
1.1 |
0.056 |
1 |
13 |
32.3 |
13.9 |
9.4 |
8.3 |
9.8 |
13.3 |
2.126 |
17.1 |
14 |
38.5 |
9.1 |
11.3 |
9.5 |
12.2 |
16.4 |
1.327 |
11.6 |
15 |
26.2 |
10.1 |
5.6 |
15.6 |
7.7 |
30.1 |
0.126 |
25.9 |
由于本问题中涉及8个指标,这些指标间的关联关系并不明确,而且各指标数值的数量级也有差异,为此这里将首先借助PCA方法对指标体系进行降维处理,然后根据PCA打分结果实现对企业的综合实力排序。
1. 创建稠密矩阵表并添加数据
drop table if exists mat; create table mat (id integer, row_vec double precision[] ); insert into mat values (1, '{40.4, 24.7, 7.2, 6.1, 8.3, 8.7, 2.442, 20}'), (2, '{ 25, 12.7, 11.2, 11, 12.9, 20.2, 3.542, 9.1}'), (3, '{13.2, 3.3, 3.9, 4.3, 4.4, 5.5, 0.578, 3.6}'), (4, '{22.3, 6.7, 5.6, 3.7, 6, 7.4, 0.176, 7.3}'), (5, '{34.3, 11.8, 7.1, 7.1, 8, 8.9, 1.726, 27.5}'), (6, '{35.6, 12.5, 16.4, 16.7, 22.8, 29.3, 3.017, 26.6}'), (7, '{ 22, 7.8, 9.9, 10.2, 12.6, 17.6, 0.847, 10.6}'), (8, '{48.4, 13.4, 10.9, 9.9, 10.9, 13.9, 1.772, 17.8}'), (9, '{40.6, 19.1, 19.8, 19, 29.7, 39.6, 2.449, 35.8}'), (10, '{24.8, 8, 9.8, 8.9, 11.9, 16.2, 0.789, 13.7}'), (11, '{12.5, 9.7, 4.2, 4.2, 4.6, 6.5, 0.874, 3.9}'), (12, '{ 1.8, 0.6, 0.7, 0.7, 0.8, 1.1, 0.056, 1}'), (13, '{32.3, 13.9, 9.4, 8.3, 9.8, 13.3, 2.126, 17.1}'), (14, '{38.5, 9.1, 11.3, 9.5, 12.2, 16.4, 1.327, 11.6}'), (15, '{26.2, 10.1, 5.6, 15.6, 7.7, 30.1, 0.126, 25.9}');
2. 调用PCA训练函数生成特征向量矩阵
drop table if exists result_table, result_table_mean; select madlib.pca_train('mat', -- source table 'result_table', -- output table 'id', -- row id of source table 3 -- number of principal components );
3. 查看输出表
select * from result_table order by row_id;
结果如下:
row_id | principal_components | std_dev | proportion --------+------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------+-------------------- 1 | {0.54951113056651,0.22059946589484,0.221798212432593,0.234122486371152,0.323859692705692,0.460000381165952,0.0350228413699574,0.477130544733463} | 19.4865050268107 | 0.743985609635922 2 | {-0.679390383883709,-0.258058109137903,0.0922351692999137,0.224015136531732,0.25512757908769,0.589575496706845,-0.0194312272521382,0.00881420572763583} | 9.06653318232267 | 0.161056826858628 3 | {-0.293070645355269,0.116853642654378,-0.357654514354919,-0.0363160573731402,-0.370902632819521,-0.0699941930259179,-0.0562050276014156,0.790943904553534} | 5.06251973016091 | 0.0502146089885736 (3 rows)
可以看到,主成分数量为3时,累积方差比例为95.5,即反映了95.5%的原始信息,而维度已经从8个降低为3个。
4. 调用PCA投影函数生成降维后的数据表
drop table if exists residual_table, result_summary_table, out_table; select madlib.pca_project( 'mat', 'result_table', 'out_table', 'id', 'residual_table', 'result_summary_table' );
5. 查看投影函数输出表
dm=# select * from out_table order by row_id; row_id | row_vec --------+--------------------------------------------------------- 1 | {7.08021173666004,-17.6113408380368,3.62504928877283} 2 | {-0.377499074086432,5.25083911315586,-6.06667264391957} 3 | {-24.3659516926199,2.69294552046529,-0.854680487274521} 4 | {-15.235298685282,-2.7756923532236,-1.48789032627869} 5 | {4.64264829479036,-9.80192214158058,9.97441166441563} 6 | {23.6146598612176,7.91277187194797,-1.70125446716029} 7 | {-4.25445515316499,6.71053107113929,-3.63489574437095} 8 | {12.8547303317577,-15.2151276724561,-4.53202062778529} 9 | {40.4531114732088,11.566606363421,0.333514089765778} 10 | {-2.3918721025776,3.48063922820141,-1.53633678788746} 11 | {-22.6173674430242,2.15970955881415,0.0711392924992467} 12 | {-37.2273102800874,6.50778045364591,3.06216108712083} 13 | {2.45676837959725,-5.55018275237518,0.715863146049784} 14 | {5.05828673790116,-5.6726215744102,-7.79762716115412} 15 | {10.3093376158273,10.3450641508798,9.82923967771456} (15 rows) dm=# select * from result_summary_table; exec_time | residual_norm | relative_residual_norm ---------------+---------------+------------------------ 7834.64002609 | 17.8804330669 | 0.0999460602087 (1 row) dm=# select * from residual_table order by row_id; row_id | row_vec --------+---------------------------------------------------------------------------------------------------------------------------------------------------------- 1 | {-2.25323523421767,7.27642620892876,-0.31614472682197,-0.494115688859853,1.00468388047691,0.433380657606633,0.599100230104459,-1.52349927341588} 2 | {-0.863154123125062,3.95387717098127,-0.237022939622535,0.678462615857513,-1.40752199307202,1.2065851169394,1.85980716819093,-1.40110122200098} 3 | {0.308441190889249,-1.42340844662228,-0.116406757628345,0.356984675694431,0.447101713452669,-0.585836964458252,-0.0208119097031971,0.444674616668891} 4 | {0.490130533527738,-1.37485909630399,-0.163638890332356,-1.17864453350125,0.250392381501536,0.293913050865083,-0.884445243345333,0.337196335237827} 5 | {0.152688703669817,-3.81251089756285,1.67507754859814,-0.442271462365288,1.85670956345357,-2.40516264125975,0.477083304830599,2.04871340760574} 6 | {-0.3592450632185,-1.36196195708871,0.957346795421167,0.323580259078128,1.66239742146767,-1.99367354425669,0.791616661159451,1.17524319516153} 7 | {-0.0283404999568164,0.00165496908974205,0.057980039554014,0.54746466878389,0.0776125903500138,-0.300401958384908,-0.5343691201399,0.0124478027687696} 8 | {1.81096896189017,-3.72588393721226,-1.03535063544512,1.12091902152632,-1.90226870931166,0.993403809233695,-0.685046795881378,-0.0480344625583826} 9 | {-1.53345069357698,2.22861611294688,1.01334044488596,-2.06329935977889,2.93160872351416,-1.45115700607537,-0.180751047312987,0.699510168883641} 10 | {0.168817950757148,-1.28795389715317,0.593331153806535,-0.388851856449367,0.376792544638479,-0.506038843322491,-0.602413269186595,0.592379053435519} 11 | {-1.44337010134268,4.34506352414871,0.176067114438398,0.000676834542009175,0.560237949521619,-0.011001520447941,0.255621998627472,-0.817199798912856} 12 | {-0.284425653421206,-0.759447727683328,0.585233711708927,-0.944218598761936,1.49187460452629,-1.04458414728561,0.201902525223109,0.849594937231783} 13 | {-0.470963886374596,0.948783991627835,0.756380230030218,-0.0191957806666807,-0.154128037749362,-0.154423041481078,0.515878569618902,-0.0228197077983638} 14 | {1.72123496250158,-3.46187354552954,-0.954226967261204,0.289982019939877,-1.72309342301114,1.22516956751968,-0.855114089441233,-0.0293111133050323} 15 | {2.58390295180211,-1.54652247225864,-2.99196612118835,2.21252718509424,-5.47239920950344,4.29982746453179,-0.938058982777885,-2.31779393895638} (15 rows)
out_table为降维后,投影到主成分的数据表。residual_table中的数据表示与每个原始数据项对应的误差,越接近零说明误差越小。result_summary_table表中包含函数执行概要信息。
6. 按主成分总得分降序排列得到综合实力排序
select row_id, row_vec, madlib.array_sum(row_vec) r from out_table order by r desc;
结果如下:
row_id | row_vec | r --------+----------------------------------------------------------+------------------- 9 | {40.4531114732088,11.566606363421,-0.333514089765778} | 51.686203746864 6 | {23.6146598612176,7.91277187194796,1.70125446716029} | 33.2286862003258 2 | {-0.377499074086431,5.25083911315585,6.06667264391957} | 10.940012682989 15 | {10.3093376158273,10.3450641508798,-9.82923967771456} | 10.8251620889925 14 | {5.05828673790117,-5.6726215744102,7.79762716115411} | 7.18329232464508 7 | {-4.254455153165,6.71053107113929,3.63489574437095} | 6.09097166234524 10 | {-2.3918721025776,3.48063922820141,1.53633678788746} | 2.62510391351128 8 | {12.8547303317577,-15.2151276724561,4.53202062778528} | 2.17162328708682 13 | {2.45676837959725,-5.55018275237518,-0.715863146049783} | -3.80927751882771 1 | {7.08021173666005,-17.6113408380368,-3.62504928877282} | -14.1561783901495 5 | {4.64264829479035,-9.80192214158058,-9.97441166441563} | -15.1336855112059 4 | {-15.235298685282,-2.7756923532236,1.48789032627869} | -16.5231007122269 11 | {-22.6173674430242,2.15970955881415,-0.0711392924992431} | -20.5287971767093 3 | {-24.3659516926199,2.69294552046528,0.85468048727452} | -20.8183256848801 12 | {-37.2273102800874,6.50778045364591,-3.06216108712083} | -33.7816909135623 (15 rows)
从该结果可知,第9家企业的综合实力最强,第12家企业的综合实力最弱。row_vec中的三列为个主成分的得分。以上应用示例比较简单,真实场景中,PCA方法还要根据实际问题和需求灵活使用。
参考文献:
- PCA数学原理:说明PCA的数学原理和相关性的例子。
- 主成分分析法的原理应用及计算步骤:详述PCA的数学计算步骤。
- 《大数据挖掘——系统方法与实力分析》:讲述主成分分析的基本原理及其案例。
- Principal Component Analysis:Madlib官方文档对PCA训练函数的说明。
- Principal Component Projection:Madlib官方文档对PCA投影函数的说明。