什么是矩陣:
繼續接着上一次https://www.cnblogs.com/webor2006/p/14257300.html的線性代數往下學習,前兩次的學習都是跟Vector相關的,也就是學習線性代數這里是從Vector開始,而實際上人們一談到線性代數第一想到的不是向量,而是矩陣【Matrix】。對於矩陣的樣子應該都比較熟悉:
也就是將數排成m行,n列。那它的由來其實可以這樣理解:向量是對數的拓展,一個向量表示一組數;而矩陣是對向量的拓展,一個矩陣表示一組向量。那么問題來了,既然一個矩陣是表示多個向量,那對於上圖的這個矩陣到底表示幾個向量?這些向量分別是誰?這里可以分2個視角來進行看待:
也就是橫着來看,當然另一個視角就是豎着來看嘍:
那到底怎么來看待這個矩陣呢?這個待之后慢慢再來體會,目前先了解矩陣的一些基本概念。對於上圖的這個矩陣就可以稱之為“4 * 4矩陣,行數是4,列數是4”,而還有可能是這種矩陣,行列不一樣的:
它是3 * 4矩陣,行數是3,列數是4。另外對於行列相等的矩陣,又有一個名詞出現了:
它也叫“方陣”,對於方陣它是有很多的特殊的性質的,或者某些特殊的矩陣一定是方陣,關於這塊在后續再來體會,目前先了解該名詞既可。
那既然咱們學的是代數,那就需要用字母來代替數對吧,所以對於矩陣而言它的表示法通常是用一個大寫的字母,如下:
其中每一個元素都是由行列下標來表示,所以形式為:
它跟計算機中的二維數組的表示其實是一樣的,所以理解起來也非常之自然,下面舉個實際用矩陣表示數據的例子:
其中上圖就是典型的一個矩陣,其中行向量來看就是表示某一個人各個科目的成績,而列向量則表示某一個科目不同人的成績。
實現屬於我們自己的矩陣類:
跟向量的學習一樣,接下來則編程實現一下自己的矩陣類,先新建一個文件:
__init__:定義構造
class Matrix: def __init__(self, list2d): # 遍歷二維列表,然后拷貝生成一個新的列表 self._values = [row[:] for row in list2d]
__repr__:矩陣類輸出
如之前封裝Vector所示,還有另一個輸出的方法,這里簡單起見直接讓其等於它:
下面簡單調用一下:
shape():返回矩陣的形狀
標紅的其實是python中的逗號表達式,有了它,另外再提供兩個便捷的方法,就是返回矩陣的行數和列數,如下:
下面來調用試一下:
size():返回矩陣元素的個數:
測試一下:
__len__:
對於矩陣的大小其實返回它的行數既可,所以可以簡單定義為:
調用一下:
__getitem__:獲取某個位置的元素
調用一下:
row_vector、col_vector:獲得行向量:
由於看待矩陣的向量有兩個視角,所以也對外提供相應的方法,如下:
下面調用一下:
矩陣的基本運算:
跟學向量一樣的,對於矩陣也存在基本運算,這里先來回憶一下向量的基本運算有兩個:
而對於矩陣的基本運算也是兩個:
也就是矩陣的加法和數量乘法,下面具體來學習一下。
矩陣加法:
這塊比較好理解,直接給出結論:
矩陣數量乘法:
這里也直接給出結論,跟向量的數量乘差不多:
拿現實舉個例子:
要想算出2學期的平均分,就需要使用矩陣的加法,如下:
既要用到矩陣的加法,又要用到矩陣的數量乘法。
為了進一步加深對於矩陣的數量乘法的理解,下面回到二維平面的視角,既然矩形里面是包含多個向量,而每個向量可以看作是空間中的一個點,下面對於這樣一個矩陣:
這里以行向量的視角來看,每行對應二維平面的一個坐標,如下:
而如果這樣進行矩陣的數量乘:
此時結果為:
而對應平面上的點如藍色所示:
有木有直觀感受到對於矩陣的數量乘就是把原來的矩陣進行了一個擴大?
矩陣的運算性質:
矩陣加法:
交換率:
結合率:
-A唯一:
矩陣乘法:
結合率:
分配率:
舉例論證:
同樣的對於上面的每個結論都是可以通過嚴謹的證明的,以它為例,看一下論證過程:
其中可以看到等式確實是成立的。
實現矩陣的基本運算:
接下來則來回到編程的世界給咱們的矩陣加入基本運算。
__add__:矩陣加法
接下來處理i,它則是遍歷總行數,如下:
有木有發現python的遍歷真的好強大 ,當然感覺可讀性不太好的樣子,跟自己不太熟悉Python有關,慢慢習慣這種寫法,下面調用運行一下:
__sub__:兩矩陣相減
實現了兩矩陣相加之后,相減就非常easy啦:
def __sub__(self, another): """返回兩個矩陣的減法結果""" assert self.shape() == another.shape(), \ "Error in subtracting. Shape of matrix must be same." return Matrix([[a - b for a, b in zip(self.row_vector(i), another.row_vector(i))] for i in range(self.row_num())])
運行:
__mul__:矩陣的數量乘
def __mul__(self, k): """返回矩陣的數量乘結果:self * k""" return Matrix([[e * k for e in self.row_vector(i)] for i in range(self.row_num())])
運行:
依然跟向量一樣,如果將數字提到前面其運行也是會報錯的:
這是因為得覆蓋另一個魔法函數才行,如下:
然后再運行就好了。
__truediv__:矩陣的數量除
這里直接利用數量乘的邏輯來實現:
def __truediv__(self, k): """返回數量除法的結果矩陣:self / k""" return (1 / k) * self
正負矩陣:
比較簡單,直接定義了:
def __pos__(self): """返回矩陣取正的結果""" return 1 * self def __neg__(self): """返回矩陣取負的結果""" return -1 * self
下面調用一下:
zero:零矩陣:
調用一下:
把矩陣看作是對系統的描述:
在學習了矩陣的基本運算之后,接下來則該跟向量一樣學習一下矩陣x矩陣了,不過在學習它之前,先來從另一個視角來審視下矩陣~~之前我們的例子中矩陣是一個數據表格:
其實矩陣還可以表示一個系統,下面從多個維度來看一下:
經濟系統:
需要對IT,電子,礦產,房產進行投入預算,這里分別用這四個字母來表示:
首先看一下IT行業,專家預估需要這么多億:
其中電子,礦產、房產等都需要IT的成本,並非只有IT需要成本,所以可以看到另外三個行業也乘上了成本的系數。同樣的對於其它行業的成本預算如下:
而上面四個方程式組合起來就形成了如下方程組:
這樣就用了一個方程組描述了一個系統。
網絡中:
這里以抽象的角度來描述一個網絡,如下:
而把這個可以想象成一個交通網絡,其中有四個住在不同小區的人都需要去某個地方上班,比如:
其中每個小區都是100個人,現在可能交通部門想要觀測整個道路交通網絡中從這四個小區一直到最終的某個地方各個路徑相應的網絡情況,進而可以決定下次修路時哪些道路是需要擴寬一些,或者哪些地方可以增加一些公交站或地鐵站等等,換言之就是交通部門需要知道各個節點的網絡流量是多少,所以可以將各個道路流量假設成:
此時在這個網絡中就可以列出很多的等式了,如下:
可以看到也是用了一個方程組來描述了一個網絡系統。
電路系統中:
同樣地在電路系統中也是可以用方程組來描述的,先看一下簡單的電路圖:
關於這塊基本上也忘得差不多了,不過沒關系,感受一下系統的概念既可。先來看一下左側的電壓,每個回路都是可以看成一個方程的:
稍加解釋一下,從10v的電壓出發,就有正的10;然后遇到R1的電阻則需要減掉,而由於電流是I2,所以是R1*I2;然后再遇到5v正的電壓;最后再遇到電阻R2電壓就需要減掉,它的電流是I1,所以需要減掉的電壓是R2i1。這是左回路的電壓方程描述,同樣的對於右回路的電壓也可以描述為:
最后電流I1在A這個點分流成了I2和I3,所以又有如下等式:
這樣就可以通過這個方程組可以計算出來要布多大的布阻比較合適之類的,可見通過方程組又描述了一個電力系統。
通過上面的舉例可以看出:線性方程組在各個領域,都有着非常重要的應用,而在線性代數中,將這樣的方程組稱之為“線性系統【之后還會再學】”,而這里多次在強調“系統”的概念,那它跟矩陣有啥關系呢?這里以上述網絡系統的方程組為例,其實是可以做轉換的,如下:
其中可以看到等號右側的向量是用的列向量來表示的,因為剛好跟矩陣的行匹配上,這也是為啥一般向量要用列向量表達的原因之所在,所以可以看出對於系統的求解完成是可以轉換成了對於矩陣的求解對么?所以說用矩陣就可以來表達一個系統,而一旦將矩陣用這樣的方式看成系統之后,對於我們接下來要研究的矩陣的乘法就會變得很簡單了,關於線性系統如何求解待之后學到時再說。
矩陣和向量的乘法:
要想知道矩陣x矩陣,則需要先明白矩陣x向量,所以這里還是以上面提到的網絡系統轉成矩陣的那個圖為例進行闡述,抽象起來看的話,其實就是向量的數量乘【再一次體會到數學的嚴謹,基本上所有復雜的公式全是由之前簡單的結論所能推演過來的】,看一下:
好,接下來就有一系列的變化了,會有點繞,但是又是理解矩陣和矩陣乘法的關鍵,對於上面這個式子其實又可以推導成這樣:
所以就有如下等式了:
下面再來看一下對於等式右側的向量中的每一個元素都是怎么計算出來的,對於第一項其實是這樣:
而對於它其實就是向量的點乘運算,還記得向量點乘的式子么?可以回憶一下https://www.cnblogs.com/webor2006/p/14257300.html,
以此類推,對於結果向量的第二個元素的計算如下:
第三個元素:
第四個元素:
而總結一下可以發現:
好,接下來有一個非常非常關鍵的點來了,對於向量的點乘有一點非常重要的限制就是其向量的元素個數是必須一樣的對不?看一下咱們之前所實現的Vector中的點乘實現就能知道:
那么回到咱們目前的矩陣和向量的乘法操作是不是可以得出這么一個結論:
矩陣A的列數必須和向量u的元素個數一致!另外矩陣A的行數是沒有限制的。這里標紅加粗了,因為太重要了,其原因就是由於向量的點乘其要求元數的個數必須一樣。
下面來切換一下視角以行視角的方式來看待一下矩陣x向量其實就可以抽象成這樣:
這樣就更加容易理解。
再看向量的點乘:
在上面介紹矩陣x向量時:
其中提到對於矩陣的行數是木有限制的,可以是無數個,那假如矩陣的行數是1呢?此時就變成了這樣:
此時矩陣又變成了向量,又回到了向量的點乘了,而依然也能推算出此時的結果就是向量的點乘:
矩陣是向量的函數:
最后還有一個非常重要的結論,就是對於矩陣和向量的乘法用字母來表示的話:
從另一個角度來看,可以看到矩陣T實際上是將向量a轉換成了向量b了,是不是可以把矩陣理解成是一個向量的函數?理解這個視角對於后續空間等更加高級的內容時是非常重要的,先在大腦里記住它。
矩陣在圖形變換中的應用:
矩陣在向量中的轉換其實最典型的應用就是在圖形學中,在之前學習矩陣的數量乘時舉過這樣一個例子:
它在二維平面坐標系的樣子是這樣的:
基於此,假如向量不是一個具體的值,而是抽象的,那么也就是這樣:
也就是想將向量的x元素擴大1.5倍,而y擴大2倍,要想達到這樣的目的,此時肯定需要加一個系數了:
而T這個矩陣的形態是有要求的,如之前矩陣*向量的規則所述,該矩陣是要求列數必須跟向量的行數一致才可以,所以該矩陣的列數應該為2,而根據等號右側的向量結果來看,可以看出該矩陣的行數也是2,所以T是2x2的矩陣,抽象定義如下:
此時就可以很容易求解出此時T的值為:
也就是:
上面是對一個坐標點的轉換操作,但是!!!【此轉折點就是要推出矩陣x矩陣公式的關鍵啦!!】可能圖形中不止一個點呀,比如:
有三個坐標點,那用這個矩陣對每一個點去做乘法不就可以么?是的,這樣木問題,但是感覺有點麻煩,有木有更加批量的做法呢?其實有,就是將所有的點集合成一個矩陣,此時就如下:
那不就是矩陣x矩陣了么?嗯,是的,那它跟矩陣x向量有啥關系呢?回憶一下:
那是不是也可以將標紅處的這個向量看成是一個2x1的矩陣【其中2代表每個點坐標有2個維度x,y,而1表示當前只有一個坐標點】對不?而回到咱們目前探討的3個點的情況,那不就是多組矩陣x列向量的情況么?所以其結果為:
二維坐標系中也就對應:
矩陣和矩陣的乘法:
基於上面的推導,其實對於矩陣和矩陣的乘法操作就已經得出它的計算公式了,其實是這樣的:
用抽象一點的方式來看,就是這樣:
其中跟“矩陣x向量”的限制一樣,也需要滿足“矩陣A的列數必須和矩陣B的行數一致!【這個一定得要記住!!】”
下面用一個抽象的方式再來理解下:
假設矩形AB,其中B用一個列向量的形式來表示,此時就可以變為:
其相乘的結果每列都是列向量,而矩陣A看它的每行【為啥不看每列呢?因為根據矩陣Ax矩陣B的規則矩陣A的列數必須跟矩陣B的行數一致,是固定的,不固定的只有矩陣A的行,所以抽象的角度對於矩陣A當然是看每行的行向量,仔細體會一下~~】,也就是每行是一個行向量對不?那相應的咱們又可以變化為:
而它展開則為:
其中:
另外根據上面的表示再來總結一下矩陣與矩陣的相乘【為啥要不斷總結,因為這塊如果理解不透,將直接影響后續更加高級的線性代數的知識的學習,所以再啰嗦都不為過】:結果矩陣中的第i行第j列的元素其實就是A矩陣中的第i行向量和B矩陣的第j列向量進行點乘的結果,到圖上拿結果矩陣中的第一行來理解就是:
另外還可以總結一個規律:
根據矩陣A的列數必須和矩陣B的行數一致這個規則,假設:A是m * k的矩陣;B是k * n的矩陣,則結果矩陣為m * n的矩陣。而正因為矩陣和矩陣相乘是需要有一定的限制的,所以很顯然對於矩陣的乘法是不遵守交換律的:
因為很有可能根本是不能相乘的,記住這是我們所學的第一個不遵守交換律的乘法,關於這塊的證明待下面用python來實現時再來驗證一下是否是這樣的。
實現矩陣的乘法:
矩陣x向量:
下面則回到編程的世界中來對於上面所說的矩陣和向量的乘法、矩陣和矩陣的乘法實現一下。
這里分為兩種情況,也有像java的instance機制,下面先來實現矩陣和向量的乘法:
接下來就具體實現一下,其實就是矩形的行向量和向量的點乘,而對於Vector點乘咱們在之前已經實現過了,回憶一下:
所以實現起來就比較簡單了:
矩陣x矩陣:
而有了矩陣x向量的實現,那實現矩陣x矩陣也很簡單了,因為本身內部它就是矩陣x向量嘛,再回憶一下那個抽象圖:
同樣它也有需要有前置條件,並非所有的矩陣都滿足相乘,所以:
而實現如下:
調用:
接下來看一下矩陣x矩陣:
最后再來驗證一下在上面拋出的一個結論:“矩陣的乘法是不遵循交換率的”,下面來看一下:
矩陣乘法的性質:
接下來則來審視一下矩陣乘法的性質:
1、矩陣乘法不遵守交換律!
之前已經強調過了,這里再強調一下:
2、遵守規則:
但是呢,其實它也有一些性質是遵守的,如下:
- 乘法的結合率:
- 乘法的分配率:
同樣的反過來: - 零矩陣:
跟向量一樣,零矩陣也是相關的特性:
矩陣的冪:
學習了矩陣的乘法之后,很自然的就可以來學習矩陣的冪的概念了,如算數系統中,對於一個矩陣A的k次方可以表示為:
但是!!!由於矩陣的乘法是有限制的,這個限制再拎出來復習一下:“矩陣A的列數必須和矩陣B的行數一致!”,而要想讓同一個矩陣能夠相乘就只能是該矩陣是一個方陣【也就是行和列是一樣的】,這一點需要知道。
既然已經知道了矩陣的冪的概念之后,那可能出現如下特殊的冪:
那它們是如何表示呢?這個待未來再來闡述。下面再來看一個結論:
上面這個式子對於算數是成立的,但是對於矩陣是不成立的喲,下面簡單來證明如下:
記住結論就成,其證明過程了解既可。
矩陣的轉置:
概述:
還記得咱們在闡述一個矩陣跟多個點的相乘推出矩陣與矩陣的相乘那塊的東東么?回憶一下:
但是!!!實際中可能習慣按行的視角來表示P矩陣的多個點,也就是:
也就是每一行代表一個坐標上的點,而每一列則代表是二維平面中某一個維度的值(x軸或y軸),但是!!!很顯然如果將P進行了行視角的看待之后,沒法跟T矩陣相乘了呀,因為兩矩陣相乘必須要滿足矩陣A的列數要等於矩陣B的行數對吧?而目前看上圖,T是2列的,而P是3行的,不滿足相乘的要求了呀,咋辦?此時矩陣的轉置概述就誕生了,咱們將這個P轉置一下就滿足矩陣的相乘啦,如下:
其中轉置表式是在字母P上加上一個T,上面可以看到其實就是將P的列的元素依次往左倒就成了它的轉置了對不?
簡言之:矩陣的轉置就是行變成列、列變成行。用更加抽象一點的來表示就是:
知道了矩陣的轉置之后,這里回憶一下之前學習向量時也提到過向量的轉置,如下:
這樣就串起來了。
性質:
接下來又來探討矩陣轉置的一些特性了,了解這些特性有助於咱們更好的去使用它們。
1、轉置再轉置就是本身
2、矩陣的加法轉置:
3、矩陣的數量乘轉置:
4、矩陣和矩陣的相乘轉置:
這里需要特別注意等號右側,是B的轉置*A的轉置,需要注意順序喲,下面簡單論證一下:
注意看一定是先把B的轉置提到前面再乘以A的轉置喲~~順序一定要注意!!!
實現矩陣的轉置:
接下來編程來實現一下矩陣的轉置:
調用一下:
使用Numpy實現矩陣:
接下來使用Numpy數學庫來實現矩陣:
矩陣的創建:
也就是在numpy中對於向量和矩陣封裝在同一個函數當中了。
矩陣的屬性:
獲取矩陣的元素:
矩陣的基本運算:
接下來看一下矩陣與矩陣之間的乘法:
而要真正實現兩矩陣的相乘,則需要調用它:
接下來看一下矩陣x向量:
因為在numpy中對於高維的數組(比如2維矩陣)都可以跟低維的數組(比如一維的向量)進行運算的,比如直接可以跟一個數字進行運算:
在numpy中像這種高維的數組可以和低維的數組進行運算有一個專業的名詞叫廣播,但是!!!在數學領域需要慎用它,因為會給人制造錯覺,為啥一個矩陣可以跟一個向量進行加法操作呢?這里稍加提一下,下面來看一下矩陣和向量的乘法: