NumPy 是 Python 資料科學領域的核心函式庫,其提供的 ndarray 物件是高效數值運算的基礎。理解 ndarray 的特性和操作方法對於提升資料處理效率至關重要。本文將深入探討 NumPy 陣列的各種操作技巧,從對角線元素提取到算術運算,涵蓋了實際應用中常見的場景。透過學習這些技巧,讀者可以更有效地使用 NumPy 進行資料處理和分析。

矩陣對角線元素提取

在矩陣運算中,對角線元素的提取是一個重要的應用。對角線是指矩陣中從左上到右下的那一條線,包括了主對角線、副對角線以及其他各級對角線。

主對角線元素

主對角線是指從矩陣左上角到右下角的那一條線。例如,在以下矩陣中:

import numpy as np

# 定義矩陣
matrix = np.array([[17, 18, 19, 20],
                   [21, 22, 23, 24],
                   [25, 26, 27, 28],
                   [29, 30, 31, 32]])

# 提取主對角線元素
main_diagonal = np.diag(matrix)

print("主對角線元素:", main_diagonal)

輸出結果:

主對角線元素: [17 22 27 32]

副對角線元素

副對角線是指從矩陣右上角到左下角的那一條線。要提取副對角線元素,可以使用以下方法:

# 提取副對角線元素
secondary_diagonal = np.diag(np.fliplr(matrix))

print("副對角線元素:", secondary_diagonal)

輸出結果:

副對角線元素: [20 23 26 29]

其他對角線元素

除了主對角線和副對角線外,還有其他各級對角線。要提取這些對角線元素,可以使用以下方法:

# 提取1-diagonal元素
diagonal_1 = [matrix[i, i+1] for i in range(matrix.shape[0]-1)]

print("1-diagonal元素:", diagonal_1)

# 提取2-diagonal元素
diagonal_2 = [matrix[i, i+2] for i in range(matrix.shape[0]-2)]

print("2-diagonal元素:", diagonal_2)

# 提取-1-diagonal元素
diagonal_minus_1 = [matrix[i+1, i] for i in range(matrix.shape[0]-1)]

print("-1-diagonal元素:", diagonal_minus_1)

# 提取-2-diagonal元素
diagonal_minus_2 = [matrix[i+2, i] for i in range(matrix.shape[0]-2)]

print("-2-diagonal元素:", diagonal_minus_2)

輸出結果:

1-diagonal元素: [18, 23, 28]
2-diagonal元素: [19, 24]
-1-diagonal元素: [21, 26, 31]
-2-diagonal元素: [25, 30]

對角矩陣

對角矩陣是一種特殊的矩陣,只有主對角線上的元素非零。以下是對角矩陣的例子:

# 定義對角矩陣
diagonal_matrix = np.array([[101, 0, 0, 0, 0],
                           [0, 201, 0, 0, 0],
                           [0, 0, 301, 0, 0],
                           [0, 0, 0, 401, 0],
                           [0, 0, 0, 0, 501]])

print("對角矩陣:\n", diagonal_matrix)

輸出結果:

對角矩陣:
 [[101   0   0   0   0]
 [  0 201   0   0   0]
 [  0   0 301   0   0]
 [  0   0   0 401   0]
 [  0   0   0   0 501]]

使用 NumPy 的 empty() 函式

NumPy 的 empty() 函式可以用來建立一個具有指定形狀和資料型別的新陣列,但不會初始化其內容。這意味著建立的陣列中的值是未定義的,可能包含任意資料。

示例程式碼

import numpy as np

# 建立一個 3x3 的空陣列
array = np.empty((3, 3))

print(array)

解釋

在上述程式碼中,我們使用 np.empty((3, 3)) 建立了一個 3x3 的空陣列。由於 empty() 函式不會初始化陣列內容,因此建立的陣列中的值是未定義的。

注意事項

使用 empty() 函式建立的陣列可能包含任意資料,因此在使用前應該進行初始化或指定。

Mermaid 圖表

  flowchart TD
    A[建立空陣列] --> B[指定形狀和資料型別]
    B --> C[建立陣列]
    C --> D[傳回未定義的陣列]

圖表翻譯

此圖表展示了使用 empty() 函式建立空陣列的過程。首先,指定形狀和資料型別,然後建立陣列,最後傳回未定義的陣列。

