Code so sánh 2 ma trận matlab năm 2024

Tất cả các bài tập trong bài viết này có thể được thực hiện trực tiếp trên trình duyệt qua trang web FundaML

2.0. Mảng nhiều chiều

Trong Numpy, người ta thường dùng mảng numpy hai chiều để thể hiện một ma trận. Mảng hai chiều có thể coi là một mảng của các mảng một chiều. Trong đó, mỗi mảng nhỏ một chiều tương ứng với một hàng của ma trận.

Nói cách khác, ma trận có thể được coi là mảng của các vector hàng - mỗi vector hàng được biểu diễn bằng một mảng numpy một chiều.


Code so sánh 2 ma trận matlab năm 2024


Ví dụ, nếu một mảng numpy hai chiều

array([[ 0.,  1.,  0.],
       [ 0.,  0.,  1.],
       [ 0.,  0.,  0.]])
np.eye(4, k= -2) array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 1., 0., 0., 0.], [ 0., 1., 0., 0.]])

8 mô tả ma trận: \(\left[ \begin{matrix} 1 & 2 \\ 3 & 4 \end{matrix} \right] \), khi được in ra nó sẽ có dạng:

Ở đây chúng ta có thể nhìn thấy ba mảng, mỗi mảng được thể hiện bằng một cặp đóng mở ngoặc vuông

array([[ 0.,  1.,  0.],
       [ 0.,  0.,  1.],
       [ 0.,  0.,  0.]])
np.eye(4, k= -2) array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 1., 0., 0., 0.], [ 0., 1., 0., 0.]])

9:

  • hai mảng `
    > np.diag([1, 3, 4])

    array([[1, 0, 0],

       [0, 3, 0],  
       [0, 0, 4]])  
    np.diag(np.diag([1, 3, 4]))
    array([1, 3, 4])

    0 và

    np.diag([1, 3, 4])

    array([[1, 0, 0],

       [0, 3, 0],  
       [0, 0, 4]])  
    
    np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

    1 thể hiện các hàng của ma trận. Chúng là các mảng một chiều.
  • mảng

    np.diag([1, 3, 4]) array([[1, 0, 0],

       [0, 3, 0],  
       [0, 0, 4]])  
    
    np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

    ` 2 có hai phân tử, mỗi phần tử là một hàng của ma trận.

Theo quy ước của Numpy, chúng ta cần đi từ mảng ngoài cùng tới các mảng trong:

  • mảng lớn nhất là `
    > np.diag([1, 3, 4])

    array([[1, 0, 0],

       [0, 3, 0],  
       [0, 0, 4]])  
    np.diag(np.diag([1, 3, 4]))
    array([1, 3, 4])

    2 được coi là mảng ứng với

    np.diag([1, 3, 4])

    array([[1, 0, 0],

       [0, 3, 0],  
       [0, 0, 4]])  
    
    np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

    4. Trong mảng này, thành phần thứ nhất là

    np.diag([1, 3, 4]) array([[1, 0, 0],

       [0, 3, 0],  
       [0, 0, 4]])  
    
    np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

    0, thành phần thứ hai là

    np.diag([1, 3, 4]) array([[1, 0, 0],

       [0, 3, 0],  
       [0, 0, 4]])  
    
    np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

    1.
  • hai mảng lớn thứ hai là

    np.diag([1, 3, 4]) array([[1, 0, 0],

       [0, 3, 0],  
       [0, 0, 4]])  
    
    np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

    0 và

    np.diag([1, 3, 4]) array([[1, 0, 0],

       [0, 3, 0],  
       [0, 0, 4]])  
    
    np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

    1 được coi là các mảng ứng với

    np.diag([1, 3, 4]) array([[1, 0, 0],

       [0, 3, 0],  
       [0, 0, 4]])  
    
    np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

    ` 9.

(Xem thêm hình vẽ bên.)

Chú ý:

  1. Một mảng numpy hoàn toàn có thể có nhiều hơn hai chiều. Khi đó ta vẫn đi từ cặp ngoặc vuông ngoài cùng vào tới trong cùng, `
    > a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    a

    array([[1, 2, 3],

       [4, 5, 6],  
       [7, 8, 9]])  
    np.diag(a, k = 1)
    array([2, 6])

    0 cũng đi từ

    a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) a array([[1, 2, 3],

       [4, 5, 6],  
       [7, 8, 9]])  
    
    np.diag(a, k = 1) array([2, 6])

    ` 1 theo thứ tự đó.
  2. Mỗi mảng con phải có số phần tử bằng nhau, thể hiện cho việc mỗi hàng của ma trận phải có số chiều như nhau, không có hàng nào thò ra thụt vào.
  3. Khi làm việc với các thư viện cho Machine Learning, mỗi điểm dữ liệu thường được coi là một mảng một chiều. Tập hợp các điểm dữ liệu thường được lưu trong một ma trận - tức mảng của các mảng một chiều. Trong ma trận này, mỗi hàng tương ứng với một điểm dữ liệu.

Việc này hơi ngược với cách xây dựng toán học của các thuật toán, nơi mà mỗi điểm dữ liệu thường được coi là một vector cột - tức mỗi cột của ma trận là một điểm dữ liệu. Khi đọc các tài liệu và làm việc với các thư viện, bạn đọc cần chú ý.

