- SQL機器學習庫MADlib技術解析
- 王雪迎
- 5147字
- 2020-06-29 18:08:05
2.2 矩陣
矩陣可以用來表示數據集,描述數據集上的變換,是MADlib中數據的基本格式,通常使用二維數組數據類型。MADlib中的向量是一維數組,可看作是矩陣的一種特殊形式。MADlib的矩陣運算模塊(matrix_ops)實現SQL中的矩陣操作。本節將介紹矩陣的概念,說明MADlib矩陣運算相關函數,并舉出一些簡單的函數調用示例。
2.2.1 矩陣定義
矩陣(matrix)是把數集合匯聚成行和列的一種表表示。術語“m×n矩陣”通常用來說明矩陣具有m行和n列。下面所示的矩陣A是2×3矩陣。如果m=n,則我們稱該矩陣為方陣(square matrix)。矩陣A的轉置記作AT(通過交換A的行和列得到)。

矩陣的元素用帶下標的小寫字母表示。對于矩陣A,aij是其第i行第j列的元素。行自上而下編號,列自左向右編號,編號從1開始。例如,a21是矩陣A的第2行第1列的元素,該元素的值是7。
矩陣的每一行或列定義一個向量。對于矩陣A,其第i個行向量(row vector)可以用ai?表示,第j個列向量(column vector)用a?j表示。使用前面的例子,a2?=[7 5 2],而a?3=[1 2]T。注意,行向量和列向量都是矩陣,必須加以區分,即元素個數相同并且值相同的行向量和列向量代表不同的矩陣。
2.2.2 MADlib中的矩陣表示
MADlib支持稠密和稀疏兩種矩陣表示形式,所有矩陣運算都以任一種表示形式工作。
1. 稠密
矩陣被表示為一維數組的行集合,例如3×10的矩陣如下:

row_id列表示每一行的行號,是從1到N沒有重復值的連續整型序列,N為矩陣的行數。row_vec列對應構成矩陣每行的一維數組,即行向量。
2. 稀疏
使用行列下標指示矩陣中每一個非零項,例如:

常用這種方式表示包含多個零元素的稀疏矩陣。上面的例子只用6行表示一個4×7的矩陣中的非零元素。矩陣的行列元素個數分別由row_id和col_id的最大值指定。注意最后一行,即使value為0也要包含此行,它指出了矩陣的維度,而且指示矩陣的第4行與第7列的元素值都是0。
對于稀疏矩陣表,row_id和col_id列邏輯類似于關系數據庫的聯合主鍵,要求非空且唯一。value列應該是標量簡單數據類型。上面矩陣對應的稠密表示如下:

2.2.3 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_vec integer[]); 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, vector integer[]); 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條記錄。

