原创

MADlib——基于SQL的数据挖掘解决方案(4)——数据类型之矩阵

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://wxy0327.blog.csdn.net/article/details/78904700

        矩阵可以用来表示数据集,描述数据集上的变换,是MADlib中数据的基本格式,通常使用二维数组数据类型存储。MADlib中的向量是一维数组,可看作是矩阵的一种特殊形式。MADlib的矩阵运算模块(matrix_ops)实现SQL中的矩阵操作。本篇介绍矩阵的概念,说明MADlib矩阵运算相关函数,并举出一些简单的函数调用示例。

 

一、矩阵定义

        矩阵(matrix)是把数集合汇聚成行和列的一种表表示。术语通常用来说明矩阵具有m行和n列。例如,下面所示的矩阵A是。如果m=n,则我们称该矩阵为方阵(square matrix)。矩阵A的转置记作,它通过交换A的行和列得到。

       

        矩阵的元素用带小标的小写字母表示。例如,对于矩阵A,是其第 行第 列的元素。行自上而下编号,列自左向右编号,编号从1开始。例如,是矩阵A的第2行第1列的元素。

        矩阵的每一行或列定义一个向量。对于矩阵A,其第 个行向量(row vector)可以用表示,而第 个列向量(column vector)用表示。使用前面的例子,,而。注意:行向量和列向量都是矩阵,必须加以区分,即元素个数相同并且值相同的行向量和列向量代表不同的矩阵。

 

二、MADlib中的矩阵表示

        MADlib支持稠密和稀疏两种矩阵表示形式,所有矩阵运算都以任一种表示形式工作。

1. 稠密

        矩阵被表示为一维数组的行集合,例如3x10的矩阵如下表:

row_id |         row_vec   
-------+-------------------------   
  1    | {9,6,5,8,5,6,6,3,10,8}   
  2    | {8,2,2,6,6,10,2,1,9,9}   
  3    | {3,9,9,9,8,6,3,9,5,6}

        row_id列表示每一行的行号,是从1到N没有重复值的连续整型序列,N为矩阵的行数。row_vec列对应构成矩阵每行的一维数组(行向量)。

2. 稀疏

        使用行列下标指示矩阵中每一个非零项,例如:

row_id | col_id | value   
-------+--------+-------   
     1 |      1 |     9   
     1 |      5 |     6   
     1 |      6 |     6   
     2 |      1 |     8   
     3 |      1 |     3   
     3 |      2 |     9   
     4 |      7 |     0 

        常用这种方式表示包含多个零元素的稀疏矩阵。上面的例子只用6行表示一个4x7的矩阵中的非零元素。矩阵的行列元素个数分别由row_id和col_id的最大值指定。注意最后一行,即使value为0也要包含此行,它指出了矩阵的维度,而且指示矩阵的第4行与第7列的元素值都是0。

        对于稀疏矩阵表,row_id和col_id列逻辑类似于关系数据库的联合主键,要求非空且唯一。value列应该是标量(非数组)数据类型。上面矩阵对应的稠密表示如下:

row_id |         row_vec 
-------+------------------------- 
  1    | {9,0,0,0,6,6,0} 
  2    | {8,0,0,0,0,0,0} 
  3    | {3,9,0,0,0,0,0} 
  4    | {0,0,0,0,0,0,0}

三、MADlib中的矩阵运算函数

        与数组操作相同,矩阵运算函数支持的元素数据类型也包括SMALLINT、INTEGER、BIGINT、FLOAT8和NUMERIC(内部被转化为FLOAT8,可能丢失精度)。

1. 矩阵操作函数分类

        MADlib的矩阵操作函数可分为表示、计算、提取、归约、创建、转换六类。下面列出每一类中所包含的函数名称及其参数。

 (1)表示函数

-- 转为稀疏矩阵

matrix_sparsify( matrix_in, in_args,matrix_out, out_args)

-- 转为稠密矩阵

matrix_densify( matrix_in, in_args,matrix_out, out_args)

-- 获取矩阵的维度

matrix_ndims( matrix_in, in_args )

 

(2)计算函数

-- 矩阵转置

matrix_trans( matrix_in, in_args,matrix_out, out_args)

-- 矩阵相加

matrix_add( matrix_a, a_args, matrix_b,b_args, matrix_out, out_args)

-- 矩阵相减

matrix_sub( matrix_a, a_args, matrix_b,b_args, matrix_out, out_args)

-- 矩阵乘法

matrix_mult( matrix_a, a_args, matrix_b,b_args, matrix_out, out_args)

-- 数组元素相乘

matrix_elem_mult( matrix_a, a_args,matrix_b, b_args, matrix_out, out_args)

-- 标量乘矩阵

matrix_scalar_mult( matrix_in, in_args,scalar, matrix_out, out_args)

-- 向量乘矩阵

matrix_vec_mult( matrix_in, in_args,vector)

 

(3)提取函数

