Các phép toán với ma trận
Các phép toán trên ma trận là những tính toán cơ bản khi làm việc. Trong phần này, Quantrimang chỉ đề cập tới 3 phép toán cơ bản thường được sử dụng là cộng ma trận, nhân ma trận và chuyển vị ma trận.
Các phép toán ở đây sử dụng cả nested list và thư viện NumPy.
Cộng 2 ma trận
Để cộng hai ma trận, ta cộng từng phần tử tương ứng của 2 ma trận cùng cấp với nhau.
import numpy as npA = np.array([[2, 4], [5, -6]])B = np.array([[9, -3], [3, 6]])C = A + Bprint(C)”’Output:[[11 1][ 8 0]]”’
Nhân 2 ma trận
Nhân 2 ma trận là phép lấy tổng của tích từng phần tử của hàng tương ứng với cột tương ứng.
Chú ý: Nhân ma trận chỉ xảy ra khi số cột của ma trận A bằng với số hàng của ma trận B. Ví dụ cho 2 ma trận [A]mp và [B]pn, tích chúng theo thứ tự đó sẽ được kết quả là ma trận [AB]mn.
Biểu diễn với NumPy như sau:
import numpy as npA = np.array([[3, 6, 7], [5, -3, 0]])B = np.array([[1, 1], [2, 1], [3, -3]])C = a.dot(B)print(C)# Output:[[ 36 -12][ -1 2]]
Chuyển vị ma trận
Chuyển vị là phép biến cột thành hàng và hàng thành cột của một ma trận.
import numpy as npA = np.array([[1, 1], [2, 1], [3, -3]])print(A.transpose())#Output:[[ 1 2 3][ 1 1 -3]]
Ma trận (matrix) với NumPy
Định nghĩa
Ma trận là một mảng 2 chiều. Trong Python mảng 2 chiều có thể xem là một List của List.
Kích thước
Kích thước của 1 ma trận = số hàng * số cột.
Ví dụ:
Ma trận B có 4 hàng và 3 cột: ma trận 4 x 3
Bạn cũng có thể hiểu ma trận là một sheet với số hàng và số cột nhất định trong excel.
1.Range và Null space¶
Với mỗi ma trận \(\mathbf{A} \in \mathbb{R}^{m×n}\), có hai không gian con quan trọng ứng với ma trận này.
-
Range của ma trận \(\mathbf{A}\) được định nghĩa là tập hợp tất cả các điểm là tổ hợp tuyến tính của các cột của ma trận \(\mathbf{A}\):
\(\mathcal{R}(\mathbf{A})\) còn chính là không gian sinh (span) của các cột của ma trận \(\mathbf{A}\). \(\mathcal{R}(\mathbf{A})\) là một không gian con của \(\mathbb{R}^m\) với số chiều chính bằng số lượng lớn nhất các cột của \(\mathbf{A}\) độc lập tuyến tính.
-
Null của \(\mathbf{A}\), ký hiệu là \(\mathcal{N}(\mathbf{A})\), được định nghĩa là:
Mỗi véc tơ trong \(\mathcal{N}(\mathbf{A})\) chính là một bộ các hệ số làm cho tổ hợp tuyến tính các cột của \(\mathbf{A}\) tạo thành một véc tơ \(0\). \(\mathcal{N} (\mathbf{A})\) có thể được chứng minh là một không gian con trong \(\mathbb{R}^n\) . Khi các cột của \(\mathbf{A}\) là độc lập tuyến tính, theo định nghĩa, \(\mathcal{N}(\mathbf{A}) = \{ 0 \}\) (chỉ gồm véc tơ \(0\)).
\(\mathcal{R}(\mathbf{A})\) và \(\mathcal{N} (\mathbf{A})\) là các không gian con véc tơ với số chiều lần lượt là \(\dim(\mathcal{R}(\mathbf{A}))\) và \(\dim(\mathcal{N} (\mathbf{A}))\), ta có tính chất quan trọng sau đây:
1.Khái niệm chuẩn¶
Chuẩn là một độ đo trên véc tơ véc tơ hoặc ma trận. Một hàm \(f(\mathbf{x})\) là một phép ánh xạ từ véc tơ sang một đại lượng vô hướng \(\mathbb{R}^{d} \mapsto \mathbb{R}\) nếu nó thoả mãn các tính chất.
1-. Tính chất scale:
Như vậy khi bạn phóng đại lên véc tơ \(\alpha\) lần thì giá trị chuẩn của nó cũng phóng đại lên \(\alpha\) lần.
2-. Bất đẳng thức tam giác:
Nếu ta coi \(\mathbf{x}\) như là véc tơ cạnh và \(f(\mathbf{x})\) như là độ dài cạnh của một tam giác thì \(f(\mathbf{x}), f(\mathbf{y})\) là độ dài của 2 cạnh bất kỳ và tổng của chúng sẽ lớn hơn độ dài cạnh còn lại \(f(\mathbf{x} + \mathbf{y})\).
3-. Tính chất không âm:
Trong machine learning các bạn sẽ thường xuyên gặp một số chuẩn chính là chuẩn bậc 2
import torch x = torch.randn(10) torch.norm(x, p=2)
import numpy as np x = np.random.randn(10) np.linalg.norm(x, ord=2)
Ta nhận thấy hàm MSE đo lường sai số giữa giá trị dự báo và thực tế trong phương trình hồi qui tuyến tính cũng là một dạng chuẩn bậc 2.
Chuẩn bậc 1:
print(torch.norm(x, p=1)) # hoặc torch.abs(x).sum()
print(np.linalg.norm(x, ord=1)) # hoặc np.abs(x).sum()
Trong hồi qui tuyến tính thì chuẩn bậc 1 đo lường sai số tuyệt đối giữa giá trị dự báo và giá trị thực tế. Tuy nhiên nó ít được sử dụng hơn so với chuẩn bậc 2 như là một loss function vì giá trị của nó có đạo hàm không liên tục. Điều này dẫn tới việc huấn luyện mô hình không ổn định. Tuy nhiên nó cũng khá thường xuyên được sử dụng trong các mô hình deep learning chẳng hạn như GAN.
Cả hai chuẩn trên đều là trường hợp cụ thể của chuẩn bậc \(p\) (ký hiệu \(L_{p}\)) tổng quát hơn có công thức như sau:
Để cả 3 điều kiện về chuẩn được thoả mãn thì chúng ta cần có \(p \geq 1\).
# chuẩn p bất kỳ >= 1, chẳng hạn p=1.5 torch.norm(x, p=1.5)
# chuẩn p bất kỳ >= 1, chẳng hạn p=1.5 np.linalg.norm(x, ord=1.5)
1.Định thức và các tính chất của định thức¶
Giả sử ta có một ma trận vuông \(\mathbf{A}\) như sau:
Định thức của một ma trận \(\mathbf{A}\) được kí hiệu là \(| \mathbf{A} |\) hoặc \(\det(\mathbf{A})\) là một giá trị được tính theo công thức:
Trong đó \(\sigma=(\sigma_1, \sigma_2, \dots, \sigma_n)\) là một phép hoán vị các thành phần của tập hợp \(n\) số tự nhiên đầu tiên \(O = \{1, 2, \dots, n\}\). Tập hợp tất cả các hoán vị của \(n\) số tự nhiên này còn được kí hiệu là \(\mathcal{S}\). Hàm \(\text{sgn}(\sigma)\) là một hàm nhận hai gía trị \(\{1, -1\}\). Nếu số lần hoán vị \(\sigma\) để biến đổi trở về tập \(O\) là chẵn thì nhận gía trị 1 và lẻ thì nhận giá trị -1.
Trong
numpy
, định thức có thể được tính toán khá dễ dàng thông qua hàm
np.linalg.det()
.
import torch A = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32) # Định thức của ma trận torch.det(A)
import numpy as np A = np.array([[1, 2], [3, 4]]) # Định thức của ma trận np.linalg.det(A)
Ngoài ra định thức của ma trận \(\mathbf{A}\) có thể được khai triển theo các ma trận phần bù \(\mathbf{A}_{ij}\) của ma trận \(\mathbf{A}\). Trong đó ma trận phần bù \(\mathbf{A}_{ij}\) là ma trận được tạo thành bằng cách xoá đi dòng thứ \(i\) và cột thứ \(j\) của ma trận \(\mathbf{A}\).
Định thức có vai trò rất quan trọng trong đại số tuyến tính. Thông qua định thức, chúng ta có thể biết được hệ các véc tơ dòng (hoặc cột) của một ma trận là độc lập tuyến tính hay phụ thuộc tuyến tính? Hệ phương trình tương ứng với ma trận có thể có bao nhiêu nghiệm? Bên dưới là một số tính chất của định thức:
1-. Định thức chỉ tồn tại trên những ma trận vuông.
2-. \(\text{det}(\mathbf{A}) = \text{det}(\mathbf{A}^{\intercal})\)
3-. \(\det(\mathbf{I}) = 1\)
4-. Một ma trận đường chéo thì có định thức bằng tích các phần tử nằm trên đường chéo. Ma trận đường chéo còn được kí hiệu thông qua các phần tử trên đường chéo là \(\text{diag}(a_1, a_2, \dots, a_m)\). Tức là nếu:
thì:
5-. Nếu \(\mathbf{A}, \mathbf{B}\) là những ma trận vuông cùng kích thước thì
Cũng từ tính chất này ta suy ra:
6-. Ma trận vuông \(\mathbf{A}\) khả nghịch thì
Từ tính chất này ta cũng suy ra một ma trận khả nghịch thì định thức của nó phải khác 0 bởi nếu định thức của nó bằng 0 thì \(\det(\mathbf{A}) = 0\), điều này là vô lý vì vế phải của phương trình trên không thể bằng 0.
7-. Nếu một ma trận tồn tại một véc tơ dòng hoặc véc tơ cột có toàn bộ các phần tử bằng 0 thì định thức của ma trận bằng 0.
8-. Trong một ma trận nếu đổi vị trí của hai dòng bất kì hoặc hai cột bất kì và các vị trí còn lại dữ nguyên thì định thức đổi dấu. Tức là nếu bên dưới ta có hai ma trận vuông:
Trong đó ma trận \(\mathbf{A’}\) thu được bằng cách thay đổi vị trí dòng \(\mathbf{A}_{i:}\) cho dòng \(\mathbf{A}_{j:}\) của ma trận \(\mathbf{A}\) thì \(\det({\mathbf{A}}) = -\det(\mathbf{A’})\).
9-. Khi cộng vào một dòng tích của một dòng khác với hệ số \(\alpha\) hoặc cộng vào một cột với tích của một cột khác với hệ số \(\alpha\) thì định thức không đổi.
10-. Khi nhân một dòng hoặc một cột bất kì của ma trận với hệ số \(\alpha\) và các dòng và cột khác giữa nguyên thì định thức của ma trận mới tăng gấp \(\alpha\) lần. Như vậy ta suy ra một tính chất khá quan trọng đối với ma trận \(\mathbf{A} \in \mathbb{R}^{n \times n}\):
Kiến thức cần có
- Hàm input() và hàm print()
- Cấu trúc lặp trong Python
- Cấu trúc rẽ nhánh trong Python
- Biến và kiểu dữ liệu
- Hàm trong Python
- Xử lý ngoại lệ (Exception Handling)
- Các phương thức xử lý List trong Python:
- split()
- len()
- Unpacking arguments
Định dạng đầu vào
Gồm hai dòng:
- Dòng đầu tiên chứa hai giá trị M, N cách nhau bởi khoảng trắng.
- M dòng tiếp theo, mỗi dòng chứa N phần tử, các phần tử cách nhau bởi khoảng trắng
Định dạng đầu ra
- Gồm N dòng, mỗi dòng hiển thị M phần tử của danh sách hai chiều chuyển vị. Các phần tử cách nhau bởi khoảng trắng.
Lưu ý: Nếu M, N nhỏ hơn hoặc bằng 0 thì xuất thông báo: Vui long nhap kich thuoc danh sach la so nguyen duong.
Nếu danh sách hai chiều nhập vào không đúng kích thước MxN thì xuất thông báo: Danh sach hai chieu khong dung kich thuoc!
Nếu input nằm ngoài định dạng đầu vào thì xuất thông báo: Dinh dang dau vao khong hop le!
Ví dụ
- Input 1:
3 4 1 2 3 4 nam sau bay tam 9 muoi 11 12
- Output 1:
1 nam 9 2 sau muoi 3 bay 11 4 tam 12
- Input 2:
1 1 Kteam
- Output 2:
Kteam
- Input 3:
-5 0
- Output 3:
Vui long nhap kich thuoc danh sach la so nguyen duong!
- Input 4:
3 2 1 hai 1 2 ba
- Output 4:
Danh sach hai chieu khong dung kich thuoc da khai bao!
- Input 5:
4 5 Kteam
- Output 5:
Dinh dang dau vao khong hop le!
Chuyển đổi ma trận Python sang mảng
Bạn có thể dùng các hàm ravel và flatten để chuyển đổi ma trận Python sang mảng.
Code:
# Chương trình Python chuyển đổi ma trận sang một mảng # nhập mô đun được yêu cầu import numpy as np # Tạo ma trận bằng numpy matrix = np.matrix("[4, 6, 7; 5, 2, 6; 6, 3, 6]") # Dùng hàm ravel() để chuyển đổi ma trận sang mảng array = matrix.ravel() print(array) # Dùng hàm flatten() để chuyển đổi ma trận sang mảng array = np.asarray(matrix).flatten() print(array) # Dùng hàm reshape() để chuyển đổi ma trận sang mảng array = (np.asarray(matrix)).reshape(-1) print(array)
Kết quả:
[[4 6 7 5 2 6 6 3 6]] [4 6 7 5 2 6 6 3 6] [4 6 7 5 2 6 6 3 6]
Tóm lại những điều cần ghi nhớ về ma trận Python:
- Ma trận Python là một mảng hình chữ nhật hai chiều chuyên biệt của dữ liệu được lưu trữ trong hàng và cột. Dữ liệu trong một ma trận có thể là số, chuỗi, biểu thức, biểu tượng… Ma trận là một trong số cấu trúc dữ liệu quan trọng có thể được dùng ở các phép tính toán học và khoa học.
- Python không có cách đơn giản để triển khai một kiểu dữ liệu ma trận. Khai báo ma trận trong Python có thể được tạo bằng một kiểu dữ liệu danh sách được lồng và bằng việc dùng thư viện numpy.
- Thư viện Python Numby giúp xử lý các vấn đề liên quan tới mảng. Numpy xử lý một mảng nhỏ nhanh hơn so với dạng danh sách.
- Những toán tử ma trận có thể được thực hiện là cộng, trừ, nhân, hoán vị, đọc hàng, cột của ma trận, cắt ma trận, v.v.
- Để thêm hai ma trận, bạn có thể sử dụng numpy.array() và thêm chúng bằng toán tử +.
- Để nhân chúng, bạn có thể dùng phương thức numpy dot(). Numpy.dot() là sản phẩm dot của ma trận M1 và M2. Numpy.dot() xử lý mảng 2D và thực hiện phép nhân ma trận.
Vậy như bạn thấy, sử dụng thư viện NumPy thay vì nested list làm cho các phép toán với ma trận dễ dàng hơn rất nhiều. Quantrimang khuyên bạn nên tìm hiểu và học cách sử dụng thư viện NumPy thật kĩ đặc biệt khi sử dụng Python để áp dụng cho việc tính toán khoa học hay phân tích dữ liệu.
Chúc các bạn thành công!
Xem thêm:
2.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
shape
:
>>> 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)
Ở đây, kết quả trả về là một
tuple
. 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:
>>> A.shape[0] 3 >>> A.shape[1] 4
Với mảng numpy nhiều chiều, ta cũng dùng thuộc tính
shape
để tìm kích thước
của mỗi chiều.
2.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 (
+, -, *, /, **
) 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:
>>> import numpy as np >>> A = np.array([[1., 5], [2, 3]]) >>> B = np.array([[5., 8], [7, 3]]) >>> A*B array([[ 5., 40.], [ 14., 9.]]) >>> A**B array([[ 1.00000000e+00, 3.90625000e+05], [ 1.28000000e+02, 2.70000000e+01]])
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
A*B
được thực hiện trên từng cặp phần tử của và
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 và . Viết hàm
dist_fro
tính bình phương Frobenious norm của hiệu hai ma trận được mô tả bởi hai mảng đó.
1.Cơ sở của một không gian¶
Một hệ các véc tơ \(\{\mathbf{a}_1, \mathbf{a}_2, \dots, \mathbf{a}_n \}\) trong không gian véc tơ \(m\) chiều, kí hiệu là \(V = \mathbb{R}^{m}\) được gọi là một cơ sở (basic) nếu như điều kiện kiện sau được thoả mãn:
-
\(V \equiv \text{span}(\mathbf{a}_1, \dots, \mathbf{a}_n)\)
-
\({\mathbf{a}_1, \mathbf{a}_2, \dots, \mathbf{a}_n}\) là một hệ véc tơ độc lập tuyến tính.
Mỗi một véc tơ đều có một biểu diễn duy nhất dưới dạng một tổ hợp tuyển tính của những véc tơ của các \(\mathbf{a}_i\).
2.Ma trận đơn vị và ma trận đường chéo
2.2.Ma trận đơn vị
Để tạo một ma trận đơn vị có số chiều bằng (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
np.eye()
:
>>> import numpy as np >>> np.eye(3) array([[ 1., 0., 0.], [ 0., 1., 0.], [ 0., 0., 1.]])
Hàm
np.eye()
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ụ:
>>> 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.]])
k = 1
sẽ tương ứng với đường chéo phụ ngay trên đường chéo chíh.
k = -2
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õ
help(func)
trong đó
func
là tên hàm bạn muốn tra cứu. Ví dụ,
help(np.eye)
.
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
np.diag
.
>>> 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])
-
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ứ
, cột thứvới
0 <= i <= min(m, n)
. Trong đó,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 :
>>> 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])
Bài tập:
Với một số tự nhiên , 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.Truy cập vào nhiều phần tử của ma trận
2.5.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:
>>> 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[0, 2:] array([3, 4]) >>> A[1, range(0, A.shape[1], 2)] array([5, 7])
trong đó,
range(0, A.shape[1], 2)
tạo ra một
list
các phần tử là cấp số cộng với công sai là ,
bắt đầu từ và kết thúc tại số lớn nhất có thể không vượt quá số cột của . Số cột của chính là
A.shape[1]
.
2.5.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:
>>> A[[0, 2], -1] # the first and the third elements in the last column array([ 4, 12])
2.5.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ố và , cột có chỉ số và , ta làm như sau:
>>> A[[1, 2]][:, [0,3]] array([[ 5, 8], [ 9, 12]])
Chú ý: Một cách tự nhiên, bạn đọc có thể suy ra rằng câu lệnh nên là
A[[1,
2], [0, 3]]
(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).
A[[1, 2]][:, [0,3]]
có thể hiểu được là: đầu tiên lấy hai hàng có chỉ số
và bằng
A[[1, 2]]
, ta được một ma trận, sau đó lấy hai cột có chỉ số
và của ma trận mới này.
2.5.Cặp các toạ độ
Xét câu lệnh:
>>> A[[1, 2], [0, 3]] array([ 5, 12])
Câu lệnh này sẽ trả về một mảng một chiều gồm các phần tử:
A[1][0]
và
A[2][3]
, tức
[1, 2]
và
[0, 3]
là
list
các toạ độ theo mỗi chiều. Hai
list
này
phải có độ dài bằng nhau hoặc một
list
có độ dài bằng 1.
Khi một
list
có độ dài bằng 1, nó sẽ được cặp với mọi phần tử của
list
còn lại. Ví dụ:
>>> A[[1, 2], [0]] # equivalent to A[[1, 2], [0, 0]] array([5, 9])
Bài tập:
Viết hàm
myfunc
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 bất kỳ. Ví dụ:
>>> A array([[ 1, 2, 3, 4], [ 5, 6, 7, 8], [ 9, 10, 11, 12]]) >>> myfunc(A) # = 1 + 3 + 9 + 11 24
Gợi ý: bạn đọc tìm đọc trước cách sử dụng
np.sum
cho mảng nhiều chiều.
Hàm size với ma trận
Chúng ta có thể sử dụng hàm size để lấy kích thước của ma trận:
np.size(matrix, axis)
Trong đó:
- matrix: ma trận cần tìm kích thước
- axis: chiều, nếu là 0 sẽ trả về số hàng, 1 trả về số cột, mặc định trả về số phần tử.
Ví dụ:
import numpy as np _a = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] a = np.array(_a) print(np.size(a)) print(np.size(a, 1))
Transpose matrix (ma trận chuyển vị)
Transpose matrix được kí hiệu là: AT
Transpose matrix là ma trận đảo hàng và cột so với ma trận gốc.
Với NumPy ta sử dụng function np.transpose() để transpose matrix.
Ví dụ:
import numpy as np _a = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] a = np.array(_a) a_t = np.transpose(a) #Create transpose of a print(a) print(a_t)
2.Truy cập vào từng phần tử của ma trận
2.4.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.Cách 1: giống với list
Để truy cập vào phần tử ở hàng thứ , cột thứ của ma trận (chỉ số bắt đầu
từ 0), ta có thể coi phần tử đó là phần tử thứ của mảng trong mảng hai
chiều ban đầu.
Ví dụ:
>>> import numpy as np >>> A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> A[1][2] 6
ở đây
A[1]
chính lả mảng một chiều
[4, 5, 6]
, trong mảng này, ta lấy phần
tử có chỉ số là , phần tử đó có giá trị là . Vậy
A[1][2]
= 6.
2.4.1.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 , ta sử dụng
A(1, 1)
. Trong Numpy, có một chút thay đổi:
- Chỉ số bắt đầu từ 0.
-
Bộ chỉ số được đặt trong dấu ngoặc vuông
[]
.
Ví dụ
>>> A[2, 1] 8
2.4.Truy cập vào hàng/cột
Để truy cập vào hàng có chỉ số của một ma trận , ta chỉ cần dùng
A[i]
hoặc
A[i,:]
hoặc
A[i][:]
:
>>> A[2] array([7, 8, 9]) >>> A[0,:] array([1, 2, 3])
Để truy cập vào cột có chỉ số , ta dùng
A[:,j]
:
>>> A[:, 1] array([2, 5, 8])
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[:][1]
, kết quả trả về là hàng có chỉ sốchứ không phải cột có chỉ số. Trong trường hợp này,
A[:]
vẫn được hiểu là cả ma trận, vì vậy nên
A[:][1]
tương đương với
A[1]
. -
Có sự khác nhau căn bản giữa
và
A[:]
, 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 , viết hàm
myfunc
tính tổng các phần tử trên các cột
có chỉ số chẵn (
0, 2, 4, ...
) của ma trận đó.
Ví dụ:
>>> A = np.array([[1, 2], [3, 4]]) >>> myfunc(A) 4
Giải thích: cột có chỉ số của ma trận là mảng
[1, 3]
, tổng các phần tử
của mảng này là 4.
Sử dụng ma trận Python với Numpy
Để thực hiện các thao tác dữ liệu ma trận, bạn có thể sử dụng gói numpy. NumPy là thư viện được viết bằng Python nhằm phục vụ cho việc tính toán khoa học, hỗ trợ nhiều kiểu dữ liệu đa chiều giúp cho việc tính toán, lập trình, làm việc với các hệ cơ sở dữ liệu cực kì thuận tiện. Bạn có thể sử dụng các các phép toán và mảng (array) được định nghĩa trong numpy để tạo ma trận. Array này là một đối tượng mảng đa chiều thuần nhất tức là mọi phần tử đều cùng 1 kiểu.
Vector với NumPy
Định nghĩa
Vector là ma trận với 1 cột và nhiều hàng (n * 1)
Kích thước
Kích thước của vector (còn được gọi là chiều vector – vector dimension) là số hàng của vector.
Ví dụ:
- Vector có 4 hàng là vector 4 chiều.
- Vector tương tự như 1 cột trong excel với số hàng nhất định.
Khởi tạo ma trận và vector với NumPy
Khởi tạo ma trận
Ta có thể khởi tạo ma trận với NumPy bằng np.array:
np.array(object, dtype=None, ndmin=0)
Trong đó:
- Object: một mảng 2 chiều, ta có thể sử dụng một list của list.
- dtype: kiểu dữ liệu của các phần tử trong ma trận
- ndmin: số chiều tối thiểu khi return object, nên đặt = 2 để tiện cho việc indexing ma trận cho Machine Learning.
Lưu ý: trừ object, các parameter khác khi truyền vào phải có key_arg.
Ví dụ:
import numpy as np #import numpy and uses shorter keyword _A = [ [1, 2, 3], [4, 5, 6] ] #array-like object A = np.array(_A) #create a 2-dimension array (matrix) from _A print(A) #print matrix A
Ma trận này cũng tương tự như bảng sau:
Khởi tạo vector
Ta khởi tạo vector như ma trận nhưng chỉ có 1 cột (mảng 1 chiều). Ta có thể xem đây là 1 List.
import numpy as np #import numpy and uses shorter keyword _a = [ 1, 2, 3, 4 ] #array-like object a = np.array(_a) #create a 1-dimension array (vector) from _a print(‘Vector 4 chiều:’, a) #print vector a
Ví dụ:
Sử dụng NumPy cho ma trận
NumPy là thư viện được viết bằng Python nhằm phục vụ cho việc tính toán khoa học, hỗ trợ nhiều kiểu dữ liệu đa chiều giúp cho việc tính toán, lập trình, làm việc với các hệ cơ sở dữ liệu cực kì thuận tiện.
Để tạo một ma trận ta có thể sử dụng ndarray (viết gọn là array) của NumPy
Array này là một đối tượng mảng đa chiều thuần nhất tức là mọi phần tử đều cùng 1 kiểu.
Hãy thử với một ví dụ:
import numpy as np
a = np.array([1, 2, 3])
print(a)
# Output: [1, 2, 3]print(type(a))# Output:
Các toán tử với ma trận và vector
Cộng và trừ với ma trận
Các phép toán cộng và trừ với ma trận là phép toán “element-wise”, nghĩa là phép toán với từng phần tử tương ứng.
Tương tự với trừ:
Lưu ý: Để cộng và trừ 2 ma trận, kích thước của cả hai phải giống nhau.
Ví dụ :
import numpy as np _a = [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] _b = [ [ 2, 3, 5], [7, 9, 21] ] a = np.array(_a) #create 2 * 3 matrix: a b = np.array(_b) #create 2 * 3 matrix: b print(‘a + b:’, a + b) #print out a + b print(‘a – b:’, a – b) #print out a - b
Nhân và chia ma trận với số
Để nhân và chia ma trận với số, ta chỉ cần nhân/chia từng phần tử của ma trận với số đó.
Tương tự với chia:
Ví dụ:
import numpy as np _a = [ [ 3, 2, 1 ], [ 2, 4, 6 ] ] a = np.array(_a) print(‘a / 2:’, a / 2) #print out a / 2 print(‘a * 2:’, a * 2) #print out a * 2
Nhân ma trận với vector
Khi nhân ma trận với vector, ta lấy các phần tử trong cột số của vector nhân lần lượt với các hàng của ma trận để được các tích, sau đó lấy tổng của các tích rồi cho vào từng hàng của kết quả. Chúng ta có thể hình dung như sau:
Kết quả của phép tính luôn là một vector. Số cột của ma trận phải bằng với số hàng của vector.
Một ma trận m * n nhân với một vector n * 1 sẽ có tích là một vector m * 1
Phân tích
Đầu tiên, ta xoay ngang vector lại thành
Sau đó nhân lần lượt từng dòng của ma trận với :
Cuối cùng lấy tổng của từng hàng:
Phép nhân ma trận – vector trong NumPy
Trong NumPy, để nhân ma trận với vector như trên, ta có thể dùng:
Matrix_name.dot(vector)
Từ phiên bản 3.5 trở lên Python đã hỗ trợ toán tử @:
Matrix @ vector
Để hiểu rõ hơn, chúng ta cùng đi đến Ví dụ:
import numpy as np _a = [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ] a = np.array(_a) #Create a 3 * 2 matrix _b = [ 1, 2 ] b = np.array(_b) #Create a 2-dimension vector print(a) print(b) print(‘a * b:’, a.dot(b)) #print out a * b using narray.dot() print(‘a * b:’, a @ b) #print out a * b using @ operation
Thực hiện từng bước:
Đầu tiên xoay ngang b:
Nhân từng dòng a với b:
Kết quả phép nhân là tổng từng dòng
Nhân ma trận với ma trận
Chúng ta nhân 2 ma trận bằng cách tách 1 ma trận ra thành nhiều vector rồi nhân, sau đó ghép các kết quả lại.
Để nhân 2 ma trận, số cột của ma trận 1 phải bằng số hàng ở ma trận 2.
Một ma trận m * n nhân với một ma trận n * o sẽ cho kết quả là một ma trận m * o
Phân tích
Đầu tiên tách ma trân thứ 2 thành 2 vector nhỏ: thành và
Nhân ma trận đầu lần lượt với 2 vector và : ; ;
Kết quả là 2 vector có cùng kích thước: và
Cuối cùng, ghép 2 vector lại với nhau:
Phép nhân ma trận – ma trận với NumPy
Cũng như nhân ma trận với vector, trong NumPy ta có thể dùng:
Matrix1.dot(matrix2)
Hoặc
Matrix1 @ matrix2
Ví dụ:
import numpy as np _a = [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ] a = np.array(_a) #Create a 3 * 2 matrix _b = [ [1, 3], [2, 1] ] b = np.array(_b) #Create a 2 * 2 matrix print(a) print(b) print(‘a * b:’, a.dot(b)) #print out a * b using narray.dot() print(‘a * b:’, a @ b) #print out a * b using @ operation
Thực hiện từng bước:
Đầu tiên tách ma trân thứ 2 thành 2 vector nhỏ: thành và
Nhân ma trận đầu lần lượt với 2 vector và :
Kết quả là 2 vector có cùng kích thước: và
Cuối cùng, ghép 2 vector lại với nhau:
Tính chất của phép nhân ma trận
Phép nhân ma trận không có tính chất giao hoán.
Phép nhân ma trận có tính chất kết hợp.
Identity matrix (ma trận đơn vị)
Identity matrix là ma trận mà khi nhân với bất kì ma trận khác cùng kích thước, ma trận đó sẽ không đổi. Phép nhân với identity matrix có tính chất giao hoán. Chúng ta có thể xem identity matrix là “số 1” của ma trận.
Cấu trúc của identity matrix là 1 ma trận có số 1 trên đường chéo.
Ví dụ:
Ta có thể tạo một identity matrix trong NumPy bằng hàm eye:
np.eye(x)
Với x là kích thước của identity matrix.
Ví dụ:
import numpy as np a = np.eye(5) print(a)
Phép nhân “element-wise” với ma trận
Đối với phép nhân element-wise, kết quả sẽ là một ma trận với những phần tử là tích của các phần tử là tích của 2 phần tử tương ứng trong 2 ma trận.
Với NumPy, ta có thể thực hiện phép nhân element-wise bằng toán tử *
Ví dụ:
import numpy as np _a = [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] _b = [ [ 2, 3, 5], [7, 9, 21] ] a = np.array(_a) #create 2 * 3 matrix: a b = np.array(_b) #create 2 * 3 matrix: b print(‘a .* b:’, a * b) #print out a .* b
Toán tử logic với ma trận
Ta hoàn toàn có thể thực hiện các toán tử logic với ma trận. Kết quả trả ra sẽ được ghi vào một ma trận với kích thước tương đương.
Ví dụ:
import numpy as np a = np.eye(5) print(a == 1)
Indexing ma trận và vector
Ta có thể indexing ma trận và vector theo cấu trúc:
Matrix_name[row_index, column_index]
Trong đó:
- Row_index, column_index có thể là kí tự ‘:’ với ý nghĩa lấy toàn bộ những phần tử theo hàng/ cột.
Ví dụ:
import numpy as np #import numpy and uses shorter keyword _a = [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] #array-like object a = np.array(_a) #create a 2-dimension array (matrix) from _a print(‘a[0, 1]:’, a[0, 1]) #print a[0, 1] element print(‘a[:, 0]:’, a[:, 0]) #print a[:, 0] elements print(‘a[1, :]:’, a[1, :]) #print a[1, :] elements
Thảo luận
Nếu bạn có bất kỳ khó khăn hay thắc mắc gì về khóa học, đừng ngần ngại đặt câu hỏi trong phần bên dưới hoặc trong mục HỎI & ĐÁP trên thư viện Howkteam.com để nhận được sự hỗ trợ từ cộng đồng.
Nội dung bài viết
Khóa học
Machine Learning cơ bản với NumPy
Với mục đích giới thiệu đến mọi người về Machine Learning cũng như tạo điểm khởi đầu cho các bạn mới, muốn tham gia và tìm hiểu ban đầu về lĩnh vực khá hot này. Cùng Kteam tìm hiểu về Machine Learning cơ bản với ngôn ngữ Python.
Thông qua khóa học MACHINE LEARNING VỚI NUMPY, Kteam sẽ hướng dẫn các kiến thức cơ bản của thuật toán Machine Learning để các bạn có thể tạo ra những sản phẩm Machine Learning của riêng mình.
Đánh giá
Bình luận
Nôm na là cái ma trận là cái ma trận trong môn Đại số tuyến tính
Bổ dưỡng lắm các ông ạ.
Mình thuộc loại ngu đần về mảng này nhưng mà xem cái ngu hơn hẳn.
Nói đùa vậy cho vui chứ thực sự hay lắm. Nhờ có HKteam mà mình chập chững có những dòng code đầu tiên để tự động hóa cho công việc của mình.
Cảm ơn rất nhiều!
Kteam ơi, hình như phút thứ 18:27 sai cách tính rồi ạ, phải là 1×7 + 2×9 + 3×21 mới ra 88 và đúng theo quy tắc nhân ạ
Shout out to Howkteam. Dạy kỹ từ căn bản, không phải như kiểu trang web khác. Dạy toàn presume là đã hiểu hết về toán học.
Viết hàm trả về danh sách hai chiều chuyển(Tham số là danh sách hai chiều MxN)
Ý nghĩa của ma trận trong Machine Learning
Đối với Machine Learning, chúng ta phải xử lí những dữ liệu với số lượng rất lớn, ta không thể cứ dùng vòng lặp duyệt qua từng dữ liệu được vì sẽ thiếu tối ưu về tốc độ. Vì thế chúng ta cần một công cụ mạnh hơn để xử lí những dữ liệu số lượng lớn, đó là ma trận. Với các phép tính với ma trận, chỉ cần 1 dòng lệnh ta đã có thể cùng lúc thực hiện phép tính trên nhiều dữ liệu.
2.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ụ:
>>> import numpy as np >>> A = np.arange(12).reshape(3, -1) >>> A array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> b = np.array([1., 2, 3, 5]) >>> A + b array([[ 1., 3., 5., 8.], [ 5., 7., 9., 12.], [ 9., 11., 13., 16.]]) >>> A*b array([[ 0., 2., 6., 15.], [ 4., 10., 18., 35.], [ 8., 18., 30., 55.]])
Nhận thấy rằng kết quả của phép toán
A + b
thu được bằng cách lấy từng hàng của cộng với . Kết quả của
A*b
thu được bằng cách lấy tích của từng hàng của và – 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
A*b
thu được bằng cách lấy từng cột của nhân với phần tử tương ứng của . Quy luật tương tự xảy ra
với cả phép , và
**
:
>>> c = np.array([1, 2, 1,2]) >>> A**c array([[ 0, 1, 2, 9], [ 4, 25, 6, 49], [ 8, 81, 10, 121]])
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à chuẩn hoá dữ liệu. 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 mô tả dữ liệu, trong đó
X[i]
là một mảng một chiều mô tả dữ liệu có chỉ số . Hãy viết hàm
zero_mean
trả về ma trận dữ liệu đã chuẩn hoá theo zero-mean.
Xuất các phần tử, cột, dòng của ma trận
Xuất các phần tử của ma trận
Tương tự với cách kết xuất bằng list, chúng ta có thể sử dụng bằng NumPy. Trước tiên, hãy thử với mảng một chiều:
import numpy as npA = np.array([12, 14, 16, 18, 20])print(“A[0] =”, A[0]) # phần tử đầu tiênprint(“A[2] =”, A[2]) # phần tử thứ 3print(“A[-1] =”, A[-1]) # phần tử cuối cùng
Output được trả về ở đây là:
A[0] = 12
A[2] = 16
A[-1] = 20
Ví dụ về mảng hai chiều:
import numpy as npA = np.array([[1, 4, 5, 12],[-5, 8, 9, 0],[-6, 7, 11, 19]])# Phần tử đầu tiên của hàng đầu tiênprint(“A[0][0] =”, A[0][0])# Phần tử thứ 3 của hàng thứ 2print(“A[1][2] =”, A[1][2])# Phần tử cuối cùng của hàng cuối cùngprint(“A[-1][-1] =”, A[-1][-1])
Chạy chương trình, kết quả được trả về là:
A[0][0] = 1
A[1][2] = 9
A[-1][-1] = 19
Xuất các dòng của ma trận
import numpy as npA = np.array([[1, 4, 5, 12],[-2, 8, 6, 14],[-1, 5, 10, 22]])print(“A[0] =”, A[0]) # Dòng đầu tiênprint(“A[2] =”, A[2]) # Dòng thứ 3print(“A[-1] =”, A[-1]) # Dòng cuối cùng (dòng thứ 3)
Output được trả về ở đây là:
A[0] = [1, 4, 5, 12]
A[2] = [-1, 5, 10, 22]
A[-1] = [-1, 5, 10, 22]
Xuất các cột của ma trận
import numpy as npA = np.array([[1, 4, 5, 12],[-2, 8, 6, 14],[-1, 5, 10, 22]])print(“A[:,0] =”,A[:,0]) # Cột đầu tiênprint(“A[:,3] =”, A[:,3]) # Cột thứ 4print(“A[:,-1] =”, A[:,-1]) # Cột cuối cùng (Cột thứ 4)
Output được trả về:
A[:,0] = [ 1 -2 -1]
A[:,3] = [12 14 22]
A[:,-1] = [12 14 22]
Kết luận
Trong bài này, Kteam đã hướng dẫn bạn cách viết hàm với tham số truyền vào là một danh sách hai chiều kích thước MxN. Trả về danh sách hai chiều chuyển vị (cột thành hàng, hàng thành cột). Thêm bài giải của bạn vào phần bình luận để được Kteam review code và fix lỗi (nếu có) trong livestream của khóa học này.
Ở bài tiếp theo, chúng ta sẽ cũng nhau học cách VIẾT HÀM TRẢ VỀ DANH SÁCH PHẦN TỬ XUẤT HIỆN Ở TẤT CẢ CÁC HÀNG. (THAM SỐ LÀ DANH SÁCH HAI CHIỀU MxN).
Cảm ơn các bạn đã theo dõi bài viết. Hãy để lại bình luận hoặc góp ý của bạn để phát triển bài viết tốt hơn. Đừng quên ” Luyện tập – Thử Thách – Không ngại khó!”
2.Khởi tạo một ma trận
2.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ỏ.
>>> import numpy as np >>> A = np.array([[1, 2], [3, 4]]) >>> A 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à
float
,
type
của mọi phần tử trong mảng sẽ được coi là
'numpy.float64'
(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 xuất hiện),
type
của mọi phần tử trong mảng sẽ được coi là
'numpy.int64'
(số nguyên 64 bit).
Nếu muốn chỉ định
type
của các phần tử trong mảng, ta cần đặt giá trị cho
dtype
.
Ví dụ:
>>> B = np.array([[1, 2, 3], [4, 5, 6]], dtype = np.float) >>> type(B[0][0])
Bài tập:
Khai báo một mảng numpy hai chiều mô tả ma trận:
\[\mathbf{A} = \left[ \begin{matrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{matrix} \right] \]
1.Tích giữa một ma trận với véc tơ¶
Bản chất của phép nhân một ma trận với một véc tơ là một phép biến hình. Giả sử bạn có ma trận \(\mathbf{A} \in \mathbb{R}^{m \times n}\) và véc tơ \(\mathbf{x} \in \mathbb{R}^{n}\). Khi đó tích giữa ma trận \(\mathbf{A}\) với véc tơ \(\mathbf{x}\) là một véc tơ \(\mathbf{y}\) trong không gian mới \(\mathbf{y} \in \mathbb{R}^{m}\). \(\mathbf{y}\) được xem như ảnh của \(\mathbf{x}\) khi chiếu lên không gian \(m\) chiều thông qua hàm ánh xạ \(f(\mathbf{x}) = \mathbf{A}\mathbf{x}\).
Như vậy thông qua ma trận \(\mathbf{A}\) chúng ta đã biến đổi véc tơ \(\mathbf{x}\) từ không gian \(n\) chiều sang véc tơ \(\mathbf{y}\) trong không gian \(m\) chiều. Khi lựa chọn số chiều \(m\) trong không gian mới nhỏ hơn, chúng ta thu được một đầu ra \(\mathbf{y}\) là hình ảnh giảm chiều của véc tơ đầu vào \(\mathbf{x}\). Phép biến đổi này thường xuyên được áp dụng trong machine learning để nhằm giảm chiều dữ liệu, đặc biệt là ở những layer fully connected cuối cùng của mạng nơ ron. Trong phân tích suy biến (singular decomposition) chúng ta cũng sử dụng phép biến đổi không gian để tạo thành một véc tơ mới sao cho tích vô hướng giữa hai véc tơ bất kì được bảo toàn. Bạn sẽ được đọc thêm về phép phân tích suy biến ở những chương sau. Các phép xoay ảnh cũng biến đổi toạ độ các điểm sang không gian mới bằng cách nhân véc tơ toạ độ của chúng với ma trận xoay rotation.
Một ứng dụng đặc biệt quan trọng của phép nhân ma trận với một véc tơ là trong hồi qui tuyến tính. Để tính được giá trị dự báo của biến mục tiêu \(\hat{y}\) chúng ta cần nhân ma trận đầu vào \(\mathbf{X}\) với véc tơ hệ số ước lượng \(\mathbf{w}\). Ví dụ, khi đã biết được các biến đầu vào gồm: diện tích và số phòng ngủ như các dòng của ma trận bên dưới:
import torch X = torch.tensor([[100, 120, 80, 90, 105, 95], [2, 3, 2, 2, 3, 2]])
import numpy as np X = np.array([[100, 120, 80, 90, 105, 95], [2, 3, 2, 2, 3, 2]])
Và hệ số hồi qui tương ứng với với chúng lần lượt là \(\mathbf{w} = (10, 100)\). Khi đó giá nhà có thể được ước lượng bằng tích \(\mathbf{y} = \mathbf{X}^{\top}\mathbf{w}\)
w = torch.tensor([[10], [100]]) y = X.T@w y
w = np.array([[10], [100]]) y = X.T@w y
Code mẫu
def nhap_danh_sach(M, N): #Khoi tao danh sach rong danhSach2Chieu = [] for i in range(M): #Nhap du lieu tung hang tu ban phim va cat thanh list cac phan tu hang = input().split() #Kiem tra so phan tu co dung kich thuoc if len(hang) != N: print("Danh sach hai chieu khong dung kich thuoc!") return None #Them hang vao danh sach 2 chieu danhSach2Chieu.append(hang) return danhSach2Chieu def in_danh_sach(danhSach2Chieu): #Su dung vong lap for duyet tung hang cua danh sach 2 chieu for hang in danhSach2Chieu: #Unpacking arguments print(*hang) def danh_sach_chuyen_vi(danhSach2Chieu): #Khoi tao danh sach rong dsChuyenVi = [] #So dong cua danh sach moi bang so cot cua danh sach cu va nguoc lai M = len(danhSach2Chieu[0]) N = len(danhSach2Chieu) #Su dung vong lap for duyet tung cot cua danh sach 2 chieu for i in range(M): #List Comprehension lay phan tu thu i cua tat ca cac hang cot = [danhSach2Chieu[j][i] for j in range(N)] #Them vao danh sach chuyen vi moi dsChuyenVi.append(cot) return dsChuyenVi #Khoi lenh co the phat sinh loi try: #Nhap kich thuoc danh sach 2 chieu tu ban phim #M - So dong, N - So cot M, N = map(int, input().split()) #Kiem tra dieu kien M, N <=0 if M <=0 or N <=0: print("Vui long nhap kich thuoc danh sach la so nguyen duong!") else: #Goi ham nhap danh sach va truyen vao tham so kich thuoc M, N danhSach2Chieu = nhap_danh_sach(M, N) if danhSach2Chieu is not None: #Goi ham va truyen vao tham so la danh sach 2 chieu dsChuyenVi = danh_sach_chuyen_vi(danhSach2Chieu) in_danh_sach(dsChuyenVi) #Khoi lenh duoc thuc thi khi loi xay ra except: print("Dinh dang dau vao khong hop le!")
Cách tạo array của NumPy
Mảng số nguyên, số thực, số phức (integer, float, complex)
import numpy as np
A = np.array([[1, 2, 3], [3, 4, 5]])
print(A)
A = np.array([[1.1, 2, 3], [3, 4, 5]]) # mảng số thực
print(A)
A = np.array([[1, 2, 3], [3, 4, 5]], dtype = complex) # mảng số phức
print(A)
Chương trình trả về kết quả:
[[1 2 3]
[3 4 5]]
[[1.1 2. 3. ]
[3. 4. 5. ]]
[[1.+0.j 2.+0.j 3.+0.j]
[3.+0.j 4.+0.j 5.+0.j]]
Mảng giá trị mặc định (0 và 1)
import numpy as np# Mọi phần tử đều là 0A = np.zeros( (2, 3) )print(A)# Output:[[0. 0. 0.][0. 0. 0.]]# Mọi phần tử đều là 1B = np.ones( (1, 5) )print(B)# Output: [[1 1 1 1 1]]
Sử dụng arange() và shape()
import numpy as npA = np.arange(4)print(‘A =’, A)B = np.arange(12).reshape(2, 6)print(‘B =’, B)# Output:A = [0 1 2 3]B = [[ 0 1 2 3 4 5][ 6 7 8 9 10 11]]
1.Tích vô hướng (inner product)¶
Tích vô hướng giữa hai véc tơ \(\mathbf{x}, \mathbf{y} \in \mathbb{R}^{d}\) có cùng kích thước là một số vô hướng được ký hiệu là \(\langle \mathbf{x}, \mathbf{y} \rangle\) hoặc \(\mathbf{x}^{\top}\mathbf{y}\) có công thức như sau:
import torch x = torch.tensor([1, 2, 3]) y = torch.tensor([2, 3, 4]) x.dot(y)
import numpy as np x = np.array([1, 2, 3]) y = np.array([2, 3, 4]) x.dot(y)
Tích vô hướng rất quan trọng. Đây cũng là lý do mà tôi phải tách chúng thành một mục riêng. Bạn có thể bắt gặp tích vô hướng rất nhiều trong machine learning. Bên dưới là một số tình huống thường gặp:
-
Tích vô hướng có thể được sử dụng để tính giá trị ước lượng của phương trình hồi qui tuyến tính. Ví dụ nếu bạn biết giá nhà được biểu diễn theo diện tích \(x_1\) và số phòng ngủ \(x_2\) theo công thức:
Thì một cách khái quát bạn có thể ước lượng \(y\) theo tích vô hướng giữa véc tơ đầu vào \(\mathbf{x}^{\top} = (x_1, x_2, 1)\) và véc tơ hệ số \(\mathbf{w} = (20, 10, 200)\) như sau:
-
Tích vô hướng cũng được sử dụng để tính trung bình có trọng số của \(\mathbf{x}\):
với \(\sum_{i=1}^{n} q_i= 1\)
-
Ngoài ra, chắc hẳn bạn còn nhớ cách tính cos giữa hai véc tơ \(\mathbf{x}\) và \(\mathbf{y}\) sẽ bằng tích vô hướng giữa hai véc tơ được chuẩn hoá theo norm chuẩn bậc 2.
Khái niệm về norm chuẩn bậc 2 cũng là một kiến thức rất quan trọng. Mình sẽ giúp các bạn tìm hiểu bên dưới.
Tải xuống
Tài liệu
Nhằm phục vụ mục đích học tập Offline của cộng đồng, Kteam hỗ trợ tính năng lưu trữ nội dung bài học Viết hàm trả về danh sách hai chiều chuyển vị. (Tham số là danh sách hai chiều MxN) dưới dạng file PDF trong link bên dưới.
Ngoài ra, bạn cũng có thể tìm thấy các tài liệu được đóng góp từ cộng đồng ở mục TÀI LIỆU trên thư viện Howkteam.com
Đừng quên like và share để ủng hộ Kteam và tác giả nhé!
Ma trận trong Python
Ma trận trong Python là gì? Cách tạo ma trận trong Python như thế nào? Hãy cùng Quantrimang.com tìm hiểu nhé!
Python là một trong số ngôn ngữ lập trình phổ biến nhất hiện nay. Chính vì thế, nhu cầu học Python rất lớn. Thực tế, sử dụng ngôn ngữ lập trình này không khó. Hãy bắt đầu từ những hàm và đối tượng cơ bản nhất, ma trận hay matrix là một trong số đó.
Một số thao tác phép toán trong Numpy
- add (): – Hàm này được sử dụng để thực hiện phép cộng ma trận phần tử wise
- subtract (): – Hàm này dùng để thực hiện phép trừ ma trận phần tử .
- split (): – Hàm này được sử dụng để thực hiện phép chia ma trận phần tử wise.
Ví dụ
# Python code to demonstrate matrix operations
# add(), subtract() and divide()
# importing numpy for matrix operations
import numpy
# initializing matrices
x = numpy.array([[1, 2], [4, 5]])
y = numpy.array([[7, 8], [9, 10]])
# using add() to add matrices
print (“The element wise addition of matrix is : “)
print (numpy.add(x,y))
# using subtract() to subtract matrices
print (“The element wise subtraction of matrix is : “)
print (numpy.subtract(x,y))
# using divide() to divide matrices
print (“The element wise division of matrix is : “)
print (numpy.divide(x,y))
Kết quả
The element wise addition of matrix is :
[[ 8 10]
[13 15]]
The element wise subtraction of matrix is :
[[-6 -6]
[-5 -5]]
The element wise division of matrix is :
[[ 0.14285714 0.25 ]
[ 0.44444444 0.5 ]]
- Nhân (): – Hàm này được sử dụng để thực hiện phép nhân ma trận phần tử .
- dot (): – Hàm này được sử dụng để tính toán phép nhân ma trận, chứ không phải phép nhân phần tử wise .
- sqrt (): – Hàm này dùng để tính căn bậc hai của từng phần tử của ma trận.
- sum (x, axis): – Hàm này dùng để cộng tất cả các phần tử trong ma trận . Đối số “trục” tùy chọn tính tổng cột nếu trục là 0 và tổng hàng nếu trục là 1 .
- “T”: – Đối số này được sử dụng để chuyển vị trí của ma trận được chỉ định.
Return của numpy.transpose()
Hàm này trả về một ndarray. Mảng đầu ra là mảng nguồn, với trục của nó được hoán vị. Một chế độ xem được trả lại bất cứ khi nào có thể.
Ví dụ 1: numpy.transpose ()
import numpy as np a= np.arange(6).reshape((2,3)) a b=np.transpose(a) b
Output:
Trong đoạn code trên
- Chúng tôi đã tạo một mảng ‘a’ bằng cách sử dụng hàm np.arange () và tạo ra một hình dạng bằng cách sử dụng hàm reshape ().
- Chúng ta đã khai báo biến ‘b’ và gán giá trị trả về của hàm np.transpose ().
- Chúng tôi đã chuyển mảng ‘a’ trong hàm.
- Cuối cùng, chúng tôi đã cố gắng in giá trị của b.
Trong đầu ra, mảng chuyển vị của mảng ban đầu đã được hiển thị.
Ví dụ 2: numpy.transpose () với trục
import numpy as np a= np.array([[1, 2], [4, 5], [7, 8]]) a b=np.transpose(a, (1,0)) b
Output:
Trong đoạn code trên
- Chúng tôi đã tạo một mảng ‘a’ bằng hàm np.array ().
- Chúng ta đã khai báo biến ‘b’ và gán giá trị trả về của hàm np.transpose ().
- Chúng ta đã chuyển mảng ‘a’ và trục trong hàm.
- Cuối cùng, chúng tôi đã cố gắng in giá trị của b.
Trong đầu ra, mảng chuyển vị của mảng ban đầu đã được hiển thị.
Ví dụ 3: Định vị lại các phần tử bằng cách sử dụng numpy.transpose ()
import numpy as np a=np.ones((12,32,123,64)) b=np.transpose(a,(1,3,0,2)).shape b c=np.transpose(a,(0,3,1,2)).shape c
Output:
- Chúng tôi đã tạo một mảng ‘a’ bằng hàm np.ones ().
- Chúng ta đã khai báo biến ‘b’ và ‘c’ và gán giá trị trả về của hàm np.transpose ().
- Chúng ta đã chuyển mảng ‘a’ và vị trí của các phần tử mảng trong hàm.
- Cuối cùng, chúng tôi đã cố gắng in giá trị của b và c.
- Trong đầu ra, một mảng đã được hiển thị có các phần tử nằm ở vị trí xác định trong mảng.
Xem thêm Các lưu ý cần thiết để tăng năng suất khi lập trình (CODING)
Ưu điểm và hạn chế của numpy.transpose()
Ưu điểm của numpy.transpose():
- Chuyển đổi hình dạng mảng: numpy.transpose() cho phép bạn chuyển đổi hình dạng của mảng bằng cách hoán đổi các trục hoặc chiều dữ liệu. Bằng cách này, bạn có thể thay đổi cách tổ chức và truy cập dữ liệu trong mảng để phù hợp với yêu cầu của bạn.
- Tăng hiệu suất tính toán: numpy.transpose() không sao chép dữ liệu khi thực hiện việc chuyển đổi trục. Thay vào đó, nó chỉ thay đổi cách chỉ mục dữ liệu. Điều này giúp tiết kiệm bộ nhớ và tăng hiệu suất tính toán, đặc biệt là khi làm việc với các mảng lớn.
- Đa dạng ứng dụng: numpy.transpose() có thể được sử dụng trong nhiều ngữ cảnh và ứng dụng khác nhau. Bạn có thể sử dụng nó để chuyển đổi ma trận, mảng nhiều chiều, hoặc để chuẩn hóa dữ liệu cho các thuật toán xử lý dữ liệu khác.
Hạn chế của numpy.transpose():
- Không thay đổi mảng gốc: numpy.transpose() không thay đổi mảng ban đầu mà chỉ trả về một mảng mới đã được chuyển đổi. Điều này có thể yêu cầu bạn lưu kết quả vào một biến mới hoặc ghi đè lên mảng gốc nếu cần thiết.
- Cần kiểm tra kích thước mảng: Khi sử dụng numpy.transpose(), bạn cần kiểm tra kích thước và hình dạng của mảng để đảm bảo rằng chuyển đổi trục được thực hiện đúng. Nếu kích thước không phù hợp, bạn sẽ nhận được một mảng mới với hình dạng không mong muốn hoặc gặp lỗi.
- Phụ thuộc vào bộ nhớ: Một số chức năng numpy như numpy.transpose() có thể tiêu tốn nhiều bộ nhớ. Khi làm việc với các mảng lớn hoặc có kích thước lớn, bạn cần đảm bảo rằng hệ thống của bạn đủ bộ nhớ để thực hiện chuyển đổi mà không gây ra quá tải hoặc lỗi.
Tóm lại, numpy.transpose() là một công cụ hữu ích để chuyển đổi hình dạng của mảng trong NumPy. Bạn cần chú ý đến kiểm tra kích thước mảng và quản lý bộ nhớ để sử dụng nó một cách hiệu quả và đảm bảo tính chính xác của kết quả.
Đại số tuyến tính¶
Lát cắt của Ma trận
Lát cắt của mảng một chiều trong NumPy được biểu diễn tương tự như list.
import numpy as np
A = np.array([1, 3, 5, 7, 9, 7, 5])
# Phần tử thứ tự từ 3 đến 5
print(A[2:5]) # Output: [5, 7, 9]
# Phần tử thứ tự từ 1 đến 4
print(A[:-5]) # Output: [1, 3]
# Phần tử thứ 6 trở đi
print(A[5:]) # Output:[7, 5]
# Lấy cả mảng
print(A[:]) # Output:[1, 3, 5, 7, 9, 7, 5]
# đổi chiều mảng
print(A[::-1]) # Output:[5, 7, 9, 7, 5, 3, 1]
Vậy để cắt ma trận, ta có ví dụ sau:
import numpy as npA = np.array([[1, 4, 5, 12, 14],[-5, 8, 9, 0, 17],[-6, 7, 11, 19, 21]])print(A[:2, :4]) # 2 hàng, 4 cột”’ Output:[[ 1 4 5 12][-5 8 9 0]]”’print(A[:1,]) # hàng đầu tiên, tất cả cột”’ Output:[[ 1 4 5 12 14]]”’print(A[:,2]) # tất cả các hàng, cột 2”’ Output:[ 5 9 11]”’print(A[:, 2:5]) # tất cả các hàng, cột 3 đến 5”’Output:[[ 5 12 14][ 9 0 17][11 19 21]]”’
2.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.
Ví dụ, nếu một mảng numpy hai chiều mô tả ma trận:
\(\left[
\begin{matrix} 1 & 2 \\ 3 & 4 \end{matrix} \right]
\), khi được in ra nó sẽ có dạng:
array([[1, 2], [3, 4]])
Ở đâ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
[]
:
-
hai mảng
[1, 2]
và
[3, 4]
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
[[1, 2], [3, 4]]
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à
[[1, 2], [3, 4]]
được coi là mảng ứng với
axis = 0
. Trong mảng này, thành phần thứ nhất là
[1, 2]
, thành phần thứ hai là
[3, 4]
. -
hai mảng lớn thứ hai là
[1, 2]
và
[3, 4]
được coi là các mảng ứng với
axis = 1
.
(Xem thêm hình vẽ bên.)
Chú ý:
-
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,
axis
cũng đi từ
0, 1, ...
theo thứ tự đó. -
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.
-
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, …
1.Số vô hướng (scalar)¶
Trong cuộc sống hàng ngày chúng ta sẽ gặp rất nhiều số vô hướng (scalar). Giá trị của tiền nhà tháng này mà bạn phải trả cho chủ nhà là một số vô hướng. Bạn vừa thực hiện một bài kiểm tra toán, bạn được 9 điểm thì điểm số này là một số vô hướng,… Tóm lại số vô hướng là một con số cụ thể. Số vô hướng sẽ khác với biến số vì biến số có thể nhận nhiều giá trị trong khi số vô hướng chỉ nhận một giá trị duy nhất. Ví dụ, khi biểu diễn giá nhà \(y\) theo diện tích \(x\) theo phương trình \(y=20x + 200\) thì các số vô hướng là \(20, 200\) và các biến là \(x, y\).
Để khởi tạo một số vô hướng, chúng ta sẽ sử dụng tensor
import torch a = torch.tensor(20) b = torch.tensor(200) print(“diện tích x = 50 –> giá nhà y = a*50+b = “, a*50+b)
import numpy as np a = np.array(20) b = np.array(200) print(“diện tích x = 50 –> giá nhà y = a*50+b = “, a*50+b)
Số vô hướng có thể được coi như hằng số trong một phương trình. Chúng ta có thể thực hiện các phép toán cộng/trừ/nhân/chia với số vô hướng như với hằng số.
2.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
axis
của ma trận.
axis = 0
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ự
axis = 1
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.
Xét một ma trận:
>>> import numpy as np >>> A = np.array([[1., 2, 3, 2], [4, 3, 7, 4], [1, 4, 2, 3]]) >>> A array([[ 1., 2., 3., 2.], [ 4., 3., 7., 4.], [ 1., 4., 2., 3.]])
Và các hàm
np.sum(), np.min(), np.max(), np.mean()
tác động lên theo
axis = 0
(tức các cột của ), kết quả sẽ là:
>>> np.sum(A, axis = 0) array([ 6., 9., 12., 9.]) >>> np.min(A, axis = 0) array([ 1., 2., 2., 2.]) >>> np.max(A, axis = 0) array([ 4., 4., 7., 4.]) >>> np.mean(A, axis = 0) array([ 2., 3., 4., 3.])
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 .
Tương tự như thế khi thay
axis = 1
:
>>> np.sum(A, axis = 1) array([ 8., 18., 10.]) >>> np.min(A, axis = 1) array([ 1., 3., 1.]) >>> np.max(A, axis = 1) array([ 3., 7., 4.]) >>> np.mean(A, axis = 1) array([ 2. , 4.5, 2.5])
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
axis
, kết quả được tính trên toàn bộ ma trận:
>>> np.sum(A) 36.0 >>> np.min(A) 1.0 >>> np.max(A) 7.0 >>> np.mean(A) 3.0
keepdims = True
Đô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
axis = 0
là các vector hàng thực sự, khi
axis = 1
là các vector cột thực sự.
Để làm được việc đó, Numpy cung cấp thuộc tính
keepdims = True
(mặc định là
False
). Khi
keepdims = True
, nếu sử dụng
axis = 0
, 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
axis = 1
, 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:
>>> np.sum(A, axis = 0, keepdims = True) array([[ 6., 9., 12., 9.]]) >>> np.mean(A, axis = 1, keepdims = True) array([[ 2. ], [ 4.5], [ 2.5]])
Bài tập:
Cho một ma trận 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
myfunc
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 trong bài học, độ biến động của mỗi hàng lần lượt là
2.0, 4.0, 3.0
. Vậy
myfunc(A) = 9.0
.
1.Biến đổi hệ cơ sở của véc tơ¶
Trong không gian \(m\) chiều thì mọi véc tơ đều có thể biểu diễn thông qua hệ véc tơ đơn vị \((\mathbf{e}_1, \mathbf{e}_2, \dots , \mathbf{e}_m)\). Trong đó véc tơ \(\mathbf{e}_i\) được gọi là véc tơ đơn vị có phần tử thứ \(i\) là 1, các phần tử còn lại bằng 0.
Bản chất của một phép nhân ma trận với một véc tơ là một phép biến đổi hệ cơ sở mà ở đó mỗi một cột của ma trận được xem như một véc tơ cơ sở. Giả sử ma trận \(\mathbf{A} \in \mathbb{R}^{m \times n}\) nhân với véc tơ \(\mathbf{x}\in \mathbb{R}^{n}\).
Trong đó \(\mathbf{a}^{(i)}\) có thể được xem như là một véc tơ cột thứ \(i\) của ma trận \(\mathbf{A}\). Ta có thể xem như véc tơ \(\mathbf{y}\) được biểu diễn thông qua các véc tơ cơ sở cột mà toạ độ tương ứng với mỗi chiều trong hệ cơ sở là các \(x_i\).
Nội dung
Để theo dõi bài này tốt nhất bạn cần có kiến thức về:
Trong bài này chúng ta sẽ cùng tìm hiểu về:
- Định nghĩa ma trận và vector
- Cách khởi tạo ma trận và vector
- Các toán tử với ma trận
- Identify matrix và Transpose matrix
- Ý nghĩa của ma trận và vector trong Machine Learning
Thảo luận
Nếu bạn có bất kỳ khó khăn hay thắc mắc gì về khóa học, đừng ngần ngại đặt câu hỏi trong phần bên dưới hoặc trong mục HỎI & ĐÁP trên thư viện Howkteam.com để nhận được sự hỗ trợ từ cộng đồng.
Nội dung bài viết
Khóa học
Serial dành cho những bạn cần luyện tập phương pháp, tu duy lập trình. Làm quen với các bài toán trong lập trình, ngẫu nhiên từ cơ bản đến nâng cao. Nội dung Serial này được phân tách chi tiết nhất có thể, nhằm giúp các bạn dễ hiểu và thực hành được ngay.
Bạn nên tự làm lại từng bài tập trên video để có kết quả tốt nhất. Cùng Kteam “Luyện tập – Thử thách – không ngại khó”
Bình luận
m=int(input(“Số dòng: “))
n=int(input(“Số cột: “))
# CÁCH 1:———————————————————–
def func_(m,n):
matrix=[] # Thiết lập matrix
row=[]
for i in range(m):
for j in range(n):
value=str(input(f’Nhập giá trị dòng {i+1}, cột {j+1}: ‘))
row.append(value)
matrix.append(row) # Thêm cả dòng vào matrix
row=[]
row=[] # Chuyển vị ma trận
matrix_new=[]
for j in range(4):
for i in range(3):
value=matrix[i][j]
row.append(value)
matrix_new.append(row)
row=[]
for row in matrix: # in ma trận
for value in row:
print(value, end=”\t”) # ‘/t’ để tạo khoảng trắng thay tab
print()
print(“MATRIX NEW CÁCH 1”)
for row in matrix_new: # in ma trận
for value in row:
print(value, end=”\t”) # ‘/t’ để tạo khoảng trắng thay tab
print()
func_(m,n)
# CÁCH 2:———————————————————–
def func_2(m,n):
matrix=[] # Thiết lập matrix
row=[]
for i in range(m):
for j in range(n):
value=str(input(f’Nhập giá trị dòng {i+1}, cột {j+1}: ‘))
row.append(value)
matrix.append(row) # Thêm cả dòng vào matrix
row=[]
matrix_new=[] # Chuyển vị matrix
row_new=[]
for j in range(n):
row_new=[matrix[i][j] for i in range(m)]
matrix_new.append(row_new)
row_new=[]
print(“MATRIX NEW CÁCH 2”)
for row in matrix_new: # in ma trận
for value in row:
print(value, end=”\t”) # ‘/t’ để tạo khoảng trắng thay tab
print()
func_2(m,n)
def Ketqua(a):
Day=[]
for i in range(0,Dong):
i=input()
if len(i.split())
print(“Danh sach hai chieu khong dung kich thuoc da khai bao!”)
return None
Day.append(i)
for n in range(0,phantu):
Hang=[]
for x in Day:
Hang.append(x.split()[n])
print(*Hang)
cờ=False
try:
a=input(“Nhập kích thước: “)
Dong,phantu=map(int,a.split())
cờ=True
except:
print(“Dinh dang dau vao khong hop le!”)
if cờ:
if Dong>0 and phantu>0:
Danhsach=Ketqua(a)
else:
print(“Vui lòng nhập số nguyên dương”)
def transposeMatrix(matrix): new_matrix = map(list , zip(*matrix)) for i in new_matrix: print(*i)
def xu_ly(ma_tran, dong_cot): dong = int(dong_cot[0]) cot = int(dong_cot[1]) print("-------") for j in range(cot): for i in range(dong): print(ma_tran[i][j], end = " ") print('') def dau_vao(a): ma_tran = [] for i in range(int(a[0])): dong = input().split() ma_tran.append(dong) return ma_tran def kiem_tra(dong_cot, ma_tran): try: dong = int(dong_cot[0]) cot = int(dong_cot[1]) if dong <= 0 or cot <= 0: return "a" elif len(dong_cot) > 2: return "c" else: for i in ma_tran: if len(i) != cot: return "b" except: return "c" def running(kiem_tra, dong_cot, ma_tran): if kiem_tra == "a": print("Vui lòng nhập kích thước dánh sách là số nguyên dương!") elif kiem_tra == "b": print("Danh sách hai chiều không đúng kích thước đã khai báo!") elif kiem_tra == "c": print("Định dạng đầu vào không hợp lệ!") else: xu_ly(ma_tran, dong_cot) def main(): dong_cot = input().split() ma_tran = dau_vao(dong_cot) kiem_tra1 = kiem_tra(dong_cot, ma_tran) running(kiem_tra1, dong_cot, ma_tran) main()
def transposed_list(m, n): lst = [] check = True for row in range(m): row = input().split() lst.append(row) if len(row) != n: check = False if len(lst) < m: check = False if check == True: for j in range(len(row)): for i in range(len(lst)): print(lst[i][j], end = " ") print() else: print("Danh sách hai chiều không đúng kích thước!") try: m, n = map(int, input().split()) if m < 0 or n < 0: print("Vui lòng nhập số nguyên dương!") else: transposed_list(m, n) except: print("Định dạng đầu vào không hợp lệ!")
Hàm numpy.transpose () là một trong những hàm quan trọng nhất trong phép nhân ma trận. Hàm này hoán vị hoặc bảo lưu kích thước của mảng đã cho và trả về mảng đã sửa đổi.
Các bài viết liên quan:
Hàm numpy.transpose () thay đổi các phần tử hàng thành phần tử cột và phần tử cột thành phần tử hàng. Đầu ra của hàm này là một mảng đã sửa đổi của hàm ban đầu.
Cú pháp
numpy.transpose(arr, axis=None)
Inverse matrix (ma trận khả nghịch)
Inverse matrix được kí hiệu bằng: A-1
Tích của ma trận với ma trận đảo của nó sẽ là một Identity matrix.
Tương tự như trong số tự nhiên: 2 * 2-1 = 1
Với NumPy function dùng để invert matrix là:
np.linalg.pinv(matrix)
Ví dụ:
import numpy as np _a = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] a = np.array(_a) a_i = np.linalg.pinv(a) #Create inverse of a print(a_i) print(a @ a_i)
Lưu ý: Identity matrix này hiển thị giá trị rất nhỏ thay cho số 0, ta có thể làm tròn để có identity matrix chính xác. Một số ma trận không thể invert.
Tham số của numpy.transpose()
- arr: array_like
Nó là một ndarray. Nó là mảng nguồn có các phần tử mà chúng ta muốn chuyển vị. Tham số này rất cần thiết và đóng một vai trò quan trọng trong hàm numpy.transpose ().
- axis: Danh sách ints ()
Nếu chúng tôi không chỉ định trục, thì theo mặc định, nó sẽ đảo ngược các kích thước nếu không sẽ hoán vị trục theo các giá trị đã cho.
Xem thêm Function trong R, các hàm trong R
2.Các phép toán tác động đến mọi phần tử của ma trận
2.7.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ụ:
>>> import numpy as np >>> A = np.array([[1, 3], [2, 5]]) >>> A array([[1, 3], [2, 5]]) >>> A + 2 array([[3, 5], [4, 7]]) >>> A*2 array([[ 2, 6], [ 4, 10]]) >>> 2**A array([[ 2, 8], [ 4, 32]])
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.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.
>>> A = np.random.randn(2, 3) # create a random numpy array with shape = (2, 3) >>> A array([[ 0.66079861, 2.11481663, -1.42221111], [-1.13931439, -0.31866767, -0.37294795]]) >>> np.abs(A) array([[ 0.66079861, 2.11481663, 1.42221111], [ 1.13931439, 0.31866767, 0.37294795]])
Bài tập: Frobenious norm
Frobenius 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
norm_fro(A)
tính Frobenius norm của một ma trận bất kỳ.
Ví dụ:
>>> A = np.array([[1, 3], [2, 5]]) >>> A array([[1, 3], [2, 5]])
thì
norm_fro(A) = 6.2449979983983983
\(= \sqrt{1^2 + 3^2 + 2^2 + 5^2}\).
Gợi ý: Sử dụng hàm
np.sqrt
.
Tải xuống
Tài liệu
Nhằm phục vụ mục đích học tập Offline của cộng đồng, Kteam hỗ trợ tính năng lưu trữ nội dung bài học Ma trận và vector với NumPy dưới dạng file PDF trong link bên dưới.
Ngoài ra, bạn cũng có thể tìm thấy các tài liệu được đóng góp từ cộng đồng ở mục TÀI LIỆU trên thư viện Howkteam.com
Đừng quên like và share để ủng hộ Kteam và tác giả nhé!
Một số thao tác tạo ma trận trong Python
from numpy import *
m = array([[‘Mon’,18,20,22,17],[‘Tue’,11,18,21,18],
[‘Wed’,15,21,20,19],[‘Thu’,11,20,22,21],
[‘Fri’,18,17,23,22],[‘Sat’,12,22,20,18],
[‘Sun’,13,15,19,16]])
m_r = append(m,[[‘Avg’,12,15,13,11]],0)
print(m_r)
Khi đoạn mã trên được thực thi, nó tạo ra kết quả sau:
[[‘Mon’ ’18’ ’20’ ’22’ ’17’]
[‘Tue’ ’11’ ’18’ ’21’ ’18’]
[‘Wed’ ’15’ ’21’ ’20’ ’19’]
[‘Thu’ ’11’ ’20’ ’22’ ’21’]
[‘Fri’ ’18’ ’17’ ’23’ ’22’]
[‘Sat’ ’12’ ’22’ ’20’ ’18’]
[‘Sun’ ’13’ ’15’ ’19’ ’16’]
[‘Avg’ ’12’ ’15’ ’13’ ’11’]]
>>> Xem thêm: Khóa học lập trình Python
Thêm một cột trong ma trận Python
Chúng ta có thể thêm cột vào ma trận bằng phương thức insert (). ở đây chúng ta phải đề cập đến chỉ mục nơi chúng ta muốn thêm cột và một mảng chứa các giá trị mới của các cột được thêm vào. Trong ví dụ dưới đây, một cột mới đã được thêm từ vị trí thứ 5
from numpy import *
m = array([[‘Mon’,18,20,22,17],[‘Tue’,11,18,21,18],
[‘Wed’,15,21,20,19],[‘Thu’,11,20,22,21],
[‘Fri’,18,17,23,22],[‘Sat’,12,22,20,18],
[‘Sun’,13,15,19,16]])
m_c = insert(m,[5],[[1],[2],[3],[4],[5],[6],[7]],1)
print(m_c)
Khi đoạn mã trên được thực thi, nó tạo ra kết quả sau:
[[‘Mon’ ’18’ ’20’ ’22’ ’17’ ‘1’]
[‘Tue’ ’11’ ’18’ ’21’ ’18’ ‘2’]
[‘Wed’ ’15’ ’21’ ’20’ ’19’ ‘3’]
[‘Thu’ ’11’ ’20’ ’22’ ’21’ ‘4’]
[‘Fri’ ’18’ ’17’ ’23’ ’22’ ‘5’]
[‘Sat’ ’12’ ’22’ ’20’ ’18’ ‘6’]
[‘Sun’ ’13’ ’15’ ’19’ ’16’ ‘7’]]
Xóa một hàng tạo thành một Ma trận Python
Chúng ta có thể xóa một hàng khỏi ma trận bằng phương thức delete (). Chúng ta phải chỉ định chỉ số của hàng và giá trị trục là 0 cho một hàng và 1 cho một cột.
from numpy import *
m = array([[‘Mon’,18,20,22,17],[‘Tue’,11,18,21,18],
[‘Wed’,15,21,20,19],[‘Thu’,11,20,22,21],
[‘Fri’,18,17,23,22],[‘Sat’,12,22,20,18],
[‘Sun’,13,15,19,16]])
m = delete(m,[2],0)
print(m)
Khi đoạn mã trên được thực thi, nó tạo ra kết quả sau:
[[‘Mon’ ’18’ ’20’ ’22’ ’17’]
[‘Tue’ ’11’ ’18’ ’21’ ’18’]
[‘Thu’ ’11’ ’20’ ’22’ ’21’]
[‘Fri’ ’18’ ’17’ ’23’ ’22’]
[‘Sat’ ’12’ ’22’ ’20’ ’18’]
[‘Sun’ ’13’ ’15’ ’19’ ’16’]]
Xóa một cột khỏi Ma trận Python
Chúng ta có thể xóa một cột khỏi ma trận bằng phương thức delete (). Chúng ta phải chỉ định chỉ số của cột và giá trị trục là 0 cho một hàng và 1 cho một cột.
from numpy import *
m = array([[‘Mon’,18,20,22,17],[‘Tue’,11,18,21,18],
[‘Wed’,15,21,20,19],[‘Thu’,11,20,22,21],
[‘Fri’,18,17,23,22],[‘Sat’,12,22,20,18],
[‘Sun’,13,15,19,16]])
m = delete(m,s_[2],1)
print(m)
Khi đoạn mã trên được thực thi, nó tạo ra kết quả sau:
[[‘Mon’ ’18’ ’22’ ’17’]
[‘Tue’ ’11’ ’21’ ’18’]
[‘Wed’ ’15’ ’20’ ’19’]
[‘Thu’ ’11’ ’22’ ’21’]
[‘Fri’ ’18’ ’23’ ’22’]
[‘Sat’ ’12’ ’20’ ’18’]
[‘Sun’ ’13’ ’19’ ’16’]]
Cập nhật một hàng trong Ma trận Python
Để cập nhật các giá trị trong hàng của ma trận, chúng ta chỉ cần gán lại các giá trị tại chỉ mục của hàng. Trong ví dụ dưới đây, tất cả các giá trị cho dữ liệu của ngày thứ hai được đánh dấu là 0. Chỉ số cho hàng này là 3.
from numpy import *
m = array([[‘Mon’,18,20,22,17],[‘Tue’,11,18,21,18],
[‘Wed’,15,21,20,19],[‘Thu’,11,20,22,21],
[‘Fri’,18,17,23,22],[‘Sat’,12,22,20,18],
[‘Sun’,13,15,19,16]])
m[3] = [‘Thu’,0,0,0,0]
print(m)
Khi đoạn mã trên được thực thi, nó tạo ra kết quả sau:
[[‘Mon’ ’18’ ’20’ ’22’ ’17’]
[‘Tue’ ’11’ ’18’ ’21’ ’18’]
[‘Wed’ ’15’ ’21’ ’20’ ’19’]
[‘Thu’ ‘0’ ‘0’ ‘0’ ‘0’]
[‘Fri’ ’18’ ’17’ ’23’ ’22’]
[‘Sat’ ’12’ ’22’ ’20’ ’18’]
[‘Sun’ ’13’ ’15’ ’19’ ’16’]]
Kết luận: Việc sử dụng NumPy trong việc tạo ma trận thay vì Nested list sẽ giúp bạn lập trình một cách dễ dàng hơn, đặc biệt trong việc nghiên cứu dữ liệu, khoa học.
Nguồn tham khảo: Tutorialspoint, Geeksforgeeks
Ma trận và vector với NumPy
2.Tích giữa hai ma trận, tích giữa ma trận và vector
2.11.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 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 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
A, B
trong đó
A.shape[1] == B.shape[0]
(đừ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
.dot
hoặc hàm
np.dot
:
>>> import numpy as np >>> A = np.arange(12).reshape(4, 3) >>> A array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]]) >>> B = np.arange(-5, 7).reshape(3,-1) >>> B array([[-5, -4, -3, -2], [-1, 0, 1, 2], [ 3, 4, 5, 6]]) >>> A.dot(B) array([[ 5, 8, 11, 14], [ -4, 8, 20, 32], [-13, 8, 29, 50], [-22, 8, 38, 68]]) >>> np.dot(A, B) array([[ 5, 8, 11, 14], [ -4, 8, 20, 32], [-13, 8, 29, 50], [-22, 8, 38, 68]])
2.11.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:
>>> A array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]]) >>> b = np.array([1, 3, 4]) >>> A.dot(b) array([11, 35, 59, 83]) >>> A*b array([[ 0, 3, 8], [ 3, 12, 20], [ 6, 21, 32], [ 9, 30, 44]])
Tích của mảng hai chiều và mảng một chiều với
A.shape[1] == b.shape[0]
theo ĐSTT được thực hiện bằng phương thức
.dot()
của mảng numpy . Kết quả trả về là một mảng một chiều có
shape[0] == 4
.
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ó
shape[1] = 1
) như trên lý thuyết. Kết quả
của
A*b
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:
>>> b.dot(A) Traceback (most recent call last): File "
", line 1, in
ValueError: shapes (3,) and (4,3) not aligned: 3 (dim 0) != 4 (dim 0) >>> c = np.array([1, 2, 3, 4]) >>> c.dot(A) array([60, 70, 80])
ta thấy rằng nếu đặt lên trước thì có lỗi xảy ra vì xung đột chiều. Tuy nhiên nếu mảng một chiều có kích thước bằng thì lại có thể nhân với mảng hai chiều được.
Kết quả thu được chính là vector hàng nhân với ma trận . (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 , hãy viết hàm
fro_trace
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
np.diag
, hoặc -
sử dụng
np.trace
(gõ
help(np.trace)
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 đó ;).
1.Tensor¶
Tensor là một định dạng đặc biệt được sáng tạo ra bởi google. Nó tổng quát hơn so với ma trận vì có thể biểu diễn được các không gian với số chiều tuỳ ý. Chẳng hạn trong xử lý ảnh chúng ta có một bức ảnh với kích thước là \(W \times H \times C\) lần lượt \(W, H, C\) là chiều width, height và channels. Thông thường \(C = 1\) hoặc \(3\) tuỳ theo ảnh là ảnh xám hay ảnh màu RGB. Trong huấn luyện mô hình phân loại ảnh thì các đầu vào được kết hợp theo mini-batch nên sẽ có thêm một chiều về batch_size. Do đó input có kích thước là \(N \times W \times H \times C\).
1.4.Các thuộc tính của tensor¶
Một tensor được đặc trưng bởi kích thước các chiều, số lượng chiều, định dạng dữ liệu của tensor.
A = torch.tensor([[[1, 2, 3], [3, 2, 1]], [[2, 1, 2], [1, 3, 0]]]) # Kích thước của tensor print(“shape of A: ” , A.size()) # Số chiều print(“total dim: “, A.ndim) # Định dạng dữ liệu print(“dtype: “, A.dtype)
A = np.array([[[1, 2, 3], [3, 2, 1]], [[2, 1, 2], [1, 3, 0]]]) # Kích thước của array print(“shape of A: ” , A.shape) # Số chiều print(“total dim: “, A.ndim) # Định dạng dữ liệu print(“dtype: “, A.dtype)
1.4.Các phép tính trên tensor¶
Tích thông thường giữa 2 tensors: Nếu tensor \(\mathbf{A}\) có kích thước \(m \times n \times p\) và tensor \(\mathbf{B}\) có kích thước \(n \times p \times q\) thì tích giữa chúng có kích thước là \(m \times n \times q\). Trên python chúng ta sử dụng ký hiệu để đại diện cho tích thông thường.
import torch A = torch.randn([2, 3, 4]) B = torch.randn([2, 4, 2]) # Tích giữa 2 tensor (A@B).size()
import numpy as np A = np.random.randn(2, 3, 4) B = np.random.randn(2, 4, 2) # Tích giữa 2 array (A@B).shape
Ngoài ra chúng ta có thể tính tích hadamard giữa 2 tensors \(\mathbf{A}\) và \(\mathbf{B}\) được ký hiệu bằng dấu như sau:
import torch A = torch.randn([2, 3, 4]) B = torch.randn([2, 3, 4]) # Tích hadamard giữa 2 tensor (A*B).size()
import numpy as np A = np.random.randn(2, 3, 4) B = np.random.randn(2, 3, 4) # Tích hadamard giữa 2 array (A*B).shape
Chúng ta cũng có thể thực hiện các phép cộng, trừ giữa các tensor cùng kích thước.
Phép cộng
# Phép cộng (A+B).size()
# Phép cộng (A+B).shape
Phép trừ
# Phép trừ (A-B).size()
# Phép trừ (A-B).shape
Truy cập thành phần: Để truy cập vào một mảng thành phần của \(\mathbf{A}\) chúng ta sẽ cần khai báo vị trí indices của chúng trên mỗi chiều của ma trận \(\mathbf{A}\). Cách truy cập cũng hoàn toàn tương tự như đối với ma trận.
import torch # Khởi tạo ma trận A kích thước m, n, p = 2, 3, 4 A = torch.randn([2, 3, 4]) # Truy cập ma trận đầu tiên A[:1, :, :]
import numpy as np # Khởi tạo ma trận A kích thước m, n, p = 2, 3, 4 A = np.random.randn(2, 3, 4) # Truy cập ma trận đầu tiên A[:1, :, :]
Truy cập ma trận đầu tiên và chỉ lấy dòng từ 1 tới 3
# Truy cập ma trận đầu tiên và chỉ lấy dòng từ 1 tới 3 A[0][1:3, :]
# Truy cập ma trận đầu tiên và chỉ lấy dòng từ 1 tới 3 A[0][1:3, :]
Truy cập tương ứng với các chiều m, n, p lần lượt index đầu tiên, 2 index đầu tiên, và index thứ 3.
# Truy cập tương ứng với các chiều m, n, p lần lượt index đầu tiên, 2 index đầu tiên, và index thứ 3. A[:1, :2, 3]
# Truy cập tương ứng với các chiều m, n, p lần lượt index đầu tiên, 2 index đầu tiên, và index thứ 3. A[:1, :2, 3]
Ma trận trong Python là gì?
Ma trận trong Python là một mảng Numpy hình chữ nhật. Mảng này phải là hai chiều. Nó chứa dữ liệu đã lưu trong hàng & cột của mảng. Ở một ma trận Python, các chuỗi mục nằm ngang được gọi là “hàng”, còn chuỗi mục nằm dọc gọi là “cột”. Hàng và cột được xếp chồng lên nhau giống như một danh sách lồng nhau. Nếu ma trận chứa số hàng “r” và số cột “c”, trong đó r và c là số nguyên dương, còn r x c quyết định thứ tự của đối tượng ma trận này.
Bạn có thể lưu trữ các chuỗi và đối tượng của kiểu dữ liệu khác trong ma trận. Dữ liệu được lưu trong chồng hàng & cột ở một ma trận. Ma trận là một cấu trúc dữ liệu quan trọng cho việc tính toán toán trong toán học và khoa học.
Đây là ma trận 3×4 vì nó có 3 hàng và 4 cột.
Python không có kiểu xây dựng riêng dành cho ma trận, vậy nên chúng ta có thể biểu diễn ma trận dưới dạng một nested list.
Vậy nested list là gì?
Nested list là dạng danh sách lồng ghép, nghĩa là một list xuất hiện với vai trò là phần tử của một list khác. Ví dụ:
A = [ 1, 4, 5, [8, 9]]
Ở ví dụ này, nếu in ra A[3] ta được output là [8, 9].
Nested list thường được dùng để trình bày ma trận trong Python. Biểu diễn như sau:
A = [[1, 4, 5],
[-5, 8, 9]]
Chúng ta có thể coi danh sách này là một ma trận gồm 2 hàng và 3 cột.
Để kết xuất phần tử từ ma trận, ta có thể chọn cả một hàng của ma trận theo cách thông thường hoặc dùng dạng chỉ số kép, chỉ số thứ nhất để chọn hàng, còn chỉ số thứ hai chọn cột. Cùng xem ví dụ sau:
A = [[1, 4, 5, 12],
[-5, 8, 9, 0],
[-6, 7, 11, 19]]
print("A =", A)
print("A[1] =", A[1]) # Hàng thứ 2 của ma trân
print("A[1][2] =", A[1][2]) # Phần tử thứ 3 của hàng thứ 2
print("A[0][-1] =", A[0][-1]) # Phần tử cuối cùng của hàng 1
column = [];
for row in A:
column.append(row[2])
print("Cột thứ 3 =", column)
Chạy chương trình, output được trả về là:
A = [[1, 4, 5, 12], [-5, 8, 9, 0], [-6, 7, 11, 19]]
A[1] = [-5, 8, 9, 0]
A[1][2] = 9
A[0][-1] = 12
Cột thứ 3 = [5, 9, 11]
Dùng nested list để biểu diễn ma trận là một cách thông dụng và thường dùng trong các tính toán đơn giản. Tuy nhiên có một cách hay hơn đó là sử dụng thư viện NumPy.
1.Ma trận¶
Véc tơ là đại lượng một chiều nên nó chỉ có thể biểu diễn cho một biến. Trong trường hợp chúng ta cần biểu diễn cho nhiều biến thì sẽ cần tới đại lượng hai chiều là ma trận. Ma trận được ký hiệu bởi một chữ cái in đậm \(\mathbf{A} \in \mathbb{R}^{m\times n}\) là một ma trận số thực có \(m\) dòng và \(n\) cột.
Để xác định một phần tử bất kỳ thuộc dòng thứ \(i\), cột thứ \(j\) của ma trận \(\mathbf{A}\) ta ký hiệu chúng là \(\mathbf{A}_{ij}\). Véc tơ dòng thứ \(i\) sẽ là \(\mathbf{A}_{i:}\) và véc tơ cột thứ \(j\) sẽ là \(\mathbf{A}_{:j}\). Để đơn giản hoá ta qui ước \(\mathbf{A}_{j}\) là véc tơ cột \(j\) và \(\mathbf{A}^{(i)}\) là véc tơ dòng \(i\).
1.3.Các ma trận đặc biệt¶
-
Ma trận vuông: Ma trận vuông là ma trận có số dòng bằng số cột. Ma trận vuông rất quan trọng vì khi tìm nghiệm cho hệ phương trình, từ ma trận vuông ta có thể chuyển sang ma trận tam giác. Ma trận vuông cũng là ma trận có thể tính được giá trị định thức. Tóm lại ma trận \(\mathbf{A} \in \mathbb{R}^{m \times n}\) vuông nếu \(m=n\).
-
Ma trận đơn vị: Là ma trận có đường chéo chính bằng 1, các phần tử còn lại bằng \(0\). Ví dụ ma trận đơn vị kích thước \(3 \times 3\) được ký hiệu là \(\mathbf{I}_3\) có gía trị là:
Tóm lại, \(\mathbf{A}\) là ma trận đơn vị nếu nó là ma trận vuông và \(a_{ij} = 1\) nếu \(i=j\) và \(a_{ij} = 0\) nếu \(i \neq j\).
-
Ma trận đường chéo: Là ma trận có các phần tử trên đường chéo chính khác 0 và các phần tử còn lại bằng 0. Ví dụ về ma trận đường chéo:
-
Ma trận chuyển vị: \(\mathbf{B}\) là ma trận chuyển vị của \(\mathbf{A}\) nếu \(b_{ij} = a_{ji}\) với mọi \(i, j\). Dễ hiểu hơn, tức là mọi dòng của ma trận \(A\) sẽ là cột của ma trận \(\mathbf{B}\). Ví dụ:
Ký hiệu chuyển vị của ma trận \(\mathbf{A}\) là \(\mathbf{A}^{\intercal}\)
1.3.Các thuộc tính của ma trận¶
Một ma trận được đặc trưng bởi dòng và cột.
import torch A = torch.tensor([[1, 2, 3], [3, 2, 1]]) # shape của matrix A A.size()
import numpy as np A = np.array([[1, 2, 3], [3, 2, 1]]) # shape của matrix A A.shape
1.3.Các phép tính trên ma trận¶
Hai ma trận có cùng kích thước chúng ta có thể thực hiện các phép cộng, trừ, tích hadamard (hoặc elementi-wise). Ma trận thu được cũng có cùng kích thước và các phần tử của nó được tính dựa trên các phần tử có cùng vị trí trên cả hai ma trận \(\mathbf{A}\) và \(\mathbf{B}\).
Tích hadamard hoặc element-wise
Trên pytorch chúng ta có thể tính tích hadamard của hai ma trận đơn giản như sau:
import torch A = torch.tensor([[1, 2, 3], [3, 2, 1]]) B = torch.tensor([[2, 1, 2], [1, 3, 0]]) A*B
import numpy as np A = np.array([[1, 2, 3], [3, 2, 1]]) B = np.array([[2, 1, 2], [1, 3, 0]]) A*B
Tương tự với các phép cộng và trừ
print(“A-B: \n”, A-B) print(“A+B: \n”, A+B)
print(“A-B: \n”, A-B) print(“A+B: \n”, A+B)
Tích thông thường: Tích thông thường giữa hai ma trận \(\mathbf{A}\) có kích thước \(m \times n\) và \(\mathbf{B}\) có kích thước \(n \times p\) là một ma trận có kích thước \(m \times p\). Ma trận output \(\mathbf{C}\) có giá trị tại phần tử \(c_{ij} = \mathbf{A}^{(i)} \mathbf{B}_{j}\) (dòng thứ \(i\) của ma trận \(\mathbf{A}\) nhân với cột thứ \(j\) của ma trận \(\mathbf{B}\)).
Chắc các bạn còn nhớ \(\mathbf{A}^{(i)}\) là véc tơ dòng và \(\mathbf{A}_{j}\) là véc tơ cột.
import torch A = torch.tensor([[1, 2, 3], [3, 2, 1]]) B = torch.tensor([[2, 1], [1, 3], [1, 1]]) A@B
import numpy as np A = np.array([[1, 2, 3], [3, 2, 1]]) B = np.array([[2, 1], [1, 3], [1, 1]]) A@B
1.3.Ma trận nghịch đảo¶
Cho ma trận vuông \(\mathbf{A} \in \mathbb{R}^{n \times n}\), nếu tồn tại một ma trận vuông \(\mathbf{B} \in \mathbb{R}^{n \times n}\) sao cho \(\mathbf{A} \mathbf{B} = \mathbf{I}_{n}\) thì ta nói rằng ma trận \(\mathbf{A}\) khả nghịch (invertible) hoăc không suy biến (nonsingular). Ma trận \(\mathbf{B}\) được gọi là ma trận nghịch đảo (inverse matrix) của ma trận \(\mathbf{A}\). Ta dễ dàng nhận thấy rằng nếu \(\mathbf{A} \mathbf{B} = \mathbf{I}_n\) thì
Như vậy để ma trận \(\mathbf{A}\) khả nghịch thì \(\det(\mathbf{A}) \neq 0\). Trong trường hợp không tồn tại ma trận \(\mathbf{B}\) thoả mãn điều kiện \(\mathbf{A} \mathbf{B} = \mathbf{I}\) thì ta nói rằng ma trận \(\mathbf{A}\) không khả nghịch hoặc bị suy biến (singular).
Ma trận nghịch đảo của ma trận khả nghịch \(\mathbf{A}\) được kí hiệu là \(\mathbf{A}^{-1}\) là một ma trận vuông thoả mãn:
Ta dễ nhận thấy rằng \(\mathbf{A}^{-1} = \mathbf{B}\). Ma trận nghịch đảo thường được sử dụng để giải hệ phương trình tuyến tính. Giả sử một hệ phương trình tuyến tính:
Trong đó ma trận hệ số \(\mathbf{A} \in \mathbb{R}^{n \times n}\) có các dòng tương ứng với các hệ số của một phương trình. Véc tơ \(\mathbf{x} \in \mathbb{R}^{n}\) là biến cần tìm. Véc tơ \(\mathbf{b}\) đại diện cho hệ số tự do.
Khi đó để tìm nghiệm \(\mathbf{x}\) chúng ta tính theo ma trận nghịch đảo \(\mathbf{A}^{-1}\):
Một số tính chất liên quan tới ma trận nghịch đảo.
-
Nếu ma trận \(\mathbf{A}\) là một ma trận vuông nhưng không khả nghịch thì phương trình \((1)\) có vô số nghiệm. Trong trường hợp ma trận \(\mathbf{A}\) không vuông và là một ma trận thấp chiều (có số dòng lớn hơn số cột) thì phương trình có thể vô nghiệm.
-
Nếu ma trận \(\mathbf{A}\) khả nghịch thì ma trận nghịch đảo của nó là \(\mathbf{B}\) cũng khả nghịch. Đồng thời ta có tính chất:
Chứng minh:
Ta có:
Nhân \(\mathbf{A}^{-1}\) vào bên trái mỗi vế của phương trình \((2)\) ta được:
-
Nếu ma trận \(\mathbf{A}, \mathbf{B}\) đều khả nghịch thì tích của chúng cũng khả nghịch:
chứng minh:
Nhân mỗi vế của phương trình trên với \(\mathbf{A}\mathbf{B}\) vào bên phải ta có:
Đối với vế bên trái:
Đối với vế bên phải:
Từ đó suy ra \((\mathbf{A}\mathbf{B})^{-1} = \mathbf{B}^{-1}\mathbf{A}^{-1}\)
Trên numpy để tính ma trận nghịch đảo chúng ta sử dụng hàm
np.linalg.pinv
hoặc
np.linalg.inv
. Hàm
np.linalg.pinv
sẽ bao gồm cả trường hợp \(\mathbf{A}\) không khả nghịch, giá trị trả về là một ma trận giả nghịch đảo (pseudo-inverse matrix).
import torch A = torch.tensor([[1, 2, 3], [3, 2, 1], [4, 2, 2]], dtype=torch.float32) A_inv = torch.linalg.pinv(A) print(A_inv)
import numpy as np A = np.array([[1, 2, 3], [3, 2, 1], [4, 2, 2]]) A_inv = np.linalg.pinv(A) print(A_inv)
1.3.Truy cập thành phần¶
Chúng ta có thể truy cập vào các thành phần của ma trận \(\mathbf{A}\) dựa theo các chỉ số slice index. Chúng ta có thể tổng hợp kiến thức về truy cập thành phần trong bản sau:
Cú pháp |
Mô tả |
:n |
lấy n index đầu tiên từ [0, 1, …, n-1] |
-n: |
lấy n index cuối cùng từ [len-n, …, len-1] |
i:j |
lấy các index từ [i, i+1, …, j-1] |
::2 |
lấy các index chẵn liên tiếp [0, 2, 4 …, int(len/2)*2] |
::k |
lấy các index cách đều và chia hết cho k một cách liên tiếp [0, k, 2k, …, int(len/k)*k] |
lấy toàn bộ index |
import torch A = torch.tensor([[1, 2, 3], [3, 2, 1], [4, 2, 2]]) # Truy cập ma trận con từ 2 dòng đầu tiên và 2 cột đầu tiên. A[:2, :2]
import numpy as np A = np.array([[1, 2, 3], [3, 2, 1], [4, 2, 2]]) # Truy cập ma trận con từ 2 dòng đầu tiên và 2 cột đầu tiên. A[:2, :2]
Truy cập ma trận con từ 2 dòng cuối cùng và 2 cột đầu tiên
# Truy cập ma trận con từ 2 dòng cuối cùng và 2 cột đầu tiên A[-2:, :2]
# Truy cập ma trận con từ 2 dòng cuối cùng và 2 cột đầu tiên A[-2:, :2]
Truy cập véc tơ con từ dòng thứ 2 và 2 cột cuối cùng.
# Truy cập véc tơ con từ dòng thứ 2 và 2 cột cuối cùng. print(A[2, -2:]) # Hoặc A[2:3, -2:][0]
# Truy cập véc tơ con từ dòng thứ 2 và 2 cột cuối cùng. print(A[2, -2:]) # Hoặc A[2:3, -2:][0]
Truy cập ma trận có các dòng chẵn
# Truy cập ma trận có các dòng chẵn A[::2, :]
# Truy cập ma trận có các dòng chẵn A[::2, :]
Truy cập một index cụ thể, ví dụ dòng 0, 2 của ma trận
# Truy cập một index cụ thể , ví dụ dòng 0, 2 của ma trận A.index_select(0, torch.tensor([0, 2])) # Trong công thức trên 0 là chiều mà ta sẽ lấy, tensor([0, 2]) là các index ta sẽ lấy từ chiều 0.
# Truy cập một index cụ thể , ví dụ dòng 0, 2 của ma trận A[[0, 2], :]
Ví dụ về ma trận trong Python
Ví dụ đơn giản về ma trận trong Python
Ta sẽ xem xét trường hợp ghi nhiệt độ trong một tuần được đo vào buổi sáng, giữa ngày, buổi tối và giữa đêm. Trường hợp này có thể được trình bày dưới dạng ma trận 7×5 bằng cách sử dụng mảng và phương pháp định hình có sẵn trong Numpy như sau:
from numpy import *
a = array([[‘Mon’,18,20,22,17],[‘Tue’,11,18,21,18],
[‘Wed’,15,21,20,19],[‘Thu’,11,20,22,21],
[‘Fri’,18,17,23,22],[‘Sat’,12,22,20,18],
[‘Sun’,13,15,19,16]])
m = reshape(a,(7,5))
print(m)
Dữ liệu trên có thể được biểu diễn dưới dạng một mảng hai chiều như bên dưới.
[[‘Mon’ ’18’ ’20’ ’22’ ’17’]
[‘Tue’ ’11’ ’18’ ’21’ ’18’]
[‘Wed’ ’15’ ’21’ ’20’ ’19’]
[‘Thu’ ’11’ ’20’ ’22’ ’21’]
[‘Fri’ ’18’ ’17’ ’23’ ’22’]
[‘Sat’ ’12’ ’22’ ’20’ ’18’]
[‘Sun’ ’13’ ’15’ ’19’ ’16’]]
Khi đoạn mã trên được thực thi, nó sẽ cho ra kết quả như sau:
[‘Wed’, 15, 21, 20, 19]
23
>>> Xem thêm: Từ điển trong Python – Cách sử dụng từ điển trong Python
1.Tổ hợp tuyến tính và không gian sinh¶
Thế nào là một tổ hợp tuyến tính?
Giả sử \(\mathbf{a}_1, \mathbf{a}_2, \dots, \mathbf{a}_n\) là các véc tơ thuộc không gian \(\mathbb{R}^m\) và \(k_1, k_2, \dots, k_n\) là những số vô hướng. Khi đó tổ hợp tuyến tính (linear combination) của \(n\) véc tơ \(\mathbf{a}_1, \mathbf{a}_2, \dots, \mathbf{a}_n\) tương ứng với các hệ số \(k_i\) là một véc tơ được tính theo phương trình tuyến tính dạng:
Nếu xét ma trận \(\mathbf{A} = [\mathbf{a}_1, \mathbf{a}_2 \dots ,\mathbf{a}_n] \in \mathbb{R}^{m \times n}\) có các cột là những véc tơ \(\mathbf{a}_i \in \mathbb{R}^{m}\). Khi đó tổ hợp tuyến tính có thể biểu diễn dưới dạng một phép nhân ma trận với véc tơ:
Lưu ý rằng biểu diễn tổ hợp tuyến tính đối với véc tơ \(\mathbf{b}\) có thể là không duy nhất. Tập hợp tất cả các véc tơ \(\mathbf{b}\) trong phương trình \((1)\) ở trên được gọi là không gian sinh (span space) của hệ véc tơ \(\{\mathbf{a}_1, \mathbf{a}_2, \dots, \mathbf{a}_n\}\), kí hiệu \(\text{span}(\mathbf{a}_1, \dots, \mathbf{a}_n)\)
Hệ véc tơ độc lập tuyến tính là gì?
Một hệ véc tơ \(\{\mathbf{a}_1, \mathbf{a}_2, \dots, \mathbf{a}_n\}\) gồm các véc tơ khác 0 là độc lập tuyến tính nếu phương trình:
có một nghiệm duy nhất là \(k_1 = k_2 = \dots = k_n = 0\)
Trái lại, nếu tồn tại một nghiệm mà phần tử \(k_j \neq 0\) thì hệ véc tơ là phụ thuộc tuyến tính.
Một số tính chất của tổ hợp tuyến tính
1-. Một hệ véc tơ là phụ thuộc tuyến tính khi và chỉ khi tồn tại một véc tơ trong hệ là tổ hợp tuyến tính của những véc tơ còn lại. Thật vậy, giả sử hệ véc tơ là phụ thuộc tuyến tính, khi đó tồn tại một phần tử \(k_j \neq 0\) sao cho phương trình \((2)\) được thoả mãn. Khi đó:
Như vậy \(\mathbf{a}_{j}\) là tổ hợp tuyến tính của những véc tơ còn lại. Trong trường hợp phương trình \((3)\) được thoả mãn thì ta cũng suy ra được phương trình \((2)\) có nghiệm \(k_j \neq 0\) và hệ véc tơ là phụ thuộc tuyến tính.
2-. Tập con khác rỗng của một hệ véc tơ độc lập tuyến tính là một hệ độc lập tuyến tính.
3-. Tập hợp các dòng hoặc cột của một ma trận khả nghịch sẽ tạo thành một hệ các véc tơ độc lập tuyến tính.
4-. Nếu \(\mathbf{A}\) là một ma trận cao chiều, tức số hàng lớn hơn số cột thì tồn tại véc tơ \(\mathbf{b}\) sao cho \(\mathbf{A}\mathbf{x} = \mathbf{b}\) vô nghiệm.
5-. Nếu \(n > m\) thì \(n\) véc tơ bất kì trong không gian \(m\) chiều tạo thành một hệ véc tơ phụ thuộc tuyến tính.
Hàm sum và max/min với ma trận
Chúng ta có thể sử dụng hàm sum để lấy tổng các phần tử, max để lấy phần tử lớn nhất, min để lấy phần tử nhỏ nhất.
Cấu trúc:
np.sum(matrix,axis)
np.max(matrix,axis)
np.min(matrix,axis)
Trong đó
- matrix: ma trận cần tìm kích thước
- axis: chiều, nếu là 0 sẽ tính theo cột, 1 sẽ tính theo hàng, mặc định sẽ tính trên cả ma trận.
Ví dụ:
import numpy as np _a = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] a = np.array(_a) print(np.sum(a, 0)) print(np.max(a)) print(np.min(a, 1))
2.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}\).
Bạn đọc cần viết hàm dưới dạng vectorization, tức không sử dụng vòng
for
.
Gợi ý: Lời giải có thể không vượt quá 2 dòng lệnh.
2.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
.T
hoặc dùng hàm
np.transpose
:
>>> import numpy as np >>> A = np.array([[1, 2, 3],[4, 5, 6]]) >>> A array([[1, 2, 3], [4, 5, 6]]) >>> A.T array([[1, 4], [2, 5], [3, 6]]) >>> np.transpose(A) array([[1, 4], [2, 5], [3, 6]])
2.9.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
.reshape
hoặc hàm
np.reshape
. Cùng xem ví dụ:
>>> np.reshape(A, (3, 2)) array([[1, 2], [3, 4], [5, 6]]) >>> A.reshape(3, 2) array([[1, 2], [3, 4], [5, 6]])
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ư
(3,2)
) nữa mà chỉ dùng một số tự nhiên:
>>> np.reshape(A, 6) # to a 1d numpy array array([1, 2, 3, 4, 5, 6]) >>> A.reshape(3, 1, 2) # to a 3d numpy array array([[[1, 2]], [[3, 4]], [[5, 6]]])
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
-1
:
>>> A.reshape(-1) # to 1d array, its size must be 6 array([1, 2, 3, 4, 5, 6]) >>> np.reshape(A, (6, -1)) # ~ a 2d array of shape 6x1 array([[1], [2], [3], [4], [5], [6]])
2.9.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à
'C'-order
, và một cách khác là
'F'-order
(xem hình).
Trong
'C'-order
, các thành phần của mảng nguồn được quét từ
axis
trong ra ngoài (
axis = 1
rồi mới tới
axis = 0
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
'F'-oder
(Fortran) các thành phần của mảng nguồn được quét từ
axis
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.
>>> A array([[1, 2, 3], [4, 5, 6]]) >>> A.reshape(3, -1, order = 'F') array([[1, 5], [4, 3], [2, 6]]) >>>
(Đọc thêm
numpy.reshape
.)
Bài tập:
Hãy tạo ma trận 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
np.arange()
- Để ý 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
transpose, reshape
thích hợp.
1.Hạng của ma trận¶
Xét một ma trận \(\mathbf{A} ∈ \mathbb{R}^{m×n}\) . Hạng (rank) của ma trận của ma trận được ký hiệu là \(\text{rank}(\mathbf{A})\), được định nghĩa là số lượng lớn nhất các cột hoặc dòng của nó tạo thành một hệ độc lập tuyến tính.
Các tính chất quan trọng của hạng:
-
Một ma trận có hạng bằng 0 khi và chỉ khi nó là ma trận 0.
-
\(\text{rank}(\mathbf{A}) = \text{rank}(\mathbf{A}^{\intercal})\). Hạng của một ma trận bằng hạng của ma trận chuyển vị. Nói cách khác, số lượng lớn nhất các cột độc lập tuyến tính của một ma trận bằng với số lượng lớn nhất các hàng độc lập tuyến tính của ma trận đó. Từ đây ta suy ra:
-
Nếu \(\mathbf{A} \in \mathbb{R}^{m×n}\) , thì \(\text{rank}(\mathbf{A}) \leq \min(m, n)\) vì theo định nghĩa, hạng của một ma trận không thể lớn hơn số hàng hoặc số cột của nó.
-
\(\text{rank}(\mathbf{AB}) \leq \min(\text{rank}(\mathbf{A}), \text{rank}(\mathbf{B}))\)
-
\(\text{rank}(\mathbf{A} + \mathbf{B}) ≤ \text{rank}(\mathbf{A}) + \text{rank}(\mathbf{B})\). Điều này chỉ ra rằng một ma trận có hạng bằng \(k\) không được biểu diễn dưới dạng ít hơn k ma trận có hạng bằng 1. Đến bài Singular Value Decomposition, chúng ta sẽ thấy rằng một ma trận có hạng bằng \(k\) có thể biểu diễn được dưới dạng đúng k ma trận có hạng bằng 1.
-
Bất đẳng thức Sylvester về hạng: Nếu \(\mathbf{A} \in \mathbb{R}^{m×n} , \mathbf{B} \in \mathbb{R}^{n×k}\) , thì \(\text{rank}(\mathbf{A}) + \text{rank}(\mathbf{B}) − n ≤ \text{rank}(\mathbf{AB})\)
Tóm tắt¶
Như vậy qua chương này mình đã hướng dẫn cho các bạn các kiến thức bản nhất trong đại số tuyến tính. Bao gồm:
-
Các khái niệm: Số vô hướng, véc tơ, ma trận, tensor kèm theo thuộc tính của chúng.
-
Các phép tính cộng, trừ, nhân ma trận, nhân véc tơ, nhân ma trận với véc tơ.
-
Khái niệm về chuẩn và ý nghĩa của chúng trong vai trò một độ đo đối với véc tơ.
Đây là những kiến thức nền tảng nhưng rất quan trọng mà bạn đọc cần nắm vững trước khi học sâu về AI.
Bài tập¶
Một vài bài tập dưới đây sẽ giúp bạn ôn lại kiến thức tốt hơn:
-
Khởi tạo một số vô hướng, một véc tơ có độ dài là \(3\) và một ma trận bất kỳ có kích thước là \(2\times 3\) trên pytorch.
-
Tính tích giữa ma trận và véc tơ ở câu 1.
-
Tính tổng các dòng và tổng các cột của ma trận ở câu 1.
-
Chứng minh rằng nếu \(\mathbf{A}\) là một ma trận vuông thì \(\mathbf{A} + \mathbf{A}^{\top}\) là một ma trận đối xứng.
-
Cho \(\mathbf{A}, \mathbf{B}, \mathbf{C}\) là ba ma trận có kích thước lần lượt là \(m \times n\), \(n \times p\) và \(p \times q\) chứng minh rằng \(\mathbf{ABC} = (\mathbf{A}\mathbf{B})\mathbf{C} = \mathbf{A}(\mathbf{B}\mathbf{C})\)
-
\(\mathbf{trace}\) của ma trận là tổng các phần tử nằm trên đường chéo chính ( phần tử mà có index dòng bằng cột). Chứng minh rằng: \(\mathbf{trace(AB) = trace(BA)}\)
-
Chứng minh: \(\mathbf{A} \odot \mathbf{(B+C)} = \mathbf{A} \odot \mathbf{B} + \mathbf{A} \odot \mathbf{C}\)
-
Chứng minh: \(\mathbf{A} \odot (\mathbf{B} \odot \mathbf{C})= (\mathbf{A} \odot \mathbf{B}) \odot \mathbf{C}\)
-
Chứng mình rằng: \((\mathbf{A}\mathbf{B})^{\intercal} = \mathbf{B}^{\intercal}\mathbf{A}^{\intercal}\)
-
Chứng minh: \(\mathbf{A}\mathbf{I} = \mathbf{A}\). Trong đó \(\mathbf{I}\) là ma trận đơn vị.
Để bắt đầu thì chúng ta cần cài đặt thư viện Numpy bằng cách mở CMD và gõ lệnh sau:
pip install numpy
Thư viện Numpy là gì?
Trước khi bắt đầu thì mình sẽ giới thiệu sơ lược về cái thư viện Numpy mà chúng ta sẽ sử dụng để xử lý ma trận.
Numpy (Numeric Python) là 1 thư viện toán học phổ biến và mạnh mẽ của Python. Thư viện này sẽ cho phép chúng ta làm việc hiệu quả đối với mảng và ma trận. Numpy cực kỳ hữu ích khi thực hiện các hàm liên quan tới Đại số tuyến tính
Khởi tạo 1 ma trận
np.array(object, dtype=None, ndmin=0)
- object: một mảng 2 chiều, ta có thể sử dụng một list của list.
- dtype: kiểu dữ liệu của các phần tử trong ma trận
- ndmin: số chiều tối thiểu khi return object
Trong bài viết này, chúng ta chưa cần quan tâm đến dtype và ndmin
Ví dụ về khởi tạo 1 ma trận:
import numpy as np a = [ [4, 5, 2, 3], [5, 7, 2, 8], [9, 7, 4, 8], [8, 9, 5, 2] ] matrix_a = np.array(a) print(‘Ma tran a la: \n’, matrix_a)
Kết quả sau khi chạy là:
Cộng trừ 2 ma trận
Lưu ý: Để có thể cộng hoặc trừ 2 ma trận thì 2 ma trận phải cùng kích kích thước ( cùng cấp )
import numpy as np a = [ [4, 5, 2, 3], [5, 7, 2, 8], [9, 7, 4, 8], [8, 9, 5, 2] ] b = [ [5, 6, 3, 2], [6, 7, 3, 2], [0, 8, 1, 9], [8, 5, 5, 3] ] matrix_a = np.array(a) matrix_b = np.array(b) print(‘Tong cua 2 ma tran: \n’, matrix_a + matrix_b) print(‘\nHieu cua 2 ma tran: \n’, matrix_a + matrix_b)
Sau khi chạy sẽ có kết quả như sau:
Nhân ma trận với 1 số
import numpy as np a = [ [4, 5, 2, 3], [5, 7, 2, 8], [9, 7, 4, 8], [8, 9, 5, 2] ] matrix_a = np.array(a) print(‘\nMa tran a nhan voi 2 la: \n’, matrix_a * 2)
Sau khi chạy sẽ có kết quả như sau:
Nhân ma trận với ma trận
import numpy as np a = [ [4, 5, 2, 3], [5, 7, 2, 8], [9, 7, 4, 8], [8, 9, 5, 2] ] b = [ [5, 6, 3, 2], [6, 7, 3, 2], [0, 8, 1, 9], [8, 5, 5, 3] ] matrix_a = np.array(a) matrix_b = np.array(b) matrix_c = matrix_a.dot(matrix_b) print(‘\nTich cua 2 ma tran la: \n’, matrix_c)
Sau khi chạy sẽ có kết quả như sau:
Trong bài viết tiếp theo mình sẽ tiếp tục trình bày về ma trận đơn vị, ma trận nghịch đảo, ma trận chuyển vị, tính định thức, hạng của ma trận,…
Cảm ơn các bạn đã theo dõi bài viết này!
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
- 2.1. Khởi tạo một ma trận
- 2.2. Ma trận đơn vị và ma trận đường chéo
- 2.3. Kích thước của ma trận
- 2.4. Truy cập vào từng phần tử của ma trận
- 2.5. Truy cập vào nhiều phần tử của ma trận
- 2.6. np.sum, np.min, np.max, np.mean cho mảng nhiều chiều
- 2.7. Các phép toán tác động đến mọi phần tử của ma trận
- 2.8. Các phép toán giữa hai ma trận I
- 2.9. Chuyện vị ma trận, Reshape ma trận
- 2.10. Các phép toán giữa ma trận và vector
- 2.11. Tích giữa hai ma trận, tích giữa ma trận và vector
- 2.12. Softmax III – Phiên bản tổng quát
1.Véc tơ¶
Véc tơ là một khái niệm cơ bản nhất của toán học. Chúng ta có thể coi véc tơ là một tập hợp nhiều giá trị của số vô hướng. Véc tơ thường biểu diễn một đại lượng cụ thể trên thực tiễn. Ví dụ như diện tích của các căn nhà là một véc tơ, số lượng phòng ngủ cũng là một véc tơ. Véc tơ có độ dài đặc trưng chính bằng số lượng các phần tử trong nó. Để khởi tạo một véc tơ, trong pytorch chúng ta bao các giá trị của nó trong dấu ngoặc vuông.
x = torch.tensor([1, 1.2, 1.5, 1.8, 2]) x
x = np.array([1, 1.2, 1.5, 1.8, 2]) x
1.2.Các thuộc tính của véc tơ¶
Một véc tơ sẽ có độ dài và định dạng dữ liệu xác định. Ngoài ra nếu coi một biến số là một véc tơ thì trong thống kê mô tả chúng ta sẽ quan tâm tới tổng, trung bình, phương sai, giá trị lớn nhất, nhỏ nhất.
# Độ dài print(“length of vector: “, x.size()) # or len(x) # Định dạng của véc tơ print(“vector type: “, x.dtype) # Tổng của các phần tử print(“sum of vector: “, x.sum()) # Trung bình các phần tử print(“mean of vector: “, x.mean()) # Giá trị nhỏ nhất print(“min of vector: “, x.min()) # Giá trị lớn nhất print(“max of vector: “, x.max())
# Độ dài print(“length of vector: “, x.shape) # or len(x) # Định dạng của véc tơ print(“vector type: “, x.dtype) # Tổng của các phần tử print(“sum of vector: “, x.sum()) # Trung bình các phần tử print(“mean of vector: “, x.mean()) # Giá trị nhỏ nhất print(“min of vector: “, x.min()) # Giá trị lớn nhất print(“max of vector: “, x.max())
1.2.Các phép tính trên véc tơ¶
Chúng ta có thể thực hiện các phép tính trên véc tơ như phép cộng, trừ, tích vô hướng, tích có hướng giữa hai véc tơ… Lưu ý là chúng phải có cùng độ dài. Trong khuôn khổ cuốn sách này, các véc tơ sẽ được ký hiệu là một ký tự chữ thường in đậm như \(\mathbf{x}, \mathbf{y}, \mathbf{z}\). Ngoài ra \(\mathbf{x}\in \mathbb{R}^{n}\) là véc tơ số thực có độ dài \(n\).
x = torch.tensor([1, 2, 1.5, 1.8, 1.9]) y = torch.tensor([1.1, 2.2, 1.2, 1.6, 1.7]) print(“x + y: “, x + y) print(“x – y: “, x – y) print(“x * y: “, x * y)
import numpy as np x = np.array([1, 2, 1.5, 1.8, 1.9]) y = np.array([1.1, 2.2, 1.2, 1.6, 1.7]) print(“x + y: “, x + y) print(“x – y: “, x – y) print(“x * y: “, x * y)
Véc tơ có thể thực hiện các phép cộng, trừ, nhân, chia với một số vô hướng. Giá trị thu được là một véc tơ cùng kích thước mà mỗi phần tử của nó là kết quả được thực hiện trên từng phần tử của véc tơ với số vô hướng đó.
x = torch.tensor([1, 2, 1.5, 1.8, 1.9]) print(“x + 5: “, x + 5) print(“x – 5: “, x – 5) print(“x * 5: “, x * 5)
x = np.array([1, 2, 1.5, 1.8, 1.9]) print(“x + 5: “, x + 5) print(“x – 5: “, x – 5) print(“x * 5: “, x * 5)
Gợi ý
- Định nghĩa hàm nhap_danh_sach và in_danh_sach (Tham khảo Bài 90)
- Định nghĩa hàm danh_sach_chuyen_vi với tham số là một danh sách hai chiều:
- Khởi tạo danh sách rỗng để lưu trữ ma trận chuyển vị
- Tính lại số dòng và số cột của danh sách chuyển vị
-
Sử dụng vòng lặp for và biến chạy i để duyệt qua tất cả các cột của danh sách.
- Sử dụng List Comprehension lấy phần tử ở cột i của tất cả các hàng
- Thêm danh sách cột thứ i vào danh sách chuyển vị
- Trả danh sách chuyển vị về cho hàm
- Sử dụng cấu trúc Xử lý ngoại lệ để xử lý các trường hợp gây ra lỗi khi ép kiểu dữ liệu
- Đặt chương trình trong khối try.
- Dùng hàm input(), split(), map() và int() để nhập kích thước M, N của danh sách hai chiều và ép kiểu dữ liệu sang số nguyên.
- Sử dụng cấu trúc rẽ nhánh để kiểm tra xem M, N có là số nguyên dương hay không. Xuất thông báo lỗi nếu có.
- Gọi hàm nhap_danh_sach, danh_sach_chuyen_vi, in_danh_sach và truyền vào các tham số cần thiết.
- Lỗi sẽ phát sinh ở lệnh ép kiểu nếu định dạng đầu vào không hợp lệ. Dùng lệnh except để bắt lỗi:
- Dùng hàm print() hiển thị thông báo lỗi ra màn hình.
Dẫn nhập
Trong bài trước, Kteam đã GIỚI THIỆU MACHINE LEARNING VÀ CÀI ĐẶT NUMPY , giúp các bạn một phần hiểu được bản chất của Machine Learning.
Ở bài này chúng ta sẽ cùng nhau tìm hiểu về Ma trận và vector với NumPy. Với bài này, Kteam sẽ giới thiệu đến các bạn một nội dung khá “toán học”, vì thế nếu cảm thấy mệt mỏi, hoa mắt, chóng mặt, trời đất quay cuồng thì hãy nghĩ ngơi một lúc 😊
Lưu ý: Một số nội dung được trình bày trong video vẫn có thể chưa hoàn toàn chính xác. Vì vậy, sau khi tham khảo góp ý từ cộng đồng , Kteam đã có hiệu chỉnh học liệu và cách diễn đạt các định nghĩa trong bài viết để nội dung có thể đi sát hơn với các tài liệu toán học.
Keywords searched by users: ma trận chuyển vị python
Categories: Tìm thấy 92 Ma Trận Chuyển Vị Python
See more here: kientrucannam.vn
See more: https://kientrucannam.vn/vn/