(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;
結果:

-- 稀疏格式 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 by row_id, col_id;
結果:

源矩陣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函數的返回值是由對角線元素組成的數組。可以看到,矩陣和其對應的轉置矩陣具有相同的主對角線。也就是說,矩陣轉置實際上是沿著主對角線的元素對折操作。
(4)創建對角矩陣

結果:

madlib.matrix_diag函數輸出的是一個稀疏表示的對角矩陣表,如果不指定“col=col_id”,輸出表中代表列的列名為col。
(5)創建單位矩陣
drop table if exists mat_r; select madlib.matrix_identity(4, 'mat_r'); select * from mat_r;
結果:

matrix_identity函數創建一個稀疏表示的單位矩陣表。主對角線上的元素都為1、其余元素全為0的方陣稱為單位矩陣。
(6)提取指定下標的行或列

結果返回兩個向量,即mat_a的第2行、mat_b_sparse的第3列:

(7)獲取指定維度的最大最小值及其對應的下標
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;
結果:

matrix_max和matrix_min函數分別返回指定維度的最大值和最小值,其中維度參數的取值只能是1或2,分別代表行和列。返回值為數組類型,如果最后一個參數為‘true’,表示結果中包含最大最小值對應的下標數組列。
(8)創建元素為全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;
結果分別為:

注意,元素值全為0,所以稀疏表示的矩陣表只有1行。
(9)創建元素為全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;
結果分別為:

因為元素值全為1,所以稀疏表示的矩陣表有6行。
(10)獲取行列維度數
select madlib.matrix_ndims('mat_a', 'row=row_id, val=row_vec'), madlib.matrix_ndims('mat_a_sparse', 'row=row_id, col=col_id');
結果:

(11)矩陣相加
與向量一樣,矩陣也可以通過將對應元素(分量)相加來求和。MADlib的矩陣相加函數要求兩個矩陣具有相同的行數和列數。更明確地說,假定A和B都是m×n的矩陣,A和B的和是m×n矩陣C,其元素由下式計算:
cij=aij+bij

結果:

madlib.matrix_add函數有三組參數,分別是兩個相加的矩陣表和結果矩陣表。相加的兩個矩陣表不必有相同的表示形式,如上面的函數調用中,一個矩陣為稠密形式,一個矩陣為稀疏形式,但兩個矩陣必須具有相同的行列數,否則會報如下錯誤:
Matrix error: The dimensions of the two matrices 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的元素為-aij。
(12)標量與矩陣相乘
與向量一樣,也可以用標量乘以矩陣。標量α和矩陣A的乘積是矩陣B=αA,其元素由下式給出:
bij=αaij
例如,下面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;
結果:

矩陣的標量乘法具有與向量的標量乘法非常相似的性質。
?標量乘法的結合律,被兩個標量乘的次序不影響結果:α(βA)=(αβ)A。
?標量加法對標量與矩陣乘法的分配率,兩個標量相加后乘以一個矩陣等于每個標量乘以該矩陣之后的結果矩陣相加:(α+β)A=αA+βA。
?標量乘法對矩陣加法的分配率,兩個矩陣相加之后的和與一個標量相乘等于每個矩陣與該標量相乘然后相加:α(A+B)=αA+αB。
?標量單位元的存在性,如果α=1,則對于任意矩陣A,有αA=A。
我們可以認為矩陣由行向量或列向量組成,因此矩陣相加或用標量乘以矩陣等于對應行向量或列向量相加或用標量乘它們。
(13)矩陣乘法
我們可以定義矩陣的乘法運算。先定義矩陣與向量的乘法。矩陣與列向量的乘法:m×n矩陣A乘以n×1的列矩陣u的積是m×1的列矩陣v=Au,其元素由下式給出:
vi=ai?·uT
換言之,我們取A的每個行向量與u的轉置的點積。注意,在下面的例子中,u的行數必然與A的列數相等。

類似地,我們可以定義矩陣被行向量左乘。矩陣與行向量的乘法:1×m的行矩陣u乘以m×n矩陣A的積是1×n的行矩陣v=uA,其元素由下式給出:
vi=u·(a?j)T
換言之,我們取該行向量與矩陣A的每個列向量的轉置的點積。下面給出一個例子:

MADlib的matrix_vec_mult函數用于計算一個m×n矩陣乘以一個1×n的矩陣(向量),結果是一個1×m的矩陣。如下面的5×4的矩陣mat_b乘以一個1×4的矩陣,結果是一個1×5的矩陣。

可以用下面的查詢驗證矩陣乘以向量的結果。
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)
我們定義兩個矩陣的乘積,作為上述概念的推廣。m×n矩陣A與n×p矩陣B的積是m×p矩陣C(C=AB),其元素由下式給出:
cij=ai?·(b?j)T
換言之,C的第ij個元素是A的第i個行向量與B的第j個列向量轉置的點積。
matrix_mult函數用于矩陣相乘。如前所述,第一組參數中的矩陣列數應該與第二組參數中的矩陣行數相同,否則會報錯:

可以對mat_b先進行轉置,再與mat_a相乘。matrix_mult函數調用時的trans=true參數表示先對mat_b表行列轉置再進行矩陣乘法。這次的矩陣乘法計算將正常執行。

結果是一個4×5矩陣:

執行結果與下面的查詢相同。

矩陣乘法具有如下性質。
?矩陣乘法的結合律,矩陣乘的次序不影響計算結果:(AB)C=A(BC)。
?矩陣乘法的分配率,矩陣乘法對矩陣加法是可分配的:A(B+C)=AB+AC并且(B+C)A=BA+CA。
?矩陣乘法單位元的存在性,若Ip是p×p矩陣的單位矩陣,則對于任意m×n矩陣A,AIn=A并且ImA=A。
一般地,矩陣乘法是不可交換的,即AB≠BA。
如果我們有一個n×1列向量u,我們就可以把m×n矩陣A被該向量右乘看作u到m維列向量v=Au的變換。類似地,如果我們用一個(行)向量u=[u1,…,um]左乘A,我們可以將它看作u到n維行向量v=uA的變換。這樣,我們可以把一個任意m×n矩陣A看作一個把一個向量映射到另一個向量空間的函數。
(14)兩矩陣元素相乘
與矩陣乘法定義不同,MADlib的兩矩陣元素相乘定義為C=AB,A、B、C均為m×n矩陣,C的元素由下式給出:
cij=aij×bij
MADlib的matrix_elem_mult函數執行兩矩陣元素相乘,并輸出結果矩陣。