-- 从行下标提取行

matrix_extract_row( matrix_in, in_args,index)

-- 从列下标提取列

matrix_extract_col( matrix_in, in_args,index)

-- 提取主对角线元素

matrix_extract_diag( matrix_in, in_args)

 

(4)归约函数(指定维度的聚合)

-- 获取指定维度的最大值。如果fetch_index = True,返回对应的下标。

matrix_max( matrix_in, in_args, dim,matrix_out, fetch_index)

-- 获取指定维度的最小值。如果fetch_index = True,返回对应的下标。

matrix_min( matrix_in, in_args, dim,matrix_out, fetch_index)

-- 获取指定维度的和

matrix_sum( matrix_in, in_args, dim)

-- 获取指定维度的均值

matrix_mean( matrix_in, in_args, dim)

-- 获取矩阵范数

matrix_norm( matrix_in, in_args, norm_type)

 

(5)创建函数

-- 创建一个指定行列维度的矩阵,用1初始化元素值。

matrix_ones( row_dim, col_dim, matrix_out,out_args)

-- 创建一个指定行列维度的矩阵,用0初始化元素值。

matrix_zeros( row_dim, col_dim, matrix_out,out_args)

-- 创建单位矩阵

matrix_identity( dim, matrix_out, out_args)

-- 用给定对角元素初始化矩阵

matrix_diag( diag_elements, matrix_out,out_args)

 

(6)转换函数

-- 矩阵求逆

matrix_inverse( matrix_in, in_args,matrix_out, out_args)

-- 广义逆矩阵

matrix_pinv( matrix_in, in_args,matrix_out, out_args)

-- 矩阵特征提取

matrix_eigen( matrix_in, in_args,matrix_out, out_args)

-- Cholesky分解

matrix_cholesky( matrix_in, in_args,matrix_out_prefix, out_args)

-- QR分解

matrix_qr( matrix_in, in_args,matrix_out_prefix, out_args)

-- LU分解

matrix_lu( matrix_in, in_args, matrix_out_prefix,out_args)

-- 求矩阵的核范数

matrix_nuclear_norm( matrix_in, in_args)

-- 求矩阵的秩

matrix_rank( matrix_in, in_args)

 

        注意:矩阵转换函数仅基于内存操作实现。单一节点的矩阵数据被用于分解计算。这种操作只适合小型矩阵,因为计算不是分布到个多个节点执行的。

 2. 矩阵操作函数示例

        先执行下面的脚本创建两个稠密表示的矩阵测试表并添加数据。mat_a矩阵4行4列,mat_b矩阵5行4列。

drop table if exists mat_a;   
create table mat_a (row_id integer, row_vecinteger[]);   
insert into mat_a (row_id, row_vec)values  
(1, '{9,6,5,8}'), (2, '{8,2,2,6}'), (3,'{3,9,9,9}'), (4, '{6,4,2,2}');   
   
drop table if exists mat_b;   
create table mat_b (row_id integer, vectorinteger[]);  
insert into mat_b (row_id, vector)values  
(1, '{9,10,2,4}'), (2, '{5,3,5,2}'), (3,'{0,1,2,3}'), (4, '{2,9,0,4}'), (5,'{3,8,7,7}');

(1)由稠密矩阵表生成稀疏表示的表

drop table if exists mat_a_sparse; 
select madlib.matrix_sparsify('mat_a','row=row_id, val=row_vec', 
                              'mat_a_sparse','col=col_id, val=val'); 

drop table if exists mat_b_sparse; 
select madlib.matrix_sparsify('mat_b','row=row_id, val=vector', 
                              'mat_b_sparse','col=col_id, val=val'); 

        madlib.matrix_sparsify函数将稠密表示矩阵表转为稀疏表示的矩阵表,四个参数分别指定输入表名、输入表参数(代表行ID的列名、存储矩阵元素值的列名等)、输出表名、输出表参数(代表列ID的列名、存储矩阵元素值的列名等)。

        上面的例子将稠密矩阵转为稀疏表示,并新建表存储转换结果。源表的两列类型分别是整型和整型数组,输出表包含三列,行ID列名与源表相同,列ID列和值列由参数指定。由于mat_a表的矩阵中不存在0值元素,生成的稀疏矩阵表共有16条记录,而mat_b中有两个0值,因此稀疏表中只有18条记录。

dm=# select * from mat_a_sparse order byrow_id, col_id;
 row_id | col_id | val
--------+--------+-----
      1 |      1 |   9
      1 |      2 |   6
…
      4 |      3 |   2
      4 |      4 |   2
(16 rows)

dm=# select * from mat_b_sparse;
 row_id | col_id | val
--------+--------+-----
      1 |      1 |   9
      1 |      2 |  10
…
      4 |      2 |   9
      4 |      4 |   4
(18 rows)

(2)矩阵转置

        matrix_trans函数的第一个参数是源表名,第二个参数指定行、列或值的字段名,第三个参数为输出表名。

-- 稠密格式
drop table if exists mat_a_r; 
select madlib.matrix_trans('mat_a','row=row_id, val=row_vec','mat_a_r'); 
select * from mat_a_r order by row_id;

        结果:

 row_id | row_vec 
--------+-----------
      1 | {9,8,3,6}
      2 | {6,2,9,4}
      3 | {5,2,9,2}
      4 | {8,6,9,2}
(4 rows)

-- 稀疏格式
drop table if exists mat_b_sparse_r; 
select madlib.matrix_trans('mat_b_sparse', 'row=row_id, col=col_id, val=val','mat_b_sparse_r'); 
select * from mat_b_sparse_r order byrow_id, col_id; 

       结果:

 col_id | row_id | val
--------+--------+-----
      1 |      1 |   9
      2 |      1 |   5
…
      4 |      4 |   4
      5 |      4 |   7
(18 rows)

        源矩阵5行4列,转置后的矩阵为4行5列。

 (3)提取矩阵的主对角线

select madlib.matrix_extract_diag('mat_b', 'row=row_id, val=vector'),
       madlib.matrix_extract_diag
       ('mat_b_sparse_r', 'row=row_id, col=col_id,val=val');

        结果:

 matrix_extract_diag | matrix_extract_diag
---------------------+---------------------
 {9,3,2,4}           | {9,3,2,4}
(1 row)

        matrix_extract_diag函数的返回值是由对角线元素组成的数组。可以看到,矩阵和其对应的转置矩阵具有相同的主对角线。也就是说,矩阵转置实际上是沿着主对角线的元素对折操作。

 (4)提取指定下标的行或列

select madlib.matrix_extract_row('mat_a','row=row_id, val=row_vec', 2) as row, 
       madlib.matrix_extract_col
       ('mat_b_sparse','row=row_id, col=col_id, val=val', 3) as col;

        结果返回两个向量,即mat_a的第2行,mat_b_sparse的第3列:

    row    |     col    
-----------+-------------
 {8,2,2,6} | {2,5,2,0,7}
(1 row)

(5)获取指定维度的最大最小值及其对应的下标

drop table if exists mat_max_r,mat_min_r; 
select madlib.matrix_max
       ('mat_a','row=row_id, val=row_vec', 2, 'mat_max_r', true), 
       madlib.matrix_min
       ('mat_b_sparse','row=row_id, col=col_id', 1, 'mat_min_r', true); 
select * from mat_max_r, mat_min_r;

        结果:

   index   |    max   |   index   |   min   
-----------+-----------+-----------+-----------
 {1,1,2,1} | {9,8,9,6} | {3,3,4,2} | {0,1,0,2}
(1 row)

        matrix_max和matrix_min函数分别返回指定维度的最大值和最小值,其中维度参数的取值只能是1或2,分别代表行和列。返回值为数组类型,如果最后一个参数为‘true’,表示结果表中包含最大最小值对应的下标数组列。

(6)按指定维度求和

select madlib.matrix_sum('mat_b_sparse', 'row=row_id, col=col_id,val=val', 1),
     madlib.matrix_sum('mat_b_sparse', 'row=row_id, col=col_id,val=val', 2); 

        结果:

  matrix_sum   |   matrix_sum    
---------------+-----------------
 {19,31,16,20} | {25,15,6,15,25}
(1 row)

        matrix_sum函数按指定维度求和,第三个参数的值只能是1或2,分别表示按行或列求和。函数返回的结果是一个向量。

(7)按指定维度求均值

select madlib.matrix_mean('mat_b_sparse', 'row=row_id, col=col_id,val=val', 1),
       madlib.matrix_mean('mat_b_sparse', 'row=row_id, col=col_id,val=val', 2); 
        结果:
   matrix_mean   |        matrix_mean        
-----------------+---------------------------
 {3.8,6.2,3.2,4} | {6.25,3.75,1.5,3.75,6.25}
(1 row)
        matrix_mean函数按指定维度求均值,第三个参数的值只能是1或2,分别表示行或列。函数返回的结果是一个向量。

(8)创建对角矩阵

drop table if exists mat_r; 
select madlib.matrix_diag(array[9,6,3,10], 
                          'mat_r', 'row=row_id,col=col_id, val=val'); 
select * from mat_r order by row_id;

        结果:

 row_id | col_id | val
--------+--------+-----
      1 |      1 |   9
      2 |      2 |   6
      3 |      3 |   3
      4 |      4 |  10
(4 rows)

        madlib.matrix_diag函数输出的是一个稀疏表示的对角矩阵表,如果不指定“col=col_id”,输出表中代表列的列名为col。

 (9)创建单位矩阵

drop table if exists mat_r; 
select madlib.matrix_identity(4,'mat_r'); 
select * from mat_r; 

        结果:

 row | col | val
-----+-----+-----
    4|   4 |  1
    2|   2 |  1
    1|   1 |  1
    3|   3 |  1
