練習題
●Ex1:利用列表推導式寫矩陣乘法
●一般的矩陣乘法根據公式,可以由三重循環寫出:
●解:先回憶一下列表推導式的形式
●列表推導式(又稱列表解析式)提供了一種簡明扼要的方法來創建列表。
●列表推導式形式:[表達式 for 變量 in 列表] 或者 [表達式 for 變量 in 列表 if 條件]
●它的結構是在一個中括號裡包含一個表達式,然後是一個for語句,然後是 0 個或多個 for 或者 if 語句。表達式可以是任意的,意思是你可以在列表中放入任意類型的對象。返回結果將是一個新的列表,在這個以 if 和 for 語句為上下文的表達式運行完成之後產生。
●列表推導式的執行順序:各語句之間是嵌套關係,左邊第二個語句是最外層,依次往右進一層,左邊第一條語句是最後一層。
M1 = np.random.rand(2,3) #產生一個隨機矩陣2*3print(M1)[[0.5488135 0.71518937 0.60276338] [0.54488318 0.4236548 0.64589411]]
In [113]:M2 = np.random.rand(3,4)#產生一個隨機矩陣 3*4print(M2)[[0.43758721 0.891773 0.96366276 0.38344152] [0.79172504 0.52889492 0.56804456 0.92559664] [0.07103606 0.0871293 0.0202184 0.83261985]]
In [114]:res = np.empty((M1.shape[0],M2.shape[1]))#產生一個給定形狀和類型的新數組,不初始化entryprint(res)[[-7.6257842 -7.39469974 -7.3765087 -7.82499163] [-7.32639951 -7.00701384 -7.29012189 -7.63867444]]
In [135]:for i in range(M1.shape[0]): for j in range(M2.shape[1]): item = 0 for k in range(M1.shape[1]): item += M1[i][k] * M2[k][j] res[i][j] = itemprint(res)[[0.8492050332765654, 0.9201954386455283, 0.9473174754148058, 1.3742875058416857], [0.6197337964575249, 0.7662572840289622, 0.7787973807055315, 1.1388485499974779]]
In [136]:res=[[sum([M1[i][k] * M2[k][j] for k in range(M1.shape[1])]) for j in range(M2.shape[1])] for i in range(M1.shape[0])]#用列表推導式形式print(res)[[0.8492050332765654, 0.9201954386455283, 0.9473174754148058, 1.3742875058416857], [0.6197337964575249, 0.7662572840289622, 0.7787973807055315, 1.1388485499974779]]
In [137]:M1@M2 - resOut[137]:array([[0., 0., 0., 0.], [0., 0., 0., 0.]])In [138]:((M1@M2-res)< 1e-15).all()## 排除我們的結果是不是準確(和真正的矩陣乘法結果對比誤差小於1e-15)Out[138]:True●Ex2:更新矩陣
這個題應該就是考察廣播機制吧
import numpy as npm=3n=3A=np.arange(9).reshape(m,n)#這樣生成的A是不對的,因為不能有為0的元素print(A)[[0 1 2] [3 4 5] [6 7 8]]
A = np.arange(1,10).reshape(3,-1)#這樣弄成不含有0的就行了print(A)[[1 2 3] [4 5 6] [7 8 9]]
B=A*(1/A).sum(1).reshape(-1,1)print(B)[[1.83333333 3.66666667 5.5 ] [2.46666667 3.08333333 3.7 ] [2.65277778 3.03174603 3.41071429]]Ex3:卡方統計量
A = np.random.randint(10, 20, (8, 5))print(A)[[19 19 10 14 17] [13 12 17 12 10] [10 14 15 15 16] [18 14 11 14 19] [18 11 11 17 19] [19 13 16 17 12] [10 13 15 19 14] [14 16 14 14 13]]
A.sum(0)#按列相加array([121, 112, 109, 122, 120])
A.sum(1)#按行相加array([79, 64, 70, 76, 76, 77, 71, 71])
A.sum(0)*A.sum(1)#這樣會出錯的ValueError Traceback (most recent call last)<ipython-input-52-bb25f4d5b1de> in <module>----> 1 A.sum(0)*A.sum(1)ValueError: operands could not be broadcast together with shapes (5,) (8,)
A.sum(0)*A.sum(1).reshape(-1,1)#所以這裡要reshapearray([[9559, 8848, 8611, 9638, 9480], [7744, 7168, 6976, 7808, 7680], [8470, 7840, 7630, 8540, 8400], [9196, 8512, 8284, 9272, 9120], [9196, 8512, 8284, 9272, 9120], [9317, 8624, 8393, 9394, 9240], [8591, 7952, 7739, 8662, 8520], [8591, 7952, 7739, 8662, 8520]])B = A.sum(0)*A.sum(1).reshape(-1, 1)/A.sum()print(B)[[16.36815068 15.15068493 14.74486301 16.50342466 16.23287671] [13.26027397 12.2739726 11.94520548 13.36986301 13.15068493] [14.50342466 13.42465753 13.06506849 14.62328767 14.38356164] [15.74657534 14.57534247 14.18493151 15.87671233 15.61643836] [15.74657534 14.57534247 14.18493151 15.87671233 15.61643836] [15.95376712 14.76712329 14.37157534 16.08561644 15.82191781] [14.71061644 13.61643836 13.25171233 14.83219178 14.5890411 ] [14.71061644 13.61643836 13.25171233 14.83219178 14.5890411 ]]res = ((A-B)**2/B).sum()print(res)18.661200646129636Ex4:改進矩陣計算的性能
● 題目:
● 原方法是這樣的:
● 怎麼改進呢????
● 這裡我是照搬老師的
● 我只能說大約看懂了,實踐一下試試
● (((B**2).sum(1).reshape(-1,1) + (U**2).sum(0) -2*B@U)*Z).sum()#這個新方法看起來十分不錯
● 對比時間的開銷,好的果然不一般。。。
Ex5:連續整數的最大長度輸入一個整數的 Numpy 數組,返回其中遞增連續整數子數組的最大長度。例如,輸入 [1,2,5,6,7],[5,6,7]為具有最大長度的遞增連續整數子數組,因此輸出3;輸入[3,2,1,2,3,4,6],[1,2,3,4]為具有最大長度的遞增連續整數子數組,因此輸出4。請充分利用 Numpy 的內置函數完成。(提示:考慮使用 nonzero, diff 函數)。numpy.nonzero(a) 作用:函數返回輸入數組中非零元素的索引diff 表示和前一個元素做差,由於第一個元素為缺失值,因此在默認參數情況下,返回長度是原數組減1 f = lambda x:np.diff(np.nonzero(np.r_[1,np.diff(x)!=1,1])).max()