Giống như bài “Cơ bản về vector”, trong bài học này, chúng ta sẽ cùng làm quen với các cách xử lý ma trận trong Numpy: Khởi tạo, truy cập, thay đổi, ma trận đặc biệt, …

2.1. Khởi tạo một ma trận

2.1.1. Khởi tạo một ma trận

Cách đơn giản nhất để khởi tạo một ma trận là nhập vào từng phần tử của ma trận đó. Cách làm này, tất nhiên, chỉ phù hợp với các ma trận nhỏ.

array([[1, 2],
       [3, 4]])

Nếu bạn mới chuyển từ Matlab qua Python, bạn sẽ thấy cách khai báo của Matlab dễ chịu hơn rất nhiều. Chúng ta sẽ phải quen dần thôi :).

Khi khai báo một mảng numpy nói chung, nếu ít nhất một phần tử của mảng là

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
np.diag(a, k = 1) array([2, 6])

2,

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
np.diag(a, k = 1) array([2, 6])

3 của mọi phần tử trong mảng sẽ được coi là

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
np.diag(a, k = 1) array([2, 6])

4 (số thực 64 bit).

Ngược lại, nếu toàn bộ các phần tử là số nguyên (không có dấu

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
np.diag(a, k = 1) array([2, 6])

5 xuất hiện),

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
np.diag(a, k = 1) array([2, 6])

3 của mọi phần tử trong mảng sẽ được coi là

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
np.diag(a, k = 1) array([2, 6])

7 (số nguyên 64 bit).

Nếu muốn chỉ định

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
np.diag(a, k = 1) array([2, 6])

3 của các phần tử trong mảng, ta cần đặt giá trị cho

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
np.diag(a, k = 1) array([2, 6])

9. Ví dụ:

<type 'numpy.float64'>


Bài tập:

Khai báo một mảng numpy hai chiều

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0 mô tả ma trận:

\[\mathbf{A} = \left[ \begin{matrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{matrix} \right] \]


2.2. Ma trận đơn vị và ma trận đường chéo

2.2.1. Ma trận đơn vị

Để tạo một ma trận đơn vị có số chiều bằng

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

1 (ma trận đơn vị là một ma trận vuông có tất cả các phần tử trên đường chéo bằng 1), chúng ta sử dụng hàm

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

2:

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

Hàm

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

2 cũng được dùng để tạo các ma trận toàn 1 ở một đường chéo phụ nào đó, các thành phần còn lại bằng 0. Ví dụ:

array([[ 0.,  1.,  0.],
       [ 0.,  0.,  1.],
       [ 0.,  0.,  0.]])
np.eye(4, k= -2) array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 1., 0., 0., 0.], [ 0., 1., 0., 0.]])
array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

4 sẽ tương ứng với đường chéo phụ ngay trên đường chéo chíh.

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

5 sẽ tương ứng với đường chéo phụ thứ hai bên dưới đường chéo chính.

Bạn đọc có thể đọc thêm về cách sử dụng hàm ‘np.eye()’ tại đây.

Xin nhắc lại rằng bạn đọc luôn có thể xem cách sử dụng một hàm trên terminal bằng cách gõ

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

6 trong đó

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

7 là tên hàm bạn muốn tra cứu. Ví dụ,

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

8.

2.2.2. Ma trận đường chéo

Để khai báo một ma trận đường chéo, hoặc muốn trích xuất đường chéo của một ma trận, ta dùng hàm

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

9.

array([[1, 0, 0],
       [0, 3, 0],
       [0, 0, 4]])
np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

  • Nếu đầu vào là một mảng một chiều, trả về một mảng hai chiều thể hiện ma trận có đường chéo là các phần tử thuộc mảng đó.
  • Nếu đầu vào là một mảng hai chiều (có thể không vuông), trả về mảng một chiều chứa các giá trị ở hàng thứ `
    > A.shape[0] 3
    A.shape[1]

    4

    0, cột thứ

    A.shape[0]

    3 A.shape[1] 4

    0 với

    A.shape[0] 3 A.shape[1] 4

    2. Trong đó

    A.shape[0] 3 A.shape[1] 4

    3,

    import numpy as np A = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) A array([[ 1, 2, 3, 4],

       [ 5,  6,  7,  8],  
       [ 9, 10, 11, 12]])  
    
    A.shape (3, 4)

    ` 1 lần lượt là số hàng và số cột của ma trận được biểu diễn bằng mảng hai chiều ban đầu.

Đường chéo phụ của một ma trận cũng có thể được lấy bằng cách sử dụng hàm này và chỉ ra giá trị của

3
A.shape[1] 4

5:

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
np.diag(a, k = 1) array([2, 6])


Bài tập:

Với một số tự nhiên

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