(4 rows)

        matrix_identity函数创建一个稀疏表示的单位矩阵表。主对角线上的元素都为1,其余元素全为0的方阵称为单位矩阵。

 (10)创建元素为全0的矩阵

drop table if exists mat_r01, mat_r02; 
select madlib.matrix_zeros(3, 2, 'mat_r01','row=row_id, col=col_id, val=entry'), 
       madlib.matrix_zeros(3, 2, 'mat_r02', 'fmt=dense');
select * from mat_r01;
select * from mat_r02;

        结果分别为:

 row_id | col_id | entry
--------+--------+-------
      3 |      2 |     0
(1 row)

 row|  val 
-----+-------
   1| {0,0}
   3| {0,0}
   2| {0,0}
(3 rows)

        注意因为元素值全为0,稀疏表示的矩阵表只有1行。fmt=dense指示结果表是稠密格式。

 (11)创建元素为全1的矩阵

drop table if exists mat_r11, mat_r12; 
select madlib.matrix_ones(3, 2, 'mat_r11','row=row_id, col=col_id, val=entry'), 
       madlib.matrix_ones(3, 2, 'mat_r12', 'fmt=dense');
select * from mat_r11 order by row_id;
select * from mat_r12 order by row;

        结果分别为:

row_id | col_id | entry
--------+--------+-------
     1 |      2 |     1
     1 |      1 |     1
     2 |      2 |     1
     2 |      1 |     1
     3 |      2 |     1
     3 |      1 |     1
(6 rows)

 row|  val 
-----+-------
   1| {1,1}
   2| {1,1}
   3| {1,1}
(3 rows)

        注意因为元素值全为1,稀疏表示的矩阵表有6行。

 (12)获取行列维度数

select madlib.matrix_ndims('mat_a','row=row_id, val=row_vec'),
       madlib.matrix_ndims('mat_a_sparse', 'row=row_id, col=col_id');

        结果:

 matrix_ndims | matrix_ndims
--------------+--------------
  {4,4}       | {4,4}
(1 row)

(13)矩阵相加

        与向量一样,矩阵也可以通过将对应元素(分量)相加来求和。MADlib的矩阵相加函数要求两个矩阵具有相同的行数和列数。更明确地说,假定A和B都是mXn的矩阵,A和B的和是mXn矩阵C,其元素由下式计算:

drop table if exists mat_r; 
select madlib.matrix_add('mat_b','row=row_id, val=vector', 
                         'mat_b_sparse','row=row_id, col=col_id', 
                         'mat_r', 'val=vector,fmt=dense'); 
select * from mat_r order by row_id;

        结果:

 row_id |   vector   
--------+--------------
      1 | {18,20,4,8}
      2 | {10,6,10,4}
      3 | {0,2,4,6}
      4 | {4,18,0,8}
      5 | {6,16,14,14}
(5 rows)

        madlib.matrix_add函数有三组参数,分别指示两个相加的矩阵表和结果矩阵表。相加的两个矩阵表不必有相同的表示形式,如上面的函数调用中,两个矩阵一个为稠密形式,一个为稀疏形式。但两个矩阵必须具有相同的行列数,否则会报如下错误:

Matrix error: The dimensions of the twomatrices don't match

        矩阵加法具有如下性质。

  • 矩阵加法的交换律。加的次序不影响结果:A + B = B + A。
  • 矩阵加法的结合律。相加时矩阵分组不影响结果:(A + B) + C = A + (B + C)。
  • 矩阵加法单位元的存在性。存在一个零矩阵(zero matrix),其元素均为0并简记为0,是单位元。对于任意矩阵A,有A +0 = A。
  • 矩阵加法逆元的存在性。对于每个矩阵A,都存在一个矩阵-A,使得A +(-A) = 0。-A的元素为。 

(14)标量与矩阵相乘

        与向量一样,也可以用标量乘以矩阵。标量α和矩阵A的乘积是矩阵B =αA,其元素由下式给出:

        如下面matrix_scalar_mult函数执行结果是由原矩阵的每个元素乘以3构成的矩阵表。

drop table if exists mat_r; 
select madlib.matrix_scalar_mult('mat_a','row=row_id, val=row_vec', 3, 'mat_r'); 
select * from mat_r order by row_id;

结果:

 row_id |   row_vec   
--------+---------------
      1 | {27,18,15,24}
      2 | {24,6,6,18}
      3 | {9,27,27,27}
      4 | {18,12,6,6}