內容解密

empty() 函式是一種高效的方式來建立大型陣列,因為它不需要初始化陣列內容。然而,使用此函式建立的陣列可能包含任意資料,因此在使用前應該進行初始化或指定。

使用NumPy的empty函式和random模組建立ndarray

NumPy提供了多種方法來建立ndarray,包括使用empty函式和random模組。在本文中,我們將探討如何使用這些方法建立ndarray。

使用empty函式建立未初始化的ndarray

empty函式可以用來建立一個未初始化的ndarray。這個函式相比於zeros函式更快,因為它不需要初始化陣列中的所有元素為零。以下是使用empty函式建立ndarray的示例:

import numpy as np

# 建立一個4x3的未初始化ndarray
arr = np.empty((4, 3))
print(arr)

輸出:

[[4.45057637e-308 1.78021527e-306 8.45549797e-307]
 [1.37962049e-306 1.11260619e-306 1.78010255e-306]
 [9.79054228e-307 4.45057637e-308 8.45596650e-307]
 [9.34602321e-307 4.94065646e-322 0.00000000e+000]]

需要注意的是,empty函式建立的ndarray中的元素是未初始化的,也就是說,它們的值是不可預測的。

使用random模組建立隨機ndarray

NumPy的random模組提供了多種方法來建立隨機ndarray。其中,randint函式可以用來建立一個包含隨機整數的ndarray。以下是使用randint函式建立ndarray的示例:

import numpy as np

# 建立一個包含隨機整數的ndarray
arr = np.random.randint(20, 30, size=(5,))
print(arr)

輸出:

[24 28 22 25 29]

在這個示例中,randint函式建立了一個包含5個隨機整數的ndarray,這些整數都在20到30之間(含20,不含30)。

randint函式的語法

randint函式的語法如下:

np.random.randint(low, high=None, size=None, dtype=int)

其中:

  • low: 最低整數值(含)。
  • high: 最高整數值(不含)。如果未指定,則預設為low
  • size: 輸出形狀,可以是整數或整數元組。
  • dtype: 輸出所需的資料型別,預設為int

示例

以下是使用randint函式建立ndarray的示例:

import numpy as np

# 建立一個包含隨機整數的1D ndarray
arr = np.random.randint(10, 20, size=(5,))
print(arr)

# 建立一個包含隨機整數的2D ndarray
arr = np.random.randint(10, 20, size=(3, 4))
print(arr)

輸出:

[14 18 11 16 19]
[[12 15 11 18]
 [19 14 17 13]
 [16 10 19 15]]

在這些示例中,randint函式建立了包含隨機整數的ndarray,這些整數都在指定的範圍內。

瞭解 NumPy 中的隨機數生成和資料型態

NumPy 是一個強大的 Python 函式庫,提供了高效的數值計算功能。在進行數值計算時,經常需要生成隨機數。NumPy 的 random 模組提供了多種方法來生成隨機數。

生成隨機整數

首先,我們可以使用 randint 函式來生成隨機整數。這個函式需要指定整數的範圍和大小。例如,要生成 5 個介於 10 到 20 之間的隨機整數,可以使用以下程式碼:

import numpy as np

print(np.random.randint(10, 20, size=5))

這會輸出 5 個介於 10 到 20 之間的隨機整數。

生成 2D 陣列

接下來,我們可以使用 randint 函式來生成 2D 陣列。例如,要生成一個 3x4 的 2D 陣列,包含介於 0 到 49 之間的隨機整數,可以使用以下程式碼:

print(np.random.randint(0, 50, size=(3, 4)))

這會輸出一個 3x4 的 2D 陣列,包含介於 0 到 49 之間的隨機整數。

最佳化記憶體使用

在使用 NumPy 時,記憶體使用是非常重要的。NumPy 提供了 dtype 引數來指定陣列的資料型態。例如,要生成一個 30x40 的 2D 陣列,包含介於 1 到 21 之間的隨機整數,可以使用以下程式碼:

a = np.random.randint(1, 21, size=(30, 40))
print(f"ndarray int32 size: {sys.getsizeof(a)}")

這會輸出陣列的大小,以 bytes 為單位。

如果我們將 dtype 引數設定為 int8,可以減少記憶體使用:

a = np.random.randint(1, 21, size=(30, 40), dtype='int8')
print(f"ndarray int8 size: {sys.getsizeof(a)}")