1, hãy viết hàm trả về ma trận có dạng: \[ \left[ \begin{matrix} 0 & 0 & 0 & 0 & \dots & 0 & 0 \\ 1 & 0 & 0 & 0 & \dots & 0 & 0 \\ 0 & 2 & 0 & 0 & \dots & 0 & 0 \\ \dots & \dots & \dots & \dots & \ddots & \dots \\ 0 & 0 & 0 & 0 & \dots & 0 & 0 \\ 0 & 0 & 0 & 0 & \dots & n & 0 \end{matrix} \right] \] tức đường chéo phụ ngay dưới đường chéo chính nhận các giá trị từ 1 đến \(n\). Các thành phần là kiểu số nguyên.


2.3. Kích thước của ma trận

Giống như cách tìm kích thước của mảng một chiểu, để tìm kích thước của mảng hai chiều, ta cũng sử dụng thuộc tính

3
A.shape[1] 4

7:

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

Ở đây, kết quả trả về là một

3
A.shape[1] 4

8. Số phần tử của tuple này chính là số chiều của mảng. Nếu coi mảng hai chiều như ma trận, số hàng và số cột của ma trận có thể được tính bằng:

3
A.shape[1] 4

Với mảng numpy nhiều chiều, ta cũng dùng thuộc tính

3
A.shape[1] 4

7 để tìm kích thước của mỗi chiều.

2.4. Truy cập vào từng phần tử của ma trận

2.4.1. Truy cập vào từng phần tử

Có hai cách để truy cập vào mỗi phần tử của mảng hai chiều:

2.4.1.1. Cách 1: giống với list

Để truy cập vào phần tử ở hàng thứ

3
A.shape[1] 4

0, cột thứ

6

1 của ma trận (chỉ số bắt đầu từ 0), ta có thể coi phần tử đó là phần tử thứ

6

1 của mảng

3
A.shape[1] 4

0 trong mảng hai chiều ban đầu.

Ví dụ:

6

ở đây

6

4 chính lả mảng một chiều

6

5, trong mảng này, ta lấy phần tử có chỉ số là

6

6, phần tử đó có giá trị là

6

7. Vậy

6

8 = 6.

2.4.1.2. Cách 2: giống như Matlab

Trong Matlab, để truy cập vào phần tử ở hàng đầu tiên, cột đầu tiên của một ma trận

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0, ta sử dụng

array([7, 8, 9])
A[0,:] array([1, 2, 3])

0. Trong Numpy, có một chút thay đổi:

  1. Chỉ số bắt đầu từ 0.
  2. Bộ chỉ số được đặt trong dấu ngoặc vuông `
    > np.eye(3, k = 1) array([[ 0., 1., 0.],
       [ 0.,  0.,  1.],  
       [ 0.,  0.,  0.]])  
    np.eye(4, k= -2)
    array([[ 0., 0., 0., 0.],
       [ 0.,  0.,  0.,  0.],  
       [ 1.,  0.,  0.,  0.],  
       [ 0.,  1.,  0.,  0.]])  
    
    ` 9.

Ví dụ

2.4.2. Truy cập vào hàng/cột

Để truy cập vào hàng có chỉ số

3
A.shape[1] 4

0 của một ma trận

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0, ta chỉ cần dùng

array([7, 8, 9])
A[0,:] array([1, 2, 3])

4 hoặc

array([7, 8, 9])
A[0,:] array([1, 2, 3])

5 hoặc

array([7, 8, 9])
A[0,:] array([1, 2, 3])

6:

array([7, 8, 9])
A[0,:] array([1, 2, 3])

Để truy cập vào cột có chỉ số

6

1, ta dùng

array([7, 8, 9])
A[0,:] array([1, 2, 3])

8:

<type 'numpy.float64'>

0

Chú ý:

  • Trong Numpy, kết quả trả về của một cột hay hàng đều là một mảng một chiều, không phải là một vector cột như trong Matlab. Tuy nhiên, khi lấy một ma trận nhân với nó, nó vẫn được coi là một vector cột. Thông tin chi tiết sẽ có trong các bài sau.
  • Nếu sử dụng `
    > A[2] array([7, 8, 9])
    A[0,:]

    array([1, 2, 3])

    9, kết quả trả về là hàng có chỉ số

    B = np.array([[1, 2, 3], [4, 5, 6]], dtype = np.float)

    type(B[0][0]) <type 'numpy.float64'>

    00 chứ không phải cột có chỉ số

    B = np.array([[1, 2, 3], [4, 5, 6]], dtype = np.float) type(B[0][0]) <type 'numpy.float64'>

    00. Trong trường hợp này,

    B = np.array([[1, 2, 3], [4, 5, 6]], dtype = np.float) type(B[0][0]) <type 'numpy.float64'>

    02 vẫn được hiểu là cả ma trận

    import numpy as np A = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) A array([[ 1, 2, 3, 4],

       [ 5,  6,  7,  8],  
       [ 9, 10, 11, 12]])  
    
    A.shape (3, 4)

    0, vì vậy nên

    A[2] array([7, 8, 9]) A[0,:] array([1, 2, 3])

    9 tương đương với

    import numpy as np A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) A[1][2] 6

    4.
  • Có sự khác nhau căn bản giữa

    import numpy as np A = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) A array([[ 1, 2, 3, 4],

       [ 5,  6,  7,  8],  
       [ 9, 10, 11, 12]])  
    
    A.shape (3, 4)

    0 và

    B = np.array([[1, 2, 3], [4, 5, 6]], dtype = np.float) type(B[0][0]) <type 'numpy.float64'>

    ` 02, chúng ta sẽ quay lại trong một bài nào đó ở sau.