結果:

(15)求矩陣的秩
select madlib.matrix_rank('mat_a', 'row=row_id, val=row_vec');
結果:

注意,當矩陣以稀疏形式表示,并且列數大于行數時,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(double precision[],integer,integer,integer,integer,double precision)": Invalid col id. (UDF_impl.hpp:210) (seg20 hdp4:40000 pid=123035) (plpython.c:4663) CONTEXT: Traceback (most recent call last): PL/Python function "matrix_rank", line 23, in <module> return matrix_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/Python function "matrix_rank" dm=#
矩陣的秩(rank of a matrix)常常用來刻畫矩陣。設矩陣A=(aij)m×n,在A中任取k行k列交叉處元素按原相對位置組成的k階行列式,稱為A的一個k階子式。m×n矩陣A共有個k階子式。若A有r階子式不為0,任何r+1階子式(如果存在的話)全為0,則稱r為矩陣A的秩,記作R(A)。
矩陣的秩具有以下基本性質:
?0矩陣的秩為0。
?若R(A)=r,則A中至少有一個r階子式Dr≠0,所有r+1階子式為0,且更高階子式均為0,r是A中非零子式的最高階數。
?矩陣轉置,秩不變。
?0≤R(A)≤min(m,n)。
?若A是n×n方陣,并且|A|≠0,則R(A)=n;反之,若R(A)=n,則|A|≠0。
矩陣的秩(rank of a matrix)是行空間和列空間的最小維度,此維度中的向量組是線性無關的。例如,把一個1×n的行向量復制m次,產生一個m×n的矩陣,則我們只有一個秩為1的矩陣。
(16)求逆矩陣
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 by row_id;
結果:

設A、B是兩個矩陣,若AB=BA=E,則稱B是A的逆矩陣,而A則被稱為可逆矩陣。其中E是單位矩陣。下面看一個不可逆矩陣的例子。
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的逆矩陣,結果如下:

如果求逆的矩陣不是方陣,那matrix_inverse函數會報如下錯誤:
Matrix error: Inverse operation is only defined for square matrices
(17)求廣義逆矩陣
把逆矩陣推廣到不可逆方陣(奇異矩陣)或長方矩陣上,這就是所謂的廣義逆矩陣。廣義逆矩陣具有逆矩陣的部分性質,并且在方陣可逆時,它通常與逆矩陣一致。
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 by row_id;
結果:

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;
結果:

再看一個長方矩陣的例子。
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是一個5×4矩陣,它的廣義逆矩陣如下:

(18)提取矩陣的特征值
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;
結果:

(19)求矩陣范數
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');
結果:

F-范數的公式為:。依據公式可知下面查詢的結果與matrix_norm函數的返回值相等。
select sqrt(sum(power(val,2))) from mat_b_sparse;
(20)求矩陣核范數
select madlib.matrix_nuclear_norm('mat_a', 'row=row_id, val=row_vec');
結果:

矩陣的核范數是指矩陣奇異值的和,關于矩陣奇異值,在討論MADlib的矩陣分解函數時再進行詳細說明。
- Linux Mint System Administrator’s Beginner's Guide
- 西門子PLC與InTouch綜合應用
- 輕松學PHP
- Dreamweaver 8中文版商業案例精粹
- 精通Excel VBA
- 大數據平臺異常檢測分析系統的若干關鍵技術研究
- Windows 7寶典
- Prometheus監控實戰
- Excel 2007技巧大全
- 人工智能:智能人機交互
- 簡明學中文版Flash動畫制作
- 計算機應用基礎實訓·職業模塊
- Raspberry Pi 3 Projects for Java Programmers
- Mastering SQL Server 2014 Data Mining
- Mastering Android Game Development with Unity