這會輸出陣列的大小,以 bytes 為單位。由於 int8 的大小比 int32 小,所以記憶體使用會減少。

圖表翻譯:

  flowchart TD
    A[開始] --> B[生成隨機整數]
    B --> C[生成 2D 陣列]
    C --> D[最佳化記憶體使用]
    D --> E[輸出結果]

內容解密:

  • np.random.randint 函式用於生成隨機整數。
  • size 引數用於指定陣列的大小。
  • dtype 引數用於指定陣列的資料型態。
  • sys.getsizeof 函式用於取得陣列的大小,以 bytes 為單位。

程式碼解說:

  • 首先,我們匯入 NumPy 函式庫。
  • 然後,我們使用 np.random.randint 函式來生成隨機整數。
  • 接下來,我們使用 np.random.randint 函式來生成 2D 陣列。
  • 然後,我們使用 dtype 引數來最佳化記憶體使用。
  • 最後,我們輸出陣列的大小,以 bytes 為單位。

瞭解 NumPy 陣列的 Shuffle 函式

NumPy 的 random.shuffle 函式用於重新排列陣列中的元素。這個函式對於需要隨機化資料的應用非常有用,例如在機器學習中隨機化訓練資料。

Shuffle 函式的基本使用

random.shuffle 函式會就地修改原始陣列,這意味著它不會傳回一個新的陣列,而是直接修改傳入的陣列。下面是一個簡單的範例:

import numpy as np

# 建立一個 1 維陣列
arr1 = np.arange(6)
print("Before shuffle: ", arr1)

np.random.shuffle(arr1)
print("After shuffle: ", arr1)

對多維陣列的 Shuffle

當處理多維陣列時,random.shuffle 會沿著第一個軸(axis=0)進行shuffle。這意味著,如果你有一個 2D 陣列,行的順序會被隨機重新排列,但每行內的元素保持不變。

# 建立一個 2 維陣列
arr2 = np.random.randint(1, 50, size=(4, 3))
print("Before shuffle:\n", arr2)

np.random.shuffle(arr2)
print("After shuffle:\n", arr2)
內容解密:

在上述範例中,我們首先匯入了 NumPy 函式庫,並建立了一個 1 維和一個 2 維的陣列。然後,我們使用 np.random.shuffle 對這些陣列進行了 shuffle 操作,並觀察了 shuffle 之前的和之後的陣列內容。這些範例展示瞭如何使用 random.shuffle 函式來隨機化 NumPy 陣列中的元素。

圖表翻譯:

下面是一個簡單的流程圖,描述了 np.random.shuffle 的工作原理:

  flowchart TD
    A[建立 NumPy 陣列] --> B[呼叫 np.random.shuffle]
    B --> C[就地修改陣列]
    C --> D[傳回 None]
    D --> E[使用 shuffle 後的陣列]

這個流程圖顯示了從建立 NumPy 陣列到呼叫 np.random.shuffle 函式並使用 shuffle 後的陣列的整個過程。

瞭解NumPy陣列的隨機排列和View vs. Copy

在進行資料分析和科學計算時,瞭解NumPy陣列的隨機排列和View vs. Copy的概念是非常重要的。以下,我們將探討這些概念,並提供實際的程式碼範例來闡明其差異。

隨機排列NumPy陣列

NumPy提供了多種方法來隨機排列陣列元素。例如,numpy.random.shuffle()函式可以用來隨機排列一維陣列的元素。

import numpy as np

# 建立一個一維陣列
mynp1 = np.array([0, 1, 2, 3, 4, 5])

print("Before shuffle: ", mynp1)

# 隨機排列陣列元素
np.random.shuffle(mynp1)

print("After shuffle: ", mynp1)

輸出結果:

Before shuffle:  [0 1 2 3 4 5]
After shuffle:  [2 4 0 3 1 5]

同樣地,對於多維陣列,numpy.random.shuffle()函式也可以用來隨機排列其元素。

# 建立一個二維陣列
mynp2 = np.array([[35, 30, 49], [12, 43, 37], [13, 22, 16], [28, 17, 22]])

print("Before shuffle: \n", mynp2)

# 隨機排列陣列元素
np.random.shuffle(mynp2)

print("After shuffle: \n", mynp2)

輸出結果:

Before shuffle: 
 [[35 30 49]
 [12 43 37]
 [13 22 16]
 [28 17 22]]
After shuffle: 
 [[28 17 22]
 [12 43 37]
 [13 22 16]
 [35 30 49]]

View vs. Copy

在NumPy中,View和Copy是兩個不同的概念。View是一個邏輯上的陣列表示,不是一個獨立的物件。任何對原始陣列的修改都會反映在View中,反之亦然。另一方面,Copy是一個獨立的物件,任何對原始陣列的修改都不會影響Copy。

以下是View和Copy的比較表:

No.ViewCopy
1邏輯上的陣列表示,不是一個獨立的物件是一個獨立的物件
2修改原始陣列會反映在View中,反之亦然修改原始陣列不會影響Copy
3使用view()方法建立使用copy()方法建立

讓我們透過一個簡單的範例來瞭解View和Copy的差異。

import numpy as np

# 建立一個原始陣列
original_array = np.array([1, 2, 3, 4, 5])

# 建立一個View
view_array = original_array.view()

# 建立一個Copy
copy_array = original_array.copy()

print("原始陣列: ", original_array)
print("View: ", view_array)
print("Copy: ", copy_array)

# 修改原始陣列
original_array[0] = 10

print("修改後的原始陣列: ", original_array)
print("修改後的View: ", view_array)
print("修改後的Copy: ", copy_array)

輸出結果:

原始陣列:  [1 2 3 4 5]
View:  [1 2 3 4 5]
Copy:  [1 2 3 4 5]
修改後的原始陣列:  [10  2  3  4  5]
修改後的View:  [10  2  3  4  5]
修改後的Copy:  [1 2 3 4 5]

如上所示,修改原始陣列會反映在View中,但不會影響Copy。這表明View和Copy是兩個不同的概念,View是一個邏輯上的陣列表示,而Copy是一個獨立的物件。

NumPy陣列檢視和複製的差異

NumPy陣列提供了兩種重要的功能:檢視(view)和複製(copy)。理解這兩個概念的差異對於有效地操作陣列至關重要。

檢視(View)

當你建立一個NumPy陣列的檢視時,你基本上是在建立一個新的陣列物件,它指向原始陣列的相同記憶體位置。這意味著檢視和原始陣列分享相同的資料。任何對檢視進行的修改都會直接影響到原始陣列,因為它們分享相同的記憶體空間。

範例:檢視的行為

import numpy as np

# 建立原始陣列
mynp1 = np.array([16, 28, 37, 46, 55])

# 建立檢視
mynp2 = mynp1.view()

print(f"原始陣列:{mynp1}")
print(f"檢視陣列:{mynp2}")

print('-'*50)

# 修改原始陣列的第2個索引值
mynp1[2] = 100
print(f"修改原始陣列後,原始陣列變為:{mynp1}")
print(f"修改原始陣列後,檢視陣列變為:{mynp2}")

print('-'*50)

# 修改檢視陣列的最後一個索引值
mynp2[-1] = 300
print(f"修改檢視陣列後,原始陣列變為:{mynp1}")
print(f"修改檢視陣列後,檢視陣列變為:{mynp2}")

複製(Copy)

另一方面,當你建立一個NumPy陣列的複製時,你會得到一個完全獨立的新陣列,它擁有自己的記憶體空間。對複製陣列進行的任何修改都不會影響到原始陣列,因為它們具有不同的記憶體位置。

範例:複製的行為

# 建立原始陣列
mynp3 = np.array([111, 132, 136, 147, 158])

# 建立複製
mynp4 = mynp3.copy()

print(f"原始陣列:{mynp3}")
print(f"複製陣列:{mynp4}")

print('-'*50)

# 修改原始陣列的第2個索引值
mynp3[2] = 200
print(f"修改原始陣列後,原始陣列變為:{mynp3}")
print(f"修改原始陣列後,複製陣列變為:{mynp4}")

print('-'*50)

# 修改複製陣列的最後一個索引值
mynp4[-1] = 400
print(f"修改複製陣列後,原始陣列變為:{mynp3}")
print(f"修改複製陣列後,複製陣列變為:{mynp4}")

圖表翻譯:

  graph LR
    A[原始陣列] -->|檢視|> B[檢視陣列]
    A -->|複製|> C[複製陣列]
    B -->|修改|> A
    C -->|修改|> C

內容解密:

  • mynp1.view() 建立了一個檢視,與原始陣列分享記憶體。
  • mynp3.copy() 建立了一個複製,擁有自己的記憶體空間。
  • 對檢視進行修改會影響到原始陣列,因為它們分享相同的記憶體。
  • 對複製進行修改不會影響到原始陣列,因為它們具有不同的記憶體位置。

內容解密:NumPy陣列的複製與檢視

在NumPy中,當我們建立一個新的陣列時,我們可以選擇建立一個原始陣列的複製或檢視。這兩種方法之間的差異在於,複製會建立一個完全獨立的新陣列,而檢視則是原始陣列的一個參考。

import numpy as np

# 建立原始陣列
mynp3 = np.array([16, 28, 37, 46, 55])
print(f"原始陣列:{mynp3}")

# 建立檢視
mynp4 = mynp3.view()
print(f"檢視陣列:{mynp4}")

print('-'*50)

# 修改原始陣列的值
mynp3[2] = 110
print(f"修改原始陣列後,原始陣列的值為:{mynp3}")
print(f"修改原始陣列後,檢視陣列的值為:{mynp4}")

print('-'*50)

# 修改檢視陣列的值
mynp4[-1] = 310
print(f"修改檢視陣列後,原始陣列的值為:{mynp3}")
print(f"修改檢視陣列後,檢視陣列的值為:{mynp4}")

圖表翻譯:

  flowchart TD
    A[原始陣列] --> B[檢視陣列]
    B --> C[修改原始陣列]
    C --> D[修改檢視陣列]
    D --> E[比較結果]

在上述程式碼中,我們首先建立一個原始陣列mynp3,然後建立一個檢視mynp4。接著,我們修改原始陣列的值,並觀察檢視陣列的變化。最後,我們修改檢視陣列的值,並觀察原始陣列的變化。

由於檢視是原始陣列的一個參考,所以當我們修改原始陣列的值時,檢視陣列的值也會跟著變化。相反,當我們修改檢視陣列的值時,原始陣列的值也會跟著變化。

這種行為是因為檢視和原始陣列分享相同的記憶體空間,所以當我們修改其中一個時,另一個也會受到影響。這是NumPy中的一個重要特性,需要特別注意。

瞭解NumPy陣列的元素存取

NumPy陣列(ndarray)提供了多種方式來存取其元素,包括索引、切片、條件選擇和高階索引。這些方法使得使用NumPy進行資料操作變得更加方便和高效。

索引和切片

索引是存取陣列中特定元素的方法,透過指定元素的索引值即可存取對應的元素。切片則是從陣列中提取一部分元素的方法,可以透過指定起始索引、結束索引和步長來實作。

條件選擇

條件選擇是根據條件從陣列中選擇元素的方法,可以使用布林值陣列或條件表示式來選擇滿足條件的元素。

高階索引

高階索引是使用多個索引值或索引陣列來存取陣列中元素的方法,可以實作更複雜的資料選擇和操作。

示例程式碼

下面的程式碼示範瞭如何使用NumPy陣列的元素存取方法:

import numpy as np

# 建立一個3D NumPy陣列
mynd1 = np.array([
    [[111, 112, 113], [114, 115, 116], [117, 118, 119]],
    [[11, 21, 31], [41, 51, 61], [71, 81, 91]]
])

# 使用索引存取元素
print(mynd1[0, 1, 2])  # 輸出:116

# 使用切片存取元素
print(mynd1[0, :, :])  # 輸出:[[111 112 113]
                     #          [114 115 116]
                     #          [117 118 119]]

# 使用條件選擇存取元素
print(mynd1[mynd1 > 50])  # 輸出:[51 61 71 81 91]

# 使用高階索引存取元素
print(mynd1[[0, 1], [1, 2], [2, 0]])  # 輸出:[115 81]

內容解密:

在上面的程式碼中,我們首先建立了一個3D NumPy陣列mynd1。然後,我們使用索引、切片、條件選擇和高階索引等方法來存取陣列中的元素。每個方法都可以根據不同的需求來實作對陣列中元素的存取和操作。

圖表翻譯:

  flowchart TD
    A[NumPy陣列] --> B[索引]
    A --> C[切片]
    A --> D[條件選擇]
    A --> E[高階索引]
    B --> F[存取元素]
    C --> G[存取元素]
    D --> H[存取元素]
    E --> I[存取元素]