Bài tập:

Cho một ma trận

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0, viết hàm

<type 'numpy.float64'>

09 tính tổng các phần tử trên các cột có chỉ số chẵn (

<type 'numpy.float64'>

  1. của ma trận đó. Ví dụ:

<type 'numpy.float64'>

1

Giải thích: cột có chỉ số

<type 'numpy.float64'>

11 của ma trận là mảng

<type 'numpy.float64'>

12, tổng các phần tử của mảng này là 4.


2.5. Truy cập vào nhiều phần tử của ma trận

2.5.1. Nhiều phần tử trong cùng một hàng

Việc truy cập vào nhiều phần tử trong một hàng tương tự như với mảng một chiều:

<type 'numpy.float64'>

2

trong đó,

<type 'numpy.float64'>

13 tạo ra một

<type 'numpy.float64'>

14 các phần tử là cấp số cộng với công sai là

6

6, bắt đầu từ

<type 'numpy.float64'>

11 và kết thúc tại số lớn nhất có thể không vượt quá số cột của

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0. Số cột của

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0 chính là

<type 'numpy.float64'>

19.

2.5.2. Nhiều phần tử trong cùng một cột

Tương tự với nhiều phần tử trong cùng một cột:

<type 'numpy.float64'>

3

2.5.3. Nhiều hàng, nhiều cột

Nếu muốn trích một ma trận con từ ma trận ban đầu, giả sử lấy ma trận được tạo bởi hàng có chỉ số

<type 'numpy.float64'>

00 và

6

6, cột có chỉ số

<type 'numpy.float64'>

11 và

<type 'numpy.float64'>

23, ta làm như sau:

<type 'numpy.float64'>

4

Chú ý: Một cách tự nhiên, bạn đọc có thể suy ra rằng câu lệnh nên là

<type 'numpy.float64'>

24 (giống như cách làm trong Matlab). Tuy nhiên, câu lệnh này sẽ cho ra một kết quả khác (xem mục 4).

<type 'numpy.float64'>

25 có thể hiểu được là: đầu tiên lấy hai hàng có chỉ số

<type 'numpy.float64'>

00 và

6

6 bằng

<type 'numpy.float64'>

28, ta được một ma trận, sau đó lấy hai cột có chỉ số

<type 'numpy.float64'>

11 và

<type 'numpy.float64'>

23 của ma trận mới này.

2.5.4. Cặp các toạ độ

Xét câu lệnh:

<type 'numpy.float64'>

5

Câu lệnh này sẽ trả về một mảng một chiều gồm các phần tử:

<type 'numpy.float64'>

31 và

<type 'numpy.float64'>

32, tức

array([[1, 0, 0],
       [0, 3, 0],
       [0, 0, 4]])
np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

0 và

<type 'numpy.float64'>

34 là

<type 'numpy.float64'>

14 các toạ độ theo mỗi chiều. Hai

<type 'numpy.float64'>

14 này phải có độ dài bằng nhau hoặc một

<type 'numpy.float64'>

14 có độ dài bằng 1. Khi một

<type 'numpy.float64'>

14 có độ dài bằng 1, nó sẽ được cặp với mọi phần tử của

<type 'numpy.float64'>

14 còn lại. Ví dụ:

<type 'numpy.float64'>

6


Bài tập: Viết hàm

<type 'numpy.float64'>

09 tính tổng tất cả các phần tử có cả hai chỉ số đều chẵn của một ma trận

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0 bất kỳ. Ví dụ:

<type 'numpy.float64'>

7

Gợi ý: bạn đọc tìm đọc trước cách sử dụng

<type 'numpy.float64'>

42 cho mảng nhiều chiều.


2.6. np.sum, np.min, np.max, np.mean cho mảng nhiều chiều

Xin nhắc lại về cách quy ước

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
np.diag(a, k = 1) array([2, 6])

0 của ma trận.

array([[1, 0, 0],
       [0, 3, 0],
       [0, 0, 4]])
np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

4 là tính theo chiều từ trên xuống dưới, nghĩa là phương của nó cùng với phương của các cột. Tương tự

array([[1, 0, 0],
       [0, 3, 0],
       [0, 0, 4]])
np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

9 sẽ có phương cùng với phương của các hàng. Hãy quan sát hình dưới đây và ghi nhớ cách quy ước quan trọng này.


Code so sánh 2 ma trận matlab năm 2024


Xét một ma trận:

<type 'numpy.float64'>

8

Và các hàm

<type 'numpy.float64'>

46 tác động lên

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0 theo

array([[1, 0, 0],
       [0, 3, 0],
       [0, 0, 4]])
np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

4 (tức các cột của

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0), kết quả sẽ là:

<type 'numpy.float64'>

9

Các giá trị theo các hàm trê lần lượt là tổng, giá trị nhỏ nhất, giá trị lớn nhất, trung bình theo mỗi cột. Kết quả trả về là các mảng một chiều có số phần tử bằng số cột của

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0.

Tương tự như thế khi thay

array([[1, 0, 0],
       [0, 3, 0],
       [0, 0, 4]])
np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

9:

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

0

Kết quả trả về được tính theo hàng. Kết quả trả về cũng là các mảng một chiều có số phần tử bằng với số hàng của A.

Khi không đề cập tới

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
np.diag(a, k = 1) array([2, 6])

0, kết quả được tính trên toàn bộ ma trận:

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

1

array([[ 0.,  1.,  0.],
       [ 0.,  0.,  1.],
       [ 0.,  0.,  0.]])
np.eye(4, k= -2) array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 1., 0., 0., 0.], [ 0., 1., 0., 0.]])

7

Đôi khi, để thuận tiện cho việc tính toán về sau, chúng ta muốn kết quả trả về khi

array([[1, 0, 0],
       [0, 3, 0],
       [0, 0, 4]])
np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

4 là các vector hàng thực sự, khi

array([[1, 0, 0],
       [0, 3, 0],
       [0, 0, 4]])
np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

9 là các vector cột thực sự. Để làm được việc đó, Numpy cung cấp thuộc tính

array([[ 0.,  1.,  0.],
       [ 0.,  0.,  1.],
       [ 0.,  0.,  0.]])
np.eye(4, k= -2) array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 1., 0., 0., 0.], [ 0., 1., 0., 0.]])

7 (mặc định là

<type 'numpy.float64'>

57). Khi

array([[ 0.,  1.,  0.],
       [ 0.,  0.,  1.],
       [ 0.,  0.,  0.]])
np.eye(4, k= -2) array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 1., 0., 0., 0.], [ 0., 1., 0., 0.]])

7, nếu sử dụng

array([[1, 0, 0],
       [0, 3, 0],
       [0, 0, 4]])
np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

4, kết quả sẽ là một mảng hai chiều có chiều thứ nhất bằng 1 (coi như ma trận một hàng). Tương tự, nếu sử dụng

array([[1, 0, 0],
       [0, 3, 0],
       [0, 0, 4]])
np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

9, kết quả sẽ là một mảng hai chiều có chiều thứ hai bằng 1 (một ma trận có số cột bằng 1). Việc này, về sau chúng ta sẽ thấy, quan trọng trong nhiều trường hợp đặc biệt:

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

2


Bài tập: Cho một ma trận

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0 bất kỳ. Trong mỗi hàng, ta định nghĩa độ biến động của nó là sự khác nhau giữa giá trị lớn nhất và nhỏ nhất của các phần tử trong hàng đó. Hãy viết hàm

<type 'numpy.float64'>

09 trả về tổng độ biến động của tất cả các hàng trong ma trận đó.

Ví dụ với ma trận

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0 trong bài học, độ biến động của mỗi hàng lần lượt là

<type 'numpy.float64'>

64. Vậy

<type 'numpy.float64'>

65.


2.7. Các phép toán tác động đến mọi phần tử của ma trận

2.7.1. Tính toán giữa một mảng hai chiều và một số vô hướng

Khi tính toán giữa một số vô hướng và một mảng hai chiều, ví dụ:

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

3

Ta nhận thấy rằng từng phần tử của mảng sẽ được kết hợp với số vô hướng bằng các phép toán tương ứng để tạo ra một mảng mới cùng kích thước. Việc này, như cũng đã trình bày trong khi làm việc với mảng một chiều, đúng với các mảng numpy với số chiều bất kỳ.

2.7.2. np.abs, np.sin, np.exp, …

Bạn đọc cũng có thể dự đoán được rằng các hàm số này cũng tác động lên từng phần tử của mảng và trả về một mảng cùng kích thước với mảng ban đầu.

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

4


Bài tập: Frobenious norm

của một ma trận được định nghĩa là căn bậc hai của tổng bình phương các phần tử của ma trận. Frobenius norm được sử dụng rất nhiều trong các thuật toán Machine Learning vì các tính chất toán học đẹp của nó, trong đó quan trọng nhất là việc đạo hàm của bình phương của nó rất đơn giản. Frobenius norm của một ma trận \(\mathbf{A}\) được ký hiệu là \(||\mathbf{A}||_F\)

Numpy có sẵn hàm tính toán norm này, tuy nhiên, chúng ta nên học cách tự tính nó trước. Viết hàm

<type 'numpy.float64'>

66 tính Frobenius norm của một ma trận bất kỳ.

Ví dụ:

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

5

thì

<type 'numpy.float64'>

67 \(= \sqrt{1^2 + 3^2 + 2^2 + 5^2}\).

Gợi ý: Sử dụng hàm

<type 'numpy.float64'>

68.


2.8. Các phép toán giữa hai ma trận I

Các phép toán cộng, trừ, nhân, chia, luỹ thừa (

<type 'numpy.float64'>

  1. giữa hai mảng cùng kích thước cũng được thực hiện dựa trên từng cặp phần tử. Kết quả trả về là một mảng cùng chiều với hai mảng đã cho:

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

6

Chú ý: tích của hai ma trận như định nghĩa trong Đại số tuyến tính được thực hiện dựa trên hàm số khác. Cách viết

<type 'numpy.float64'>

70 được thực hiện trên từng cặp phần tử của

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0 và

<type 'numpy.float64'>

72


Bài tập:

Trong khi làm việc với Machine Learning, chúng ta thường xuyên phải so sánh hai ma trận. Xem xem liệu chúng có gần giống nhau không. Một cách phổ biến để làm việc này là tính bình phương của Frobineous norm của hiệu hai ma trận đó. Cụ thể, để xem ma trận \(\mathbf{A}\) có gần ma trận \(\mathbf{B}\) hay không, người ta thường tính \(||\mathbf{A} - \mathbf{B}||_F^2\).

Cho hai mảng hai chiều có cùng kích thước

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0 và

<type 'numpy.float64'>

72. Viết hàm

<type 'numpy.float64'>

75 tính bình phương Frobenious norm của hiệu hai ma trận được mô tả bởi hai mảng đó.


2.9. Chuyện vị ma trận, Reshape ma trận

2.9.1 Chuyển vị ma trận

Có hai cách để lấy chuyển vị của một ma trận: dùng thuộc tính

<type 'numpy.float64'>

76 hoặc dùng hàm

<type 'numpy.float64'>

77:

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

7

2.9.2. Reshape

Khi làm việc với ma trận, chúng ta sẽ phải thường xuyên làm việc với các phép biến đổi kích thước của ma trận. Phép biến đổi kích thước có thể coi là việc sắp xếp lại các phần tử của một ma trận vào một ma trận khác có tổng số phần tử như nhau.

Trong numpy, để làm được việc này chúng ta dùng phương thức

<type 'numpy.float64'>

78 hoặc hàm

<type 'numpy.float64'>

79. Cùng xem ví dụ:

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

8

Số chiều của mảng mới không nhất thiết phải bằng 2, nó có thể bằng bất kỳ giá trị nào (lớn hơn hoặc bằng 1) nhưng phải đảm bảo tổng số phần tử của hai mảng là như nhau. Khi biến thành mảng một chiều, ta không dùng tuple (như

<type 'numpy.float64'>

  1. nữa mà chỉ dùng một số tự nhiên:

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

9

Ta có thể nhận thấy rằng nếu biến thành một mảng hai chiều mới, ta không nhất thiết phải biết kích thước của mỗi chiều mà chỉ cần kích thước của một chiều. Kích thước còn lại được suy ra từ việc tổng số phần tử của hai mảng là như nhau. Tương tự, nếu biến thành một mảng ba chiều mới, ta chỉ cần biết hai trong ba kích thước. Kích thước còn lại sẽ được python tự tính ra, và ta chỉ cần gán nó bằng

<type 'numpy.float64'>

81:

array([[ 0.,  1.,  0.],
       [ 0.,  0.,  1.],
       [ 0.,  0.,  0.]])
np.eye(4, k= -2) array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 1., 0., 0., 0.], [ 0., 1., 0., 0.]])

0

2.9.3. Thứ tự của phép toán reshape

Có một điểm quan trọng cần nhớ là thứ tự của phép toán reshape: các phần tử trong mảng mới được sắp xếp như thế nào. Có hai cách sắp xếp chúng ta cần lưu ý: mặc định là

<type 'numpy.float64'>

82, và một cách khác là

<type 'numpy.float64'>

83 (xem hình).


Code so sánh 2 ma trận matlab năm 2024


Trong

<type 'numpy.float64'>

82, các thành phần của mảng nguồn được quét từ

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
np.diag(a, k = 1) array([2, 6])

0 trong ra ngoài (

array([[1, 0, 0],
       [0, 3, 0],
       [0, 0, 4]])
np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

9 rồi mới tới

array([[1, 0, 0],
       [0, 3, 0],
       [0, 0, 4]])
np.diag(np.diag([1, 3, 4])) array([1, 3, 4])

4 trong mảng hai chiều, tức từng hàng một), sau đó chúng được xếp vào mảng đích cũng theo thứ tự đó.

Trong

<type 'numpy.float64'>

88 (Fortran) các thành phần của mảng nguồn được quét từ

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
np.diag(a, k = 1) array([2, 6])

0 ngoài vào trong (trong mảng hai chiều là từng cột một), sau đó chúng được sắp xếp vào mảng đích cũng theo thứ tự đó - từng cột một.

array([[ 0.,  1.,  0.],
       [ 0.,  0.,  1.],
       [ 0.,  0.,  0.]])
np.eye(4, k= -2) array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 1., 0., 0., 0.], [ 0., 1., 0., 0.]])

1

(Đọc thêm

<type 'numpy.float64'>

90.)


Bài tập: Hãy tạo ma trận

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0 sau một cách nhanh nhất, không dùng cách thủ công ghi từng phần tử ra.

\[ \left[ \begin{matrix} 1 &5&9&2\\6&10&3&7 \\11&4&8&12 \end{matrix} \right] \] Gợi ý:

  • sử dụng `
    > B = np.array([[1, 2, 3], [4, 5, 6]], dtype = np.float)
    type(B[0][0])

    <type 'numpy.float64'>

    `

    92

    Để ý vị trí của 9, 10, 11 và 2, 3, 4 Lời giải không quá hai dòng

Bạn có thể nhận được phản hồi ‘Kết quả thành công’ nhưng hãy thử cố nghĩ quy luật của ma trận này rồi dùng các phép

<type 'numpy.float64'>

93 thích hợp.


2.10. Các phép toán giữa ma trận và vector

Chúng ta đã qua các bài về phép toán giữa một mảng hai chiều và một số vô hướng, giữa hai mảng hai chiều cùng kích thước. Trong bài này, chúng ta cùng làm quen với các phép toán giữa một mảng hai chiều và một mảng một chiều. Trước tiên, hãy thử vài ví dụ:

array([[ 0.,  1.,  0.],
       [ 0.,  0.,  1.],
       [ 0.,  0.,  0.]])
np.eye(4, k= -2) array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 1., 0., 0., 0.], [ 0., 1., 0., 0.]])

2

Nhận thấy rằng kết quả của phép toán

<type 'numpy.float64'>

94 thu được bằng cách lấy từng hàng của

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0 cộng với

<type 'numpy.float64'>

96. Kết quả của

<type 'numpy.float64'>

97 thu được bằng cách lấy tích của từng hàng của

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0 và

<type 'numpy.float64'>

96 - tích ở đây là tích theo từng phần tử của hai mảng một chiều, không phải tích vô hướng của hai vector. Nói cách khác, kết quả của

<type 'numpy.float64'>

97 thu được bằng cách lấy từng cột của

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0 nhân với phần tử tương ứng của

<type 'numpy.float64'>

96. Quy luật tương tự xảy ra với cả phép

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

03,

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

04 và

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

05:

array([[ 0.,  1.,  0.],
       [ 0.,  0.,  1.],
       [ 0.,  0.,  0.]])
np.eye(4, k= -2) array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 1., 0., 0., 0.], [ 0., 1., 0., 0.]])

3


Bài tập

Giả sử tập dữ liệu bao gồm nhiều điểm dữ liệu có cùng chiều, được sắp xếp thành một mảng hai chiều mô tả một ma trận - được gọi là ma trận dữ liệu. Mỗi hàng của ma trận này là một điểm dữ liệu. Một trong các kỹ thuật quan trọng trước khi áp dụng các thuật toán Machine Learning lên dữ liệu là . Trong các phương pháp chuẩn hoá dữ liệu, một phương pháp thường được sử dụng là đưa dữ liệu về dạng zero-mean, tức trung bình cộng của toàn bộ dữ liệu là một vector có toàn bộ các thành phần bằng 0.

Cách chuẩn hoá này có thể được thực hiện bằng cách trước tiên tính vector trung bình của toàn bộ dữ liệu (ở đây là vector trung bình của toàn bộ các hàng), sau đó lấy từng điểm dữ liệu trừ đi vector trung bình. Khi đó, ma trận mới sẽ có trung bình cộng các hàng bằng vector 0, và ta nói rằng ma trận dữ liệu mới này là zero-mean.

Cho một mảng hai chiều

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

06 mô tả dữ liệu, trong đó

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

07 là một mảng một chiều mô tả dữ liệu có chỉ số

3
A.shape[1] 4

0. Hãy viết hàm

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

09 trả về ma trận dữ liệu đã chuẩn hoá theo zero-mean.


2.11. Tích giữa hai ma trận, tích giữa ma trận và vector

2.11.1. Tích giữa hai ma trận

Trong Đại Số Tuyến Tính (ĐSTT), tích của hai ma trận \(\mathbf{A} \in \mathbb{R}{m\times n}\) và \(\mathbf{B} \in \mathbb{R}{n \times p}\) được ký hiệu là \(\mathbf{C = AB} \in \mathbb{R}{m \times p}\) trong đó phần tử ở hàng thứ \(i\) cột thứ \(j\) (tính từ \(0\)) của \(\mathbf{C}\) được tính theo công thức: \[ c_{ij} = \sum_{k=0}{n-1}a_{ik}b_{kj} \]

Chú ý rằng để phép nhân thực hiện được, số cột của ma trận thứ nhất phải bằng với số hàng của ma trận thứ hai (ở đây đều bằng \(n\)). Và phép nhân ma trận không có tính chất giao hoán, nhưng có tính chất kết hợp, tức: \[ \mathbf{ABC} = \mathbf{(AB)C} = \mathbf{A}(\mathbf{BC}) \]

Trong numpy, ký hiệu

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

10 không thực sự để chỉ tích hai ma trận theo nghĩa này mà là tích theo từng cặp phần tử (element-wise). Phép toán

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

10 trong numpy yêu cầu hai mảng phải có cùng kích thước, và phép toán này có tính chất giao hoán vì phép nhân của hai số vô hướng có tính chất giao hoán.

Cho hai mảng numpy hai chiều

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

12 trong đó

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

13 (đừng quên điều kiện này). Nếu hai mảng này mô tả hai ma trận thì tích của hai ma trận (theo ĐSTT) có thể được thực hiện bằng thuộc tính

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

14 hoặc hàm

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

15:

array([[ 0.,  1.,  0.],
       [ 0.,  0.,  1.],
       [ 0.,  0.,  0.]])
np.eye(4, k= -2) array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 1., 0., 0., 0.], [ 0., 1., 0., 0.]])