(4 rows)

        矩阵的标量乘法具有与向量的标量乘法非常相似的性质。

  • 标量乘法的结合律。被两个标量乘的次序不影响结果:α(βA) = (αβ)A。
  • 标量加法对标量与矩阵乘法的分配率。两个标量相加后乘以一个矩阵等于每个标量乘以该矩阵之后的结果矩阵相加:(α+β)A =αA +βA。
  • 标量乘法对矩阵加法的分配率。两个矩阵相加之后的和与一个标量相乘等于每个矩阵与该标量相乘然后相加:α(A + B)=αA + αB。
  • 标量单位元的存在性。如果α=1,则对于任意矩阵A,有αA =A。

         我们可以认为矩阵由行向量或列向量组成,因此矩阵相加或用标量乘以矩阵等于对应行向量或列向量相加或用标量乘它们。

 (15)矩阵乘法

        我们可以定义矩阵的乘法运算。先定义矩阵与向量的乘法。

        矩阵与列向量的乘法mXn矩阵A乘以nX1的列矩阵u的积是mX1的列矩阵 v=Au,其元素由下式给出:

        换言之,我们取A的每个行向量与u的转置的点积。注意,在下面的例子中,u的行数必然与A的列数相等。

        类似地,我们可以定义矩阵被行向量左乘。

        矩阵与行向量的乘法1Xm的行矩阵u乘以mXn矩阵A的积是1Xn的行矩阵v=uA,其元素由下式给出:

        换言之,我们取该行向量与矩阵A的每个列向量的转置的点积。下面给出一个例子:

        MADlib的matrix_vec_mult函数用于计算一个mXn矩阵乘以一个1Xn的矩阵(向量),结果是一个1Xm的矩阵。如下面的5X4的矩阵mat_b乘以一个1X4的矩阵,结果一个1X5的矩阵。

dm=# select * from mat_b;
 row_id |  vector  
--------+------------
     1 | {9,10,2,4}
     2 | {5,3,5,2}
     3 | {0,1,2,3}
     4 | {2,9,0,4}
     5 | {3,8,7,7}
(5 rows)

dm=# select madlib.matrix_vec_mult('mat_b','row=row_id, val=vector', 
dm(#                               array[1,2,3,4]);
 matrix_vec_mult 
------------------
 {51,34,20,36,68}
(1 row)

        可以用下面的查询验证矩阵乘以向量的结果。

dm=# select array_agg(madlib.array_dot(vector,array[1,2,3,4])) from mat_b;
   array_agg    
------------------
 {51,34,20,36,68}
(1 row)

        我们定义两个矩阵的乘积,作为上述概念的推广。mXn矩阵A与nXp矩阵B的积是mXp矩阵C=AB,其元素由下式给出:

        换言之,C的第 ij 个元素是A的第 个行向量与B的第 个列向量转置的点积。

        matrix_mult函数用于矩阵相乘。如前所述,第一组参数中的矩阵列数应该与第二组参数中的矩阵行数相同,否则会报错:

dm=# select * from mat_a;
 row_id |  row_vec 
--------+-----------
      1 | {9,6,5,8}
      2 | {8,2,2,6}
      3 | {3,9,9,9}
      4 | {6,4,2,2}
(4 rows)

dm=# select * from mat_b;
 row_id |   vector  
--------+------------
      1 | {9,10,2,4}
      2 | {5,3,5,2}
      3 | {0,1,2,3}
      4 | {2,9,0,4}
      5 | {3,8,7,7}
(5 rows)

dm=# drop table if exists mat_r; 
NOTICE:  table"mat_r" does not exist, skipping
DROP TABLE
dm=# select madlib.matrix_mult('mat_a', 'row=row_id,val=row_vec', 
dm(#                          'mat_b', 'row=row_id, val=vector', 
dm(#                          'mat_r'); 
ERROR:  plpy.Error: Matrixerror: Dimension mismatch for matrix multiplication. (plpython.c:4663)
DETAIL:  Left matrix, coldimension = 4, Right matrix, row dimension = 5
CONTEXT:  Traceback (mostrecent call last):
  PL/Python function"matrix_mult", line 26, in <module>
    matrix_out, out_args)
  PL/Python function"matrix_mult", line 1633, in matrix_mult
  PL/Python function"matrix_mult", line 49, in _assert
PL/Python function "matrix_mult"
dm=#

        可以对mat_b先进行转置,再与mat_a相乘。matrix_mult 函数调用时的trans=true参数表示先对mat_b表行列转置再进行矩阵乘法。这次的矩阵乘法计算将正常执行。

drop table if exists mat_r; 
select madlib.matrix_mult('mat_a', 'row=row_id,val=row_vec', 
                          'mat_b', 'row=row_id, val=vector, trans=true', 
                          'mat_r'); 
select * from mat_r order by row_id;

        结果是一个4X5矩阵:

row_id |      row_vec       
--------+----------------------
      1 |{183,104,40,104,166}
      2 |{120,68,24,58,96}
      3 |{171,105,54,123,207}
      4 |{106,56,14,56,78}
(4 rows)

        执行结果与下面的查询相同。

drop table if exists mat_r; 
select madlib.matrix_mult('mat_a', 'row=row_id,val=row_vec', 
                         'mat_b_sparse_r', 'row=row_id, col=col_id, val=val', 
                         'mat_r'); 
select * from mat_r order by row_id;

        矩阵乘法具有如下性质。

  • 矩阵乘法的结合律。矩阵乘的次序不影响计算结果:(AB)C=A(BC)。
  • 矩阵乘法的分配率。矩阵乘法对矩阵加法是可分配的:A(B+ C) = AB + AC并且(B + C)A = BA + CA。
  • 矩阵乘法单位元的存在性。如果pXp矩阵的单位矩阵,则对于任意mXn矩阵A,并且

         一般地,矩阵乘法是不可交换的,即

        如果我们有一个nX1列向量u,则我们可以把mXn矩阵A被该向量右乘看作u到m维列向量v=Au的变换。类似地,如果我们用一个(行)向量左乘A,则我们可以将它看作u到n维行向量v=uA的变换。这样,我们可以把一个任意mXn矩阵A看作一个把一个向量映射到另一个向量空间的函数。

        在许多情况下,可以用更容易理解的术语描述变换矩阵。

  • 缩放矩阵(scaling matrix)不改变向量的方向,而是改变向量的长度。这等价于乘以一个乘了标量的单位矩阵得到的矩阵。
  • 旋转矩阵(rotation matrix)改变向量的方向但不改变向量的量值。这相当于改变坐标系。
  • 反射矩阵(reflection matrix)将一个向量从一个或多个坐标轴反射。这等价于用-1乘该向量的某些元素,而保持其它元素不变。
  • 投影矩阵(projection matrix)把向量置于较低维子空间。最简单的例子是修改单位矩阵,将对角线上的一个或多个1改为0。这样的矩阵消除对应于0元素的向量分量,而保留其它分量。

         当然,单个矩阵可能同时进行两种类型的变换,如缩放和旋转。

 (16)两矩阵元素相乘

        与矩阵乘法定义不同,MADlib的两矩阵元素相乘定义为C=AB,A、B、C均为mXn矩阵,C的元素由下式给出:

        MADlib的matrix_elem_mult函数执行两矩阵元素相乘,并输出结果矩阵。

drop table if exists mat_r; 
select madlib.matrix_elem_mult('mat_b','row=row_id, val=vector', 
                          'mat_b_sparse','row=row_id, col=col_id, val=val', 
                          'mat_r','fmt=dense'); 
select * from mat_r order by row_id;

        结果:

row_id |   vector    
--------+---------------
     1 | {81,100,4,16}
     2 | {25,9,25,4}
     3 | {0,1,4,9}
     4 | {4,81,0,16}
     5 | {9,64,49,49}
(5 rows)

(17)求矩阵的秩

select madlib.matrix_rank('mat_a','row=row_id, val=row_vec');

        结果:

matrix_rank
-------------
          4
(1 row)

        注意,当矩阵以稀疏形式表示,并且列数大于行数时,matrix_rank函数会报错。

dm=#select madlib.matrix_rank('mat_b_sparse_r', 'row=row_id, col=col_id, val=val');
ERROR:  plpy.SPIError: Function"madlib.__matrix_compose_sparse_transition(doubleprecision[],integer,integer,integer,integer,double precision)": Invalidcol id. (UDF_impl.hpp:210)  (seg20hdp4:40000 pid=123035) (plpython.c:4663)
CONTEXT:  Traceback (most recent call last):
  PL/Python function "matrix_rank",line 23, in <module>
    returnmatrix_ops.matrix_rank(schema_madlib, matrix_in, in_args)
  PL/Python function "matrix_rank",line 2702, in matrix_rank
  PL/Python function "matrix_rank",line 2672, in matrix_eval_helper
PL/Pythonfunction "matrix_rank"
dm=#

        矩阵的秩(rank of a matrix)常常用来刻画矩阵。设矩阵,在A中任取 行 列交叉处元素按原相对位置组成的 阶行列式,称为A的一个 阶子式。mXn矩阵A共有个 阶子式。若A有 阶子式不为0,任何 r+1 阶子式(如果存在的话)全为0,称 为矩阵A的秩,记作R(A)。

        矩阵的秩具有以下基本性质:

  • 0矩阵的秩为0。
  • 如果R(A)=r,则A中至少有一个 阶子式,所有 r+1 阶子式为0,且更高阶子式均为0,是A中非零的子式的最高阶数。
  • 矩阵转置,秩不变。
  • 0<=R(A)<=min(m,n)。
  • 如果A是nXn方阵,并且|A|≠0,则R(A)=n;反之,如果R(A)=n,则|A|≠0。

        矩阵的秩是行空间和列空间的最小维度,此维度中的向量组是线性无关的。例如,如果把一个1Xn的行向量复制m次,产生一个mXn的矩阵,则我们只有一个秩为1的矩阵。

 (18)求逆矩阵

drop table if exists mat_r; 
select madlib.matrix_inverse('mat_a','row=row_id, val=row_vec', 'mat_r'); 
select row_vec from mat_r order byrow_id;

        结果:

                           row_vec                           
--------------------------------------------------------------
 {-1.2,0.900000000000001,0.333333333333334,0.600000000000001}
 {3.20000000000001,-2.4,-1,-1.1}
 {-5.00000000000001,3.50000000000001,1.66666666666667,2}
 {2.2,-1.4,-0.666666666666668,-1.1}
(4 rows)

        设A、B是两个矩阵,若AB=BA=E,则称B是A的逆矩阵,而A则被称为可逆矩阵。其中E是单位矩阵。

        一个实际和理论问题是矩阵是否像实数一样具有乘法逆元。首先,由于矩阵乘法的性质(即维必须匹配),如果矩阵具有逆矩阵(inverse matrix),它必须是方阵。这样,对于一个mXm的矩阵A,我们会问是否可以找到一个矩阵使得。答案是某些方阵有逆矩阵,而有些没有。

        一个mXm矩阵A有逆矩阵,当且仅当矩阵的秩R(A)=m,此时方阵A的行列式不为零,即|A|≠0,称A为非奇异矩阵或满秩矩阵,否则称A为奇异矩阵或降秩矩阵。满秩方阵的行、列向量组都是线性无关的。从概念上讲,一个mXm矩阵有逆矩阵,当且仅当它把每个非零m维行(列)向量都映射到一个唯一的非零m维行(列)向量。在求解各种矩阵方程时,逆矩阵的存在性是很重要的。

        下面看一个不可逆矩阵的例子。

create table t1 (a int, b int[]);
insert into t1 values
(1,'{1,2,3}'),(2,'{2,4,6}'),(3,'{3,6,9}');

select madlib.matrix_rank('t1', 'row=a,val=b');
select madlib.matrix_inverse('t1', 'row=a,val=b', 't2');
select * from t2 order by a;

        3阶矩阵t1的秩为1,用matrix_inverse求t1的逆矩阵,结果如下:

a |            b            
---+--------------------------
 1 |{NaN,NaN,NaN}
 2 |{-Infinity,Infinity,NaN}
 3 |{Infinity,-Infinity,NaN}
(3 rows)

        如果求逆的矩阵不是方阵,则matrix_inverse函数会报如下错误:

Matrix error: Inverse operation is onlydefined for square matrices

(19)求广义逆矩阵

        把逆矩阵推广到不可逆方阵(奇异矩阵)或长方矩阵上,这就是所谓的广义逆矩阵。广义逆矩阵具有逆矩阵的部分性质,并且在方阵可逆时,它通常与逆矩阵一致。

drop table if exists mat_r; 
select madlib.matrix_pinv('mat_a','row=row_id, val=row_vec', 'mat_r'); 
select row_vec from mat_r order byrow_id;

        结果:

                                  row_vec                                 
---------------------------------------------------------------------------
 {-1.20000000000001,0.900000000000004,0.333333333333335,0.600000000000003}
 {3.20000000000002,-2.40000000000001,-1,-1.10000000000001}
 {-5.00000000000003,3.50000000000002,1.66666666666667,2.00000000000001}
 {2.20000000000001,-1.40000000000001,-0.66666666666667,-1.1}
(4rows)

        matrix_pinv函数用于求矩阵的广义逆矩阵。还以上面的不可逆方阵为例,求它的广义逆矩阵。

drop table if exists t1,t2;
create table t1 (a int, b int[]);
insert into t1 values
(1,'{1,2,3}'),(2,'{2,4,6}'),(3,'{3,6,9}');

select madlib.matrix_pinv('t1', 'row=a,val=b', 't2');
select * from t2 order by a;

        结果:

a |                              b                             
---+-------------------------------------------------------------
 1 |{0.00510204081632653,0.0102040816326531,0.0153061224489796}
 2 |{0.0102040816326531,0.0204081632653061,0.0306122448979592}
 3 |{0.0153061224489796,0.0306122448979592,0.0459183673469388}
(3 rows)

        再看一个长方矩阵的例子。

drop table if exists mat_r; 
select madlib.matrix_ndims('mat_b','row=row_id, val=vector'),
       madlib.matrix_pinv('mat_b', 'row=row_id, val=vector', 'mat_r'); 
select * from mat_r order by row_id;

        mat_b是一个5X4矩阵,它的广义逆矩阵如下:

row_id|                                              vector                                              
--------+----------------------------------------------------------------------------------------------------
      1 |{0.169405974490348,-0.000368687326811998,0.153584606426279,-0.123375654346853,-0.0920196750284563}
      2 |{-0.0977762692158761,0.0690615737096675,-0.292887943436732,0.173906300749372,0.0622886509652684}
      3 | {-0.145985550968097,0.18130052991488,-0.238906461684316,0.0186947883412873,0.123325910818632}
      4 |{0.167425011631207,-0.222818819439771,0.534239640910248,-0.134386530622994,-0.0413193154120082}
(4rows)

        设A为m×n矩阵,如果存在n×m阶矩阵G,满足条件 ① AGA=A,② GAG=G, ③(AG)*=AG, ④ (GA)*=GA,式中*表示共轭后再转置,则称G为A的广义矩阵。

(20)提取矩阵的特征值

drop table if exists mat_r; 
select madlib.matrix_eigen('mat_a','row=row_id, val=row_vec', 'mat_r'); 
select * from mat_r order by row_id;

        结果:

row_id |      eigen_values     
--------+------------------------
     1 | (22.2561699851212,0)
     2 | (-0.325748023524478,0)
     3 | (2.91179834025418,0)
     4 | (-2.8422203018509,0)
(4 rows)

        特征值和特征向量,连同相关的奇异值和奇异向量概念,捕获了矩阵的结构,使得我们可以分解矩阵,并用标准形式表示它们。因此,这些概念可以用于数学方程求解、维归约和降低噪声。

        n阶方阵A的特征值和特征向量分别是标量值λ和向量u,它们是如下方程的解:Au=λu

        换言之,特征向量(eigenvector)是被A乘时除量值外并不改变的向量。特征值(eigenvalue)是缩放因子。该方程也可以写成(A-λE)u = 0,其中E为单位矩阵。|A-λE|是一个n次多项式,它的全部根就是n阶方阵A的全部特征值。如果n阶矩阵A的全部特征值为,则

(21)求矩阵范数

        matrix_norm函数用于求矩阵范数,支持的类型值有‘fro’、‘one’、‘inf’、‘max’、‘spec’,分别代表frobenius范数、1范数、infinity范数、max范数和spectral范数。缺省为frobenius范数。

select madlib.matrix_norm('mat_b_sparse','row=row_id, col=col_id, val=val','fro');

        结果:

 matrix_norm 
---------------
 23.4520787991
(1 row)

        F-范数的公式为:。依据公式下面查询的结果与matrix_norm函数的返回值相等。

select sqrt(sum(power(val,2))) frommat_b_sparse;

(22)求矩阵核范数

select madlib.matrix_nuclear_norm('mat_a','row=row_id, val=row_vec');

        结果:

matrix_nuclear_norm
---------------------
       34.322635238
(1 row)

        矩阵的核范数是指矩阵奇异值的和,关于矩阵奇异值,在讨论MADlib的矩阵分解函数时再进行详细说明。

四、矩阵与数据分析

        我们可以把数据集表示成数据矩阵,其中每一行存放一个数据对象,而每一列是一个属性。(同样,我们也可以用行表示属性,列表示对象。)矩阵表示为我们的数据提供了紧凑、结构良好的表示,使得我们可以很容易地通过各种矩阵运算对数据对象或属性进行操作。

        线性方程组是使用数据的矩阵表示的很常见的例子。线性方程组可以写成一个矩阵方程Ax=b,并使用矩阵运算求解。

        特殊地,如果A有逆矩阵,则该方程组的解为。如果A没有逆矩阵,则该方程组或者没有解,或者有无穷多个解。注意,在这种情况下,行(数据对象)是方程,列是变量(属性)。

        对于许多统计学和数据分析问题,我们希望解线性方程组,但是这些线性方程组不能使用刚才介绍的方法求解。例如,我们可能有一个数据矩阵,其中行代表病人,而列代表病人的特征(身高、体重和年龄)和他们对特定药物治疗的反应(如血压的变化)。我们想把血压(因变量)表示成其它(自)变量的线性函数,并且可以用上面的方法写一个矩阵方程。然而,如果我们的病人比变量多(通常如此),则矩阵的逆不存在。

        在这种情况下,我们仍然想找出该方程的最好解。这意味着我们想找出自变量的最好线性组合来预测因变量。使用线性代数的术语,我们想找尽可能接近向量b的向量Ax;换句话说,我们希望最小化向量b-Ax的长度‖b-Ax‖。这称作最小二乘(least square)问题。许多统计学技术(例如线性回归)都需要解最小二乘问题。可以证明,方程Ax=b的最小二乘解是

        在分析数据时,特别是对于维归约,奇异值和特征向量分解也非常有用。维归约还可以带来降低噪声的效果。


文章最后发布于: 2017-12-26 17:31:25
展开阅读全文
0 个人打赏
私信求帮助
曾参与过风云系列卫星、碳卫星、子午工程、嫦娥等项目的数据处理工作;有超10年大型项目的开发经验。 专栏收入了作者为Python爱好者精心打造的多篇文章,从小白入门学习的基础语法、基础模块精讲等内容外,还提出了“Python语感训练”的概念和方法,不仅为初学者提供了进阶之路,有一定基础的程序员亦可从中受益。后续,本专栏还将加入2D/3D应用开发、数据处理、实战项目等精品内容,敬请期待。
xufive ¥3.80 1501人订阅

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览