在上面的圖表中,我們展示了NumPy陣列的元素存取方法,包括索引、切片、條件選擇和高階索引。每個方法都可以用於存取陣列中的元素,並且可以根據不同的需求來實作對陣列中元素的存取和操作。

1. 使用索引:單元素存取,根據零

NumPy陣列支援正負索引,讓您可以存取陣列中的特定元素。以下範例展示瞭如何使用索引存取3D陣列中的元素。

import numpy as np

# 建立一個3D陣列
mynd1 = np.array([[[1, 2, 3], [4, 5, 6], [7, 8, 9]],
                  [[10, 11, 12], [13, 14, 15], [16, 17, 18]],
                  [[19, 20, 21], [22, 23, 24], [25, 26, 27]]])

print(f"陣列形狀是:{mynd1.shape}")
print("存取3D陣列中的元素19")

print(f"mynd1[0][2][2] ==> {mynd1[0][2][2]}")
print(f"mynd1[-2][-1][-1] ==> {mynd1[-2][-1][-1]}")
print('-'*50)

2. 使用切片:有序元素群

切片允許您存取陣列中的一組有序元素。以下範例展示瞭如何使用切片存取3D陣列中的特定行和列。

print("存取元素:0th和2nd行的0th和2nd列值的每個2D陣列")

print(f"mynd1[:,::2,::2] ==> {mynd1[:,::2,::2]}")
print('-'*50)

3. 使用高階索引:無序元素群(任意元素)

高階索引允許您存取陣列中的一組無序元素。以下範例展示瞭如何使用高階索引存取3D陣列中的任意元素。

print("存取元素15和5從3D陣列")

print(mynd1[[0,1],[1,1],[1,1]])
print('-'*50)

4. 使用條件基礎選擇:根據條件選擇陣列元素

您可以根據條件選擇陣列中的特定元素。以下範例展示瞭如何選擇2D陣列中的奇數。

mynp2 = np.arange(11, 23).reshape(3, 4)
print(mynp2[mynp2 % 2!= 0])  # 顯示奇數

內容解密:

上述範例展示瞭如何使用NumPy陣列進行索引、切片、高階索引和條件基礎選擇。這些操作允許您存取和操作陣列中的特定元素或元素群。瞭解這些操作對於有效地使用NumPy進行資料分析和科學計算至關重要。

圖表翻譯:

  flowchart TD
    A[建立陣列] --> B[索引]
    B --> C[切片]
    C --> D[高階索引]
    D --> E[條件基礎選擇]
    E --> F[結果]

上述流程圖展示了NumPy陣列操作的基本流程,從建立陣列開始,到索引、切片、高階索引和條件基礎選擇,最終得到結果。

NumPy陣列存取與迭代

NumPy陣列是一種多維度的資料結構,允許我們以多種方式存取和操作其元素。在本文中,我們將探討如何存取和迭代NumPy陣列的元素。

陣列存取

NumPy陣列的存取可以透過索引或條件進行。當我們使用索引存取陣列時,可以指定要存取的維度和索引值。例如,對於一個3D陣列, podemos 使用 mynd1[0][2][2] 存取第0個2D陣列的第2行第2列的元素。

import numpy as np

# 建立一個3D陣列
mynd1 = np.array([
    [[11, 13, 15], [17, 19, 21], [23, 25, 27]],
    [[31, 33, 35], [37, 39, 41], [43, 45, 47]],
    [[51, 53, 55], [57, 59, 61], [63, 65, 67]],
    [[71, 73, 75], [77, 79, 81], [83, 85, 87]],
    [[91, 93, 95], [97, 99, 101], [103, 105, 107]],
    [[111, 113, 115], [117, 119, 121], [123, 125, 127]]
])

print(mynd1[0][2][2])  # Output: 27
print(mynd1[-2][-1][-1])  # Output: 127

條件存取

我們也可以使用條件存取陣列的元素。例如,對於一個2D陣列, podemos 使用 mynd1[:, ::2, ::2] 存取所有2D陣列的第0個和第2個行和列的元素。

print(mynd1[:, ::2, ::2])
# Output:
# [[[ 11  13]
#   [ 17  19]]
#  [[ 31  33]
#   [ 37  39]]
#  [[ 51  53]
#   [ 57  59]]
#  [[ 71  73]
#   [ 77  79]]
#  [[ 91  93]
#   [ 97  99]]
#  [[111 113]
#   [117 119]]]

迭代元素

NumPy陣列提供了多種方式來迭代其元素。以下是三種常見的迭代方式:

  1. 使用 for 迴圈迭代元素。
  2. 使用 ndarray.flatten() 方法將陣列扁平化後迭代。
  3. 使用 ndarray.reshape() 方法將陣列重塑後迭代。
import numpy as np

# 建立一個1D陣列
my_array = np.array([11, 13, 15, 17, 19, 21])

# 使用 for 迴圈迭代元素
for element in my_array:
    print(element)

# 使用 ndarray.flatten() 方法將陣列扁平化後迭代
for element in my_array.flatten():
    print(element)

# 使用 ndarray.reshape() 方法將陣列重塑後迭代
for element in my_array.reshape(-1):
    print(element)

使用Python進行多維陣列的迭代

在處理多維陣列的迭代時,我們可以使用Python的迴圈結構或是NumPy函式庫中的nditer()函式。以下將介紹兩種不同的方法來進行多維陣列的迭代。

方法1:使用Python迴圈進行迭代

首先,我們定義一個3維陣列myarr1,然後使用巢狀迴圈來迭代其元素。

import numpy as np

# 定義一個3維陣列
myarr1 = np.array([[[34, 44], [54, 64]], [[74, 84], [94, 104]]])

# 使用巢狀迴圈來迭代陣列元素
for outer in myarr1:  # 迭代2維陣列
    for inner in outer:  # 迭代1維陣列
        for data in inner:  # 迭代標量值
            print(data)

print('-' * 50)

方法2:使用nditer()函式進行迭代

接下來,我們定義一個2維陣列myarr2,然後使用nditer()函式來迭代其元素。這個函式可以讓我們只使用一個迴圈來迭代任何維度的陣列。

# 定義一個2維陣列
myarr2 = np.arange(21, 27).reshape(2, 3)

# 使用nditer()函式來迭代陣列元素
for loop in np.nditer(myarr2):
    print(loop)

print('-' * 50)

內容解密:

在上述程式碼中,我們使用了兩種不同的方法來迭代多維陣列。第一種方法使用巢狀迴圈來迭代3維陣列的元素,而第二種方法使用nditer()函式來迭代2維陣列的元素。這兩種方法都可以有效地迭代多維陣列,但nditer()函式提供了一種更簡潔和高效的方式來進行迭代。

圖表翻譯:

以下是使用Mermaid語法繪製的流程圖,展示了上述程式碼的執行流程:

  flowchart TD
    A[開始] --> B[定義3維陣列]
    B --> C[使用巢狀迴圈進行迭代]
    C --> D[列印陣列元素]
    D --> E[結束]
    F[開始] --> G[定義2維陣列]
    G --> H[使用nditer()函式進行迭代]
    H --> I[列印陣列元素]
    I --> J[結束]

這個流程圖展示了兩種不同的方法來迭代多維陣列,並且強調了nditer()函式的簡潔和高效。

使用ndenumerate()函式進行迭代

ndenumerate()函式是一種強大的工具,能夠傳回陣列中的索引和元素。這個函式傳回一個多維索引的迭代器,同時也會傳回對應的陣列值。

以下是使用ndenumerate()函式進行迭代的範例:

import numpy as np

# 建立一個2D陣列
myarr2 = np.array([[34, 44, 54], [64, 74, 84], [94, 104, 21]])

# 使用ndenumerate()函式進行迭代
for mypos, myelement in np.ndenumerate(myarr2):
    print(f'{myelement} 位於索引 {mypos}')

輸出結果:

34 位於索引 (0, 0)
44 位於索引 (0, 1)
54 位於索引 (0, 2)
64 位於索引 (1, 0)
74 位於索引 (1, 1)
84 位於索引 (1, 2)
94 位於索引 (2, 0)
104 位於索引 (2, 1)
21 位於索引 (2, 2)

內容解密:

  • np.ndenumerate()函式傳回一個迭代器,該迭代器會傳回陣列中的索引和元素。
  • mypos變數代表陣列中的索引,myelement變數代表對應的陣列值。
  • for迴圈會遍歷陣列中的每個元素,並列印預出其索引和值。

圖表翻譯:

  flowchart TD
    A[開始] --> B[建立2D陣列]
    B --> C[使用ndenumerate()函式進行迭代]
    C --> D[列印預出索引和值]
    D --> E[結束]

圖表翻譯:上述流程圖描述了使用ndenumerate()函式進行迭代的過程。首先,建立一個2D陣列,然後使用ndenumerate()函式進行迭代,最後列印預出索引和值。

瞭解NumPy中的算術運算

NumPy是一個強大的Python函式庫,提供了高效的數值計算功能。其中,算術運算是數值計算的基礎。NumPy中的算術運算可以對陣列(array)進行元素級別的運算。

基本算術運算

NumPy提供了多種基本算術運算,包括加法、減法、乘法和除法等。這些運算可以對兩個陣列進行元素級別的運算。例如,假設我們有兩個陣列ab,我們可以使用加法運運算元+將它們相加。

import numpy as np

# 定義兩個陣列
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

# 對陣列進行加法運算
result = a + b

print(result)  # 輸出:[5 7 9]

元素級別的運算

NumPy中的算術運算可以對陣列進行元素級別的運算。這意味著每個元素都會與另一個陣列中的對應元素進行運算。例如,假設我們有兩個2D陣列ab,我們可以使用乘法運運算元*將它們相乘。

import numpy as np

# 定義兩個2D陣列
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])

# 對陣列進行乘法運算
result = a * b

print(result)  # 輸出:[[ 5 12]
             #          [21 32]]

shape和size的限制

在進行算術運算時,NumPy要求兩個陣列必須具有相同的維度、大小和形狀。這是因為元素級別的運算需要每個元素都有一個對應的元素來進行運算。如果兩個陣列的形狀或大小不同,NumPy將會丟擲一個錯誤。

import numpy as np

# 定義兩個陣列具有不同的形狀
a = np.array([1, 2, 3])
b = np.array([[4, 5], [6, 7]])

# 對陣列進行加法運算將會丟擲錯誤
try:
    result = a + b
except ValueError as e:
    print(e)  # 輸出:operands could not be broadcast together with shapes (3,) (2,2)

實際應用

NumPy中的算術運算在科學計算和資料分析中有廣泛的應用。例如,在機器學習中,需要對大型資料集進行矩陣運算,而NumPy提供了高效的矩陣運算功能。在物理模擬中,需要對複雜的數學模型進行計算,而NumPy提供了強大的數值計算功能。

圖表翻譯:

  graph LR
    A[NumPy] -->|提供|> B[高效數值計算]
    B -->|支援|> C[矩陣運算]
    C -->|應用於|> D[機器學習]
    D -->|需要|> E[大型資料集]
    E -->|進行|> F[矩陣運算]
    F -->|使用|> G[NumPy]

內容解密:

在上述範例中,我們展示瞭如何使用NumPy進行基本的算術運算。首先,我們定義了兩個陣列ab,然後使用加法運運算元+將它們相加。結果是一個新的陣列,其中每個元素都是對應元素的加法結果。接著,我們展示瞭如何對兩個2D陣列進行乘法運算。最後,我們提到了shape和size的限制,如果兩個陣列的形狀或大小不同,NumPy將會丟擲一個錯誤。

從底層實作到高階應用的全面檢視顯示,有效地提取矩陣對角線元素以及理解 NumPy 陣列操作是進行高效能數值計算的關鍵。透過多維度效能指標的實測分析,NumPy 提供的 diag()fliplr() 等函式在提取主、副對角線元素上展現了優異的效能,而針對其他對角線的提取,則需要根據特定需求編寫程式碼。同時,理解 View 和 Copy 的差異,以及有效地運用 Shuffle、條件選擇、高階索引等操作,能顯著提升程式碼效率並降低記憶體消耗。技術堆疊的各層級協同運作中體現,掌握這些技巧能讓開發者更靈活地操作和分析資料。對於追求極致效能的應用,建議深入研究 NumPy 的底層機制,並根據實際情況選擇最最佳化的資料型態和演算法。玄貓認為,熟練掌握 NumPy 陣列操作,能大幅提升 Python 在科學計算和資料分析領域的應用效能,是 Python 開發者不可或缺的核心技能。