1. 程式人生 > >資料分析與資料探勘 - 04科學計算

資料分析與資料探勘 - 04科學計算

### 一 認識科學計算 在人工智慧的研發中,其本質就是把一切問題轉化為數學問題,所以數學運算非常重要。很多數學運算採用的都是numpy這個庫,因為它提供了非常多的科學計算的方法,能讓我們的工作變得非常便利,這一章我將從numpy的基本使用開始,逐漸解決掉那些數學問題,讓Python與數學能夠更緊密的結合在一起。 ### 二 認識numpy numpy的本質其實還是一個多維陣列,雖然我們之前學習過陣列物件(Python中的list或者tuple)和numpy的資料看似一樣,但是陣列是無法直接參與數值運算的,而numpy物件卻可以。 ### 三 陣列建立 ```python import numpy as np arr1 = np.array([1, 2, 3, 4, 5, 6]) arr2 = np.array([[1, 2, 3, 4, ], [5, 6, 7, 8, ]]) print(arr1, arr1.shape, arr1.dtype) print(arr2, arr2.shape, arr1.dtype) # shape獲取陣列形狀2行4列,dtype獲取陣列中元素型別 ``` 如果我們建立陣列時,元素型別不一樣,numpy會給我們自動處理成一樣的。 ```python arr3 = np.array([1, 2.5, 3]) # 只要陣列元素中出現float型別,就會全部處理成float print(arr3, arr3.dtype) arr4 = np.array(['4', 5, 5.6]) # 只要陣列元素中出現str,就會全部處理成str print(arr4, arr4.dtype) ``` ### 四 陣列訪問 numpy的訪問與Python中list或者tuple訪問原理一樣,方法也非常類似,只不過是加了一個緯度的概念。 ```python # 首先我們定義了一個二維陣列 arr5 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) print(arr5[1]) # 第一行 [4 5 6] print(arr5[1][0]) # 第一行第0個 4 print(arr5[:, 2]) # 所有行第2個 [ 3 6 9 12] print(arr5[:2]) # 前2行 [[1 2 3] [4 5 6]] print(arr5[1, :]) # 第1行所有列 [4 5 6] print(arr5[:, 1:2]) # 所有行第2到第3列 [[ 2] [ 5] [ 8] [11]] ``` 對於二維來說,如果有逗號,逗號前是行篩選,逗號後是列篩選。對於n維來說,第一個逗號前是第一維,後面依次是二維三維等。 ### 五 形狀處理 #### 1 預覽修改與真正修改 numpy物件有一個shape屬性,在Python基礎中,對於形狀並不敏感,而在科學計算中,形狀卻很重要,在後面的演算法模型計算中,我們會使用地很頻繁。 ```python # 定義一個6行3列的numpy陣列物件 arr6 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15], [16, 17, 18]]) print(arr6.shape) # 注意看每次列印的結果 print(arr6.reshape(2, 9)) # 得到一個新的形狀,原來的物件不變 print(arr6.shape, arr6) print(arr6.resize(2, 9)) # 無返回值,真正修改 print(arr6.shape, arr6) ``` 我們在這段程式碼中,分別使用了reshape和resize兩種方法來對陣列進行形狀上的改變。其中reshape只是返回改變形狀後的預覽狀態,或者說如果我們要使用這個結果只能把結果賦值給一個單獨的變數,然後再進行使用。resize方法的返回結果為空,但是它卻真正的改變了組數的形狀,仔細看列印結果你就能夠發現這兩種形狀操作方法的區別了。 #### 2 降維操作 降維是人工智慧演算法中非常常用且重要的一個操作,原因是有時我們去描述一個事物的特徵時,會有非常多的維度,但過多的維度會給我們的計算帶來麻煩,這個時候我們就需要去降低它的維度,然後再進行計算。 ```python arr7 = np.array([[1, 10, 100], [2, 20, 200], [3, 30, 300]]) # 按照陣列的行順序降至一維 print(arr7) print(arr7.ravel()) print(arr7.reshape(-1)) print(arr7.flatten()) # 按照大小順序降至一維 print(arr7.ravel(order="F")) print(arr7.reshape(-1, order="F")) print(arr7.flatten(order="F")) ``` 降維後再進行修改 ```python print('ravel:{}'.format(arr7.ravel())) arr7.ravel()[1] = 1000 print(arr7) print('reshape: {}'.format(arr7.reshape(-1))) arr7.reshape(-1)[2] = 3000 print(arr7) print('flatten: {}'.format(arr7.flatten())) arr7.flatten()[0] = 2000 print(arr7) ``` 從結果中,我們看到通過flatten方法實現的降維返回的是複製的操作,如果要用,那麼只能把結果賦值給另外的變量了。它並沒有影響原來陣列的結果。通過ravel和reshape兩個方法,返回的則是檢視,也就是通過對檢視的修改,是會直接影響到原陣列中的值的。 #### 3 陣列堆疊 ```python arr8 = np.array([[1, 10, 100], [2, 20, 200], [3, 30, 300]]) arr9 = np.array([1, 2, 3]) arr10 = np.array([[5], [6], [7]]) # 縱向堆疊 print(np.vstack([arr8, arr9])) print(np.row_stack([arr8, arr9])) # 橫向合併 print(np.hstack([arr8, arr10])) print(np.column_stack([arr8, arr10])) ``` 需要注意的是:多個數組橫向堆疊時,要保證行數相同,縱向合併,則要保證列數相同。 ### 六 基本運算 #### 1 四則運算 在以前,我們如果要對兩個同形狀的陣列進行對應位置的四則運算時,我們必須要對兩個陣列進行迴圈處理,程式碼量上來說並不少,並且容易出錯。有了NumPy之後,這些運算將會變的非常的簡單。 ```python import numpy as np arr1 = np.array([11, 12, 13]) arr2 = np.array([21, 22, 23]) arr3 = np.array([31, 32, 33]) print(arr1 + arr2) print(arr1 + arr2 + arr3) print(arr1 - arr2) print(arr1 - arr2 - arr3) print(arr1 * arr2) print(arr1 * arr2 * arr3) print(arr1 / arr2) print(arr1 / arr2 / arr3) print(arr1 // arr2) print(arr1 % arr2) print(arr1 ** arr2) print(np.add(arr1, arr2)) print(np.add(np.add(arr1, arr2), arr3)) print(np.subtract(arr1, arr2)) print(np.multiply(arr1, arr2)) print(np.divide(arr1, arr2)) ``` 從程式碼的執行結果中我們可以看到,當我們使用符號進行四則運算的時候,是可以連續進行操作的。當我們使用物件的方法進行四則運算的時候,不可以連續進行操作,因為這個方法只接收兩個引數。如果我們想要對多個數組物件進行操作的時候,我們必須使用方法巢狀的方式來進行操作。除了四則運算,在學習Python基礎時,所學習的取餘數、整除、冪運算等都是支援的。 #### 2 比較運算 ```python print(arr1 <= arr2) print(arr1 == arr2) print(arr1 != arr2) print(np.greater(arr1, arr2)) print(np.greater_equal(arr1, arr2)) print(np.less(arr1, arr2)) print(np.less_equal(arr1, arr2)) print(np.equal(arr1, arr2)) print(np.not_equal(arr1, arr2)) ``` 從結果上看,運用比較運算子可以返回布林型別的值,也就是True和False。那我們什麼時候會用到這樣的運算呢?第一種情況是從陣列中查詢滿足條件的元素,第二種情況是根據判斷的結果執行不同的操作,示例程式碼如下: ```python arr3 = np.array([23, 12, 25]) arr4 = np.array([21, 15, 23]) print(arr3[arr3 > arr4]) # 取出arr3中元素大於arr4的 print(arr3[arr3 > 24]) # 取出arr3中元素大於24的 print(np.where(arr3 > 24, 0, arr3)) # 類似三元表示式,把大於24的修改成0,其他不變 print(list(0 if x > 24 else x for x in arr3)) print(np.where(arr4 > 16, 0, arr4)) ``` #### 3 廣播運算 上面我們所有的運算都是基於相同形狀的陣列,那麼當陣列形狀不同時,能夠讓它們之間進行運算嗎?答案是肯定的,但是有相應的規則,不能隨意計算,這種計算就叫做廣播運算。 ```python # 1 廣播運算,末尾的緯度值加上去 arr3 = np.arange(60).reshape(5, 4, 3) arr4 = np.arange(12).reshape(4, 3) print(arr3) print(arr4) print(arr3 + arr4) # 2 緯度值有一個為1 arr5 = np.arange(60).reshape(5, 4, 3) arr6 = np.arange(4).reshape(4, 1) print(arr5) print(arr6) print(arr5 + arr6) # 3 arr7會自動補齊,類似上面緯度值有一個為1 arr7 = np.arange(12).reshape(4, 3) arr8 = np.array([1, 2, 3]) print(arr7) print(arr8) print(arr7 + arr8) arr9 = np.arange(60).reshape(5, 4, 3) arr10 = np.arange(8).reshape(4, 2) print(arr9) print(arr10) # print(arr9 + arr10) # 不在上述三種討論範圍內,無法運算 ``` 其實,廣播運算中的廣播就是一對多,它的規律就是兩者有相似的地方可以對應的上就能運算,缺少的部分,會自動用相同的部分補齊。 ### 七 數學函式 numpy提供給我們一些常見的函式,除了np.pi或者np.e這樣的常量函式,numpy也提供給我們很多數學函式供我們直接呼叫。 ```python import numpy as np arr1 = np.array([1.3, 1.5, -1.8, 2.4, 3.2]) arr2 = np.array([1, 2, 3, 4, 5]) print(np.fabs(arr1)) # 絕對值 print(np.ceil(arr1)) # 向上取整 print(np.floor(arr1)) # 向下取整 print(np.round(arr1)) # 四捨五入 print(np.fmod(arr2, arr1)) # 餘數 print(np.modf(arr1)) # 取小數部分和整數部分 print(np.sqrt(arr2)) # 演算法平方根 print(np.square(arr2)) # 平方 print(np.exp(arr2)) # 以e為底的指數 print(np.power(arr2, 3)) # 各元素的3次方 print(np.log2(arr2)) # 以2為底的對數 print(np.log10(arr2)) # 以10為底的對數 print(np.log(arr2)) # 以e為底的對數 ``` ### 八 軸方向 陣列物件有幾個維度就有幾個軸,對於我們常見的二維陣列來說,軸0是豎直方向,軸1是水平方向。 ```python import numpy as np arr1 = np.array([[3, 7, 25, 8, 15, 20], [4, 5, 6, 9, 14, 21]]) print(arr1) print(np.max(arr1)) # 所有陣列元素最大值 print(np.max(arr1, axis=1)) # 軸1最大值 print(np.max(arr1, axis=0)) # 軸0最大值 ``` numpy提供了很多可以按照軸方向來計算的函式。 ```python print(np.min(arr1, axis=0)) # 最小值 print(np.min(arr1, axis=1)) print(np.mean(arr1, axis=0)) # 平均值 print(np.median(arr1, axis=0)) # 中位數 print(np.sum(arr1, axis=1)) # 求