4

2.11.2. Tích giữa một ma trận và một vector

Trong ĐSTT, tích giữa một ma trận và một vector cột được coi là một trường hợp đặc biệt của tích giữa một ma trận và một ma trận có số cột bằng một. Khi làm việc với numpy, ma trận được mô tả bởi mảng hai chiều, vector được mô tả bởi các mảng một chiều.

Xem ví dụ dưới đây:

array([[ 0.,  1.,  0.],
       [ 0.,  0.,  1.],
       [ 0.,  0.,  0.]])
np.eye(4, k= -2) array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 1., 0., 0., 0.], [ 0., 1., 0., 0.]])

5

Tích của mảng hai chiều

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0 và mảng một chiều

<type 'numpy.float64'>

96 với

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

18 theo ĐSTT được thực hiện bằng phương thức

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

19 của mảng numpy

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0. Kết quả trả về là một mảng một chiều có

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

21. Chúng ta cần chú ý một chút ở đây là kết quả trả về là một mảng một chiều chứ không phải một vector cột (được biểu diễn bởi một mảng hai chiều có

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

  1. như trên lý thuyết. Kết quả của

<type 'numpy.float64'>

97 cũng được chỉ ra để nhắc các bạn phân biệt hai phép nhân này.

Tiếp tục quan sát:

array([[ 0.,  1.,  0.],
       [ 0.,  0.,  1.],
       [ 0.,  0.,  0.]])
np.eye(4, k= -2) array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 1., 0., 0., 0.], [ 0., 1., 0., 0.]])

6

ta thấy rằng nếu đặt

<type 'numpy.float64'>

96 lên trước

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0 thì có lỗi xảy ra vì xung đột chiều. Tuy nhiên nếu mảng một chiều

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

26 có kích thước bằng

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

27 thì lại có thể nhân với mảng hai chiều

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0 được. Kết quả thu được chính là vector hàng

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

26 nhân với ma trận

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0. (Bạn có thể tự kiểm tra lại).

Có một chút cần lưu ý ở đây: Nếu mảng một chiều được nhân vào sau một mảng hai chiều, nó được coi như một vector cột. Nếu nó được nhân vào trước một mảng hai chiều, nó lại được coi là một vector hàng. Dù sao thì nó vẫn là một vector, và vẫn được lưu bởi một mảng một chiều :). Đây cũng chính là một trong những lý o mà những người ban đầu làm quen với numpy gặp nhiều khó khăn.


Bài tập: Quay lại với Frobineus norm. Có một cách khác để tính bình phương của Frobineus norm của một ma trận dựa trên công thức: \[ ||\mathbf{A}||_F^2 = \text{trace}(\mathbf{AA}^T) = \text{trace}(\mathbf{A}^T\mathbf{A}) \]

trong đó \(\text{trace}()\) là hàm tính tổng các phần tử trên đường chéo của một ma trận vuông.

Cho một mảng hai chiều

array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
A.shape
(3, 4)

0, hãy viết hàm

array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

32 tính bình phương của Frobineus norm của ma trận này dựa vào công thức trên.

Gợi ý:

  • sử dụng hàm `
    > import numpy as np
    A = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
    A

    array([[ 1, 2, 3, 4],

       [ 5,  6,  7,  8],  
       [ 9, 10, 11, 12]])  
    
    A.shape (3, 4)

    9, hoặc
  • sử dụng import numpy as np np.eye(3) array([[ 1., 0., 0.],
       [ 0.,  1.,  0.],  
       [ 0.,  0.,  1.]])  
    

    34 (gõ

    import numpy as np np.eye(3) array([[ 1., 0., 0.],
       [ 0.,  1.,  0.],  
       [ 0.,  0.,  1.]])  
    
    ` 35 trên Terminal hoặc google để biết thêm chi tiết).

Hy vọng các bạn gặp khó khăn chút với Compiler và nhận ra lý do của việc đó ;).


2.12. Softmax III - Phiên bản tổng quát

Chúng ta đã làm quen với Phiên bản ổn định của hàm Softmax với một một mảng một chiều \(\mathbf{z}\):

\[\frac{\exp(z_i)}{\sum_{j=0}{C-1} \exp(z_j)} = \frac{\exp(-b)\exp(z_i)}{\exp(-b)\sum_{j=0}{C-1} \exp(z_j)} = \frac{\exp(z_i-b)}{\sum_{j=0}^{C-1} \exp(z_j-b)}\]

Bây giờ, chúng ta tiếp tục tổng quát hàm số này để áp dụng cho nhiều phần tử cùng lúc. Giả sử ma trận \(\mathbf{Z}\) là ma trận scores của \(N\) điểm dữ liệu, mỗi hàng \(\mathbf{z}_i\) của ma trận này ứng với score của một điểm dữ liệu. Hãy viết một hàm số trên python để tính softmax cho từng hàng của \(\mathbf{Z}\). Kết quả thu được là một ma trận \(\mathbf{A}\) cùng chiều với \(\mathbf{Z}\) mà mỗi hàng của \(\mathbf{A}\) là kết quả khi áp dụng hàm Softmax lên một hàng tương ứng của \(\mathbf{Z}\).