Tải bản đầy đủ (.pdf) (70 trang)

BÀI TIỂU LUẬN MÔN PHƯƠNG PHÁP TÍNH ĐỀ TÀI PHÂN TÍCH THÀNH PHẦN CHÍNH VÀ ỨNG DỤNG

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.97 MB, 70 trang )

BỘ GIÁO DỤC VÀ ĐÀO TẠO
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ VÀ THIẾT KẾ UEH
KHOA TOÁN – THỐNG KÊ
----------

BÀI TIỂU LUẬN MƠN PHƯƠNG PHÁP TÍNH
ĐỀ TÀI: PHÂN TÍCH THÀNH PHẦN CHÍNH VÀ ỨNG DỤNG
Giảng viên hướng dẫn:PGS.TS Lê Xuân Trường
Lớp:FM001

Khóa:K45

Các thành viên trong nhóm:18
Lương Đình Trường - 31191024170
Phan Tấn Phong

- 31191023775

Tơ Thành Hiệp

- 31191026445


2

Mục lục
I. Giới thiệu (mục tiêu và các ứng dụng của phương pháp phân tích thành
phần chính):
1.Định nghĩa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6



2 Mục tiêu. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6

3 Ưu điểm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6

4. Các ứng dụng của PCA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

7

II. Nội dung thành phần chính:
1. Phân tích suy biến - Singular Value Decomposition (SVD)
1.1 Giới thiệu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

7

1.2 Mục tiêu của phân tích suy biến. . . . . . . . . . . . . . . . . . . . . . . . .

7

1.3 Kiến thức chung về đại số tuyến tính. . . . . . . . . . . . . . . . . . . . . .

8

1.4 Phát biểu SVD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13


1.5 Các phép giảm chiều SVD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.6 Phương pháp làm mỏng SVD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.7. Phương pháp Compact SVD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.8. Phương pháp Truncated SVD . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.9. Ứng dụng của phân tích suy biến SVD. . . . . . . . . . . . . . . . . . . . . 20
1.9.1 Giải phương trình tuyến tính . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.9.2 Giảm chiều dữ liệu hình ảnh. . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2 . Phương pháp phân tích thành phần chính – Principal Component Annalysis
(PCA)


3

2.1 Khái niệm . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.2 Đặc tính của PCA. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.3 Mục tiêu của PCA. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.4 Thuật toán PCA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.4.1 Tiền xử lí . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.4.2 Xây dựng không gian mới. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.4.3 Chuyển dữ liệu từ không gian ban đầu vào không gian mới. . . . . . 30
2.5 Cơ sở toán học của PCA. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.6. Các bước để phân tích thành phần chính. . . . . . . . . . . . . . . . . . . . . . 33
2.6.1 Toán nền (Background Mathematics) . . . . . . . . . . . . . . . . . . . . . . 33
2.6.1.1 Thống kê(Statistics). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.6.1.2 Độ lệch chuẩn(Standard Deviation) . . . . . . . . . . . . . . . . . . . . . . 33
2.6.1.3 Phương sai (variance). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.6.1.4 Hiệp phương sai (covariance). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.6.1.5 Các ma trận hiệp phương sai(The covariance matrix) . . . . . . . . . . . . . 38
2.6.1.6 Đại số ma trận(Matrix Algebra). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

2.6.1.7 Vector riêng(Eigenvectors) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.6.1.8 Giá trị riêng(Eigenvalues). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.7

Phương pháp(Method) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

2.7.1

Bước 1: Nhận được một số dữ liệu (Get some data) . . . . . . . . . . . .. 43

2.7.2

Bước 2: Trừ các trung bình (Subtract the mean) . . . . . . . . . . . . . . . .43

2.7.3

Bước 3: Tính toán ma trận hiệp phương sai(Calculate the covariance

matrix) 44
2.7.4

Bước 4: Tính vector riêng và giá trị riêng của ma trận hiệp phương sai

(Calculate the eigenvectors and eigenvalues of the covariance matrix) . . . . . . . .
. . . . . . . .44


4

2.7.5


Bước 5: Lựa chọn các thành phần và hình thành một vector đặc trưng

(Choosing components and forming a feature vector) ...................................45
2.7.6

Bước 6 : Phát sinh các tập dữ liệu mới ............................................47

2.7.7

Lấy dữ liệu cũ trở lại .....................................................................49

2.8

Các ứng dụng phân tích thành phần chính (Applications of principal

component analysis ) ....................................................................................52
2.8.1

Tổng quan về bản dữ liệu (Overview (plots) of any data table ) ......53

2.8.2

Giảm biến đa chiều (Dimensionality reduction) ............................53

2.8.3

Mơ hình tương đồng (Similarity models ) .....................................54

III. Phân tích thành phần chính (PCA) trong Python

3.1 Giới thiệu và ứng dụng của PCA ..............................................................55
3.1.1 Giới thiệu .........................................................................................55
3.1.2 Ứng dụng .........................................................................................55
3.1.3 Ý nghĩa ............................................................................................56
3.2 Phân tích thành phần chính (PCA) để trực quan hóa dữ liệu ........................56
3.2.1 Tải tệp dữ liệu Iris .............................................................................56
3.2.2 Chuẩn hóa dữ liệu .............................................................................57
3.2.3 Phép chiếu PCA sang 2D ...................................................................57
3.2.4 Trực quan hóa phép chiếu 2D .............................................................58
3.3 Phân tích thành phần chính (PCA) để tăng tốc thuật tốn Machine-Learning 60
3.3.1 Tải dữ liệu xuống ..............................................................................60
3.3.2 Tách dữ liệu thành các tập huấn luyện và kiểm tra................................61
3.3.3 Chuẩn hóa dữ liệu .............................................................................62


5

3.3.4 Các bước sử dụng PCA mà để tăng tốc thuật toán Machine Learning (hồi
quyLogistic) .............................................................................................62
3.3.5 Số thành phần, phương sai, bảng thời gian...........................................63

IV. Ứng dụng
4.1 Chúng ta sẽ bắt đầu bằng một ví dụ mang tính chất minh họa trực quan……64
4.2 Ví dụ miêu tả cách tính tốn PCA bằng Matlab……………………………. 66
4.3 Các ví dụ khác………………………………………………………………. 68


6

I. Giới thiệu (mục tiêu và các ứng dụng của phương pháp phân tích thành

phần chính).
1. Định nghĩa:
Phép phân tích thành phần chính (Principal Components Analysis - PCA) là một
thuật toán thống kê sử dụng phép biến đổi trực giao để biến đổi một tập hợp dữ liệu
từ một không gian nhiều chiều sang một khơng gian mới ít chiều hơn (2 hoặc 3
chiều) nhằm tối ưu hóa việc thể hiện sự biến thiên của dữ liệu.
Phân tích thành phần chính (PCA) cũng là một phương pháp giảm thứ
nguyên. Điều này không liên quan trực tiếp đến vấn đề dự đoán, nhưng một số
phương pháp hồi quy phụ thuộc trực tiếp vào nó. Các phương pháp hồi quy (PCR
và PLS) sẽ được xem xét sau. Giờ đây, một động lực để giảm thứ nguyên đang
được thiết lập. PCA cũng có thể phân cụm các điểm dữ liệu tương tự dựa trên sự
tương quan giữa chúng.
2. Mục tiêu của phương pháp này trên là chúng ta có thể:
- Giới thiệu Phân tích thành phần chính.
- Tiền thân của Kỹ thuật hồi quy sau giảm thứ nguyên.
- Nắm bắt sự thay đổi nội tại của dữ liệu.
- Giảm kích thước của một tập dữ liệu, để dễ giải thích hoặc là một cách để tránh
trang bị quá nhiều và để chuẩn bị cho phân tích tiếp theo.
3. Ưu điểm với tập dữ liệu:


Giảm số chiều của khơng gian chứa dữ liệu khi nó có số chiều lớn, khơng thể
thể hiện trong khơng gian 2 hay 3 chiều.



Xây dựng những trục tọa độ mới, thay vì giữ lại các trục của khơng gian cũ,
nhưng lại có khả năng biểu diễn dữ liệu tốt tương đương, và đảm bảo độ biến
thiên của dữ liệu trên mỗi chiều mới.




Tạo điều kiện để các liên kết tiềm ẩn của dữ liệu có thể được khám phá trong
không gian mới, mà nếu đặt trong không gian cũ thì khó phát hiện vì những liên
kết này khơng thể hiện rõ.


7



Đảm bảo các trục tọa độ trong khơng gian mới luôn trực giao đôi một với nhau,
mặc dù trong không gian ban đầu các trục có thể khơng trực giao.
4. Các ứng dụng chính của phương pháp phân tích thành phần chính (PCA):

+Tăng tốc độ thuật tốn Machine Learning (ML)
+ Trực quan hố dữ liệu

II. Nội dung thành phần chính
1 Singular Value Decomposition (SVD)
1.1 Giới thiệu chung
Phương pháp phân tích suy biến (singular value decomposition) được viết tắt là
SVD là một trong những phương pháp thuộc nhóm matrix factorization được phát
triển lần đầu bởi những nhà hình học vi phân. Ban đầu mục đích của phương pháp
này là tìm ra một phép xoay khơng gian sao cho tích vơ hướng của các vector không
thay đổi. Từ mối liên hệ này khái niệm về ma trận trực giao đã hình thành để tạo ra
các phép xoay đặc biệt. Phương pháp SVD đã được phát triển dựa trên những tính
chất của ma trận trực giao và ma trận đường chéo để tìm ra một ma trận xấp xỉ với
ma trận gốc. Phương pháp này sau đó đã được ứng dụng rộng rãi trong các lĩnh vực
như hình học vi phân, hồi qui tuyến tính, xử lý hình ảnh, clustering, các thuật tốn

nén và giảm chiều dữ liệu, và đặc biệt hiệu quả trong các bài tốn recommendation

1.2. Mục tiêu của phân tích suy biến.
Phương pháp SVD sẽ tìm ra một lớp các ma trận xấp xỉ tốt nhất với một ma trận
cho trước dựa trên khoảng cách norm Frobenios giữa 2 ma trận. Người ta đã chứng
minh được rằng ma trận xấp xỉ tốt nhất được biểu diễn dưới dạng tích của 3 ma trận
rất đặc biệt bao gồm 2 ma trận trực giao (orthogonal matrix) và 1 ma trận đường


8

chéo (diagonal matrix). Quá trình nhân ma trận thực chất là quá trình biến đổi các
điểm dữ liệu của ma trận gốc thông qua những phép xoay trục (rotation) và phép
thay đổi độ lớn (scaling) và từ đó tạo ra những điểm dữ liệu mới trong không gian
mới. Điều đặc biệt của ma trận đường chéo đó là các phần tử của nó chính là những
giá trị riêng của ma trận gốc. Những điểm dữ liệu trong không gian mới có thể giữ
được 100% thơng tin ban đầu hoặc chỉ giữ một phần lớn thông tin của dữ liệu ban
đầu thông qua các phép truncated SVD. Bằng cách sắp xếp các trị riêng theo thứ tự
giảm dần trên đường chéo chính thuật tốn SVD có thể thu được ma trận xấp xỉ tốt
nhất mà vẫn đảm bảo giảm được hạng của ma trận sau biến đổi và kích thước các
ma trận nhân tử nằm trong giới hạn cho phép. Do đó nó tiết kiệm được thời gian và
chi phí tính tốn và đồng thời cũng tìm ra được một giá trị dự báo cho ma trận gốc
với mức độ chính xác cao.
Trên đây là những thông tin chung nhất về thuật toán SVD. Chắc rằng chúng ta sẽ
rất mơ hồ khi mới lần đầu tiếp cận phương pháp này. Chính vì vậy kiến thức về đại
số tuyến tính sẽ được hệ thống trước khi đi vào thuật toán.
1.3. Kiến thức chung về đại số tuyến tính.
Hệ trực giao: Trong đại số tuyến tính, hệ trực giao là một lý thuyết quan trọng. Một
hệ vector cơ sở 𝑼 = [𝒖𝟏 , 𝒖𝟐 , … , 𝒖𝒏 ] ∈ ℝ𝑛 được gọi là một hệ trực giao (orthogonal)
nếu thỏa mãn hệ điều kiện:

||𝒖𝒊 ||𝟐𝟐 > 0, 𝒖𝑻𝒊 𝒖𝒋 = 0

∀1 ≤ 𝑖 ≠ 𝑗 ≤ 𝑛

Hệ trực chuẩn: Hệ trực chuẩn (orthonormal) là một trường hợp đặc biệt của hệ trực
giao khi điều kiện ||𝒖𝒊 ||𝟐𝟐 > 0 được thay thế thành ||𝒖𝒊 ||𝟐𝟐 = 1 .
Ma trận trực giao: Ma trận trực giao (orthogonal matrix) là ma trận vuông thỏa mãn
các dịng và cột của nó là một hệ trực chuẩn. Điều đó có nghĩa là một ma trận 𝑼 ∈
ℝ𝑛×𝑛 sẽ bao gồm các cột 𝒖𝑖 𝑖𝑛ℝ𝑛 có tính chất:
𝟐

||𝒖𝒊 ||𝟐 > 0, 𝒖𝑻𝒊 𝒖𝒋 = 0 ∀1<𝑖 ≠ 𝑗 ≤ 𝑛
Từ đó suy ra:


9

𝑼𝑻 𝑼 = 𝑰 𝒏
Ma trận trực giao có những tính chất đặc biệt sau:
1. Nếu U trực giao thì 𝑼𝑻 cũng trực giao.
2. Ma trận trực giao có chuyển vị bằng ma trận nghịch đảo. Từ đẳng thức 𝑼𝑻𝑼 =
𝑰𝒏 suy ra 𝑼𝑻 = 𝑼−𝟏.
3. Nếu ma trận 𝑼 ∈ ℝ𝑛 là ma trận trực giao thì ma trận 𝑼𝒓 ∈ ℝ𝑛×𝑟 được rút ra
từ 𝒓 cột đầu tiên của ma trận U có tính chất: 𝑼𝑻𝒓 𝑼𝒓 = 𝑰𝒓. Để chứng minh tính
chất này ta cần sử dụng đến khai triển tích của 2 ma trận dựa trên các ma trận
con (được trích ra từ các dịng và cột của ma trận gốc). Giả sử 𝑨, 𝑩 ∈ ℝ𝑛×𝑛 .
Ma trận 𝑴 ∈ ℝ𝑛 gồm r dịng đầu tiên của ma trận A và ma trận M là ma trận
phần bù của U được tạo thành từ các dòng còn lại. Tương tự, ma trận 𝑵 ∈
ℝ𝑛 gồm r cột đầu tiên của ma trận B và N là ma trận phần bù của V. Khi đó
tích AB được khai triển theo M,N và các ma trận phần bù như sau:

𝑴
[𝑨𝑩] = [ ][𝑵 𝑵] = [ 𝑴𝑵 N𝑵 ]
𝑴
𝑴𝑵 𝑴𝑵
Khi áp dụng tính chất trên cho ma trận UrUr ta suy ra tích 𝑼𝑻𝒓 𝑼𝒓 sẽ là ma
trận được tạo thành bởi r dòng và r cột đầu tiên của tích 𝑼𝑻𝑼. Do đó
𝑼𝑻𝒓 𝑼𝒓 = 𝑰𝒓.
4. Ma trận trực giao không làm thay đổi giá trị tích vơ hướng của 2 vector. Thật
vậy, nếu coi 𝒙, 𝒚 ∈ ℝ𝑛 là các vector được biến đổi bằng các nhân với ma trận
trực giao 𝑼 ∈ ℝ𝑛 . Khi đó tích vơ hướng của 2 vector mới như sau:
(𝑼𝒙)𝑻𝑼𝒚 = 𝒙𝑻𝑼𝑻𝑼𝒚 = 𝒙𝑻𝒚
Ma trận đường chéo: Một ma trận DD là ma trận đường chéo khi các phần tử của
nó thỏa mãn:
𝑑𝑖𝑖 ≠ 0, 𝑑𝑖𝑗 = 0 ∀𝑖 ≠ 𝑗


10

Hay nói cách khác 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. Ma trận đơn vị 𝑰𝒏 là một trường hợp đặc biệt của ma trận
đường chéo. Ma trận đường chéo có thể khơng vng. Ngồi ra ta có thể nhận thấy
mối liên hệ giữa hệ trực giao và ma trận đường chéo đó là một ma trận 𝑼 ∈
ℝ𝑛×𝑛 có các cột tạo thành một hệ trực giao thì tích của nó với ma trận chuyển vị sẽ
tạo thành một ma trận đường chéo.
Trace của ma trận: hàm trace của ma trận A kí hiệu là trace(A) là tổng của tất cả
các phần tử trên đường chéo của ma trận đó. Một số đẳng thức của trace:
1. 𝒕𝒓𝒂𝒄𝒆(𝑨) = 𝒕𝒓𝒂𝒄𝒆(𝑨𝑻). Điều này là hiển nhiên do phép chuyển vị khơng
làm thay đổi các vị trí trên đường chéo chính của A.
2. 𝒕𝒓𝒂𝒄𝒆(𝑨𝑩) = 𝒕𝒓𝒂𝒄𝒆(𝑩𝑨). Chứng minh tính chất này khá đơn giản. Giả
sử 𝑨𝒊 là vector dòng thứ i của A và 𝑩𝒋 là vector cột thứ j của B. Khi đó phần

tử 𝑨𝑩𝑰𝒋 ở dịng thứ i cột thứ j của ma trận tích AB là:
𝐴𝐵𝑖𝑗 = 𝑨(𝑖) 𝑩𝑗 = ∑(𝑎𝑖𝑘 𝑏𝑘𝑗 )
𝐾

Do đó:

𝒕𝒓𝒂𝒄𝒆(𝑨𝑩) = ∑ 𝐴𝐵𝑖𝑖 = ∑ ∑(𝑎𝑖𝑘 𝑏𝑘𝑖 )
𝑖

𝑖

(1)

𝑘

Hoàn toàn biến đổi tương tự:

𝒕𝒓𝒂𝒄𝒆(𝑩𝑨) = ∑ 𝐵𝐴𝑖𝑖 = ∑ ∑(𝑏𝑖𝑘 𝑎𝑘𝑖 )
𝑖

𝑖

(2)

𝑘

Ta nhận thấy chỉ số i,ki bình đẳng trong cả 2 biểu thức (1) và (2) nên nếu hoán
vị i và k cho nhau không làm thay đổi kết quả tổng. Mặt khác phép hoán vị



11

này sẽ biến biểu thức (1) thành (2) nên suy ra giá trị của 2 biểu thức là bằng
nhau.
3. 𝒕𝒓𝒂𝒄𝒆(𝑨𝑩𝑪) = 𝒕𝒓𝒂𝒄𝒆(𝑪𝑨𝑩) = 𝒕𝒓𝒂𝒄𝒆(𝑩𝑪𝑨). Tính chất này suy ra từ tính
chất 2.
4. 𝒕𝒓𝒂𝒄𝒆(𝑨 + 𝑩) = 𝒕𝒓𝒂𝒄𝒆(𝑨) + 𝒕𝒓𝒂𝒄𝒆(𝑩)Dễ dàng suy ra tính chất này do A
phải cùng kích thước và vị trí các phần tử trên đường chéo chính của 2 ma
trận này là trùng nhau.
Trị riêng của ma trận: Chúng ta chắc hẳn đã làm quen rất nhiều với trị riêng
(eigen-value) của một ma trận vng. Đó là một đại lượng vơ hướng (scaler) có
tính chất đặc biệt sau: ma trận 𝑨 ∈ ℝ𝑛 có trị riêng là λλ khi tồn tại một vector
𝑨 ∈ ℝ𝑛×𝑛 thỏa mãn:
𝑨𝒙 = 𝜆𝒙
Khai triển biểu thức trên để đưa về dạng tích của xx:
𝑨𝒙 − 𝜆𝒙
=0
𝑨𝒙 − 𝜆𝑰𝑛 𝒙 = 0
(𝑨 − 𝜆𝑰𝑛 )𝒙 = 0 (3)
Dòng thứ 2 đạt được là nhờ tích của một ma trận với ma trận đơn vị thì bằng chính
nó (𝑰𝒏 là kí hiệu cho ma trận đơn vị bậc n). Chúng ta gọi x là vector riêng (eigen
vector) ứng với trị riêng λ.
Trị riêng và vector riêng của ma trận có những tính chất đặc biệt sau:
1. Nếu x là vector riêng tương ứng của trị riêng λ thì kx cũng là một vector
riêng của λ. Tính chất này cho thấy một trị riêng có thể có nhiều vector riêng.
Tuy nhiên với một vector riêng chỉ có duy nhất một trị riêng.
2. Một ma trận có n trị riêng bao gồm cả lặp lại và trị riêng phức. Điều này có
được là vì trị riêng là nghiệm của một đa thức bậc n. Thật vậy, biểu thức (3)
về bản chất là tổ hợp tuyến tính của các cột ma trận 𝑨 − 𝜆𝑰𝑛 với các phần tử
của vector x. Do kết quả bằng 0 nên các cột của ma trận 𝑨 − 𝜆𝑰𝑛 là phụ

thuộc tuyến tính. Từ đó suy ra 𝒅𝒆𝒕(𝑨 − 𝜆𝑰𝑛 ) = 0. Triển khai định thức này


12

ta thu được một đa thức 𝑷𝑛 (𝜆) bậc n. Do đó ma trận có n trị riêng bao gồm
cả lặp và phức.
3. Khi ma trận A là ma trận đối xứng thì các trị riêng của A là các số thực.
4. Khi ma trận A là ma trận xác định dương thì các trị riêng của nó là các số
thực dương và nếu ma trận A là ma trận nửa xác định dương thì các trị riêng
của nó khơng âm. Chứng minh như sau: 𝜆𝒙𝑻𝒙 = 𝒙𝑻𝑨𝒙 > 0 khi A xác định
dương. Mặt khác 𝜆𝒙𝑻𝒙 = 𝜆||𝒙||𝟐𝟐 , ||𝒙||𝟐𝟐 > 0∀𝒙 ≠ 0. Suy ra λ>0λ>0, như
vậy mọi trị riêng của A đều dương. Chứng minh tương tự cho trường
hợp A bán xác định đương.
5. Tổng các phần tử trên đường chéo chính của ma trận 𝑨 ∈ ℝ𝑛×𝑛 thì bằng tổng
các trị riêng. Để chứng minh cơng thức này cần sử dụng đến phép phân tích
riêng sẽ được trình bày bên dưới. Khi ma trận A độc lập tuyến tính nó có thể
biểu diễn dưới dạng phân tích riêng như sau:
𝑨 = 𝑷𝑫𝑷−𝟏
Áp dụng hằng đẳng thức 𝒕𝒓𝒂𝒄𝒆(𝑨𝑩) = 𝒕𝒓𝒂𝒄𝒆(𝑩𝑨) ta có:
𝒕𝒓𝒂𝒄𝒆(𝑨) = 𝒕𝒓𝒂𝒄𝒆(𝑷𝑫𝑷−𝟏 ) = 𝒕𝒓𝒂𝒄𝒆((𝑷𝑫)𝑷−𝟏 ) = 𝒕𝒓𝒂𝒄𝒆(𝑷−𝟏 𝑷𝑫)
= 𝒕𝒓𝒂𝒄𝒆(𝑫)
Từ đó suy ra tổng các phần tử trên đường chéo chính của ma trận A bằng
tổng các trị riêng.
6. Định thức của ma trận 𝑨 ∈ ℝ𝑛×𝑛 thì bằng tích các trị riêng của nó. Sử dụng
phép phân tích riêng đối với ma trận A độ lập tuyến tính ta có:
𝑨 = 𝑷𝑫𝑷−𝟏
𝑨 = 𝑷𝑫𝑷−𝟏 ⇒ 𝒅𝒆𝒕(𝑨) = 𝒅𝒆𝒕(𝑷𝑫𝑷−𝟏 ) = 𝒅𝒆𝒕(𝑷). 𝒅𝒆𝒕(𝑫). 𝒅𝒆𝒕(𝑷−𝟏 )
= 𝒅𝒆𝒕(𝑫)



13

.
Phép phân tích riêng: Phép phân tích riêng (Eigen Decomposition) cũng là một
dạng matrix factorization. Nó có mối liên hệ chặt chẽ với SVD. Trong đại số tuyến
tính chúng ta ln có thể phân tích một ma trận vng độc lập tuyến tính
𝑨 ∈ ℝ𝑛×𝑛 thành tích của những ma trận vng 𝑷 ∈ ℝ𝑛×𝑛khả nghịch và ma trận
đường chéo 𝑫 ∈ ℝ𝑛×𝑛 theo cơng thức:
𝑨 = 𝑷𝑫𝑷−𝟏
Đẳng thức trên tương đương với:
AP=PD
Bây giờ ta chỉ xét đến cột thứ i của cả 2 ma trận bên vế trái và phải:
𝑨𝒑𝒊 = 𝑷𝒅𝒊
Trong đó 𝒑𝒊 , 𝒅𝒊 lần lượt là cột thứ i của ma trận P và D. Mặt khác do D là ma trận
đường chéo nên 𝑑𝑖 chỉ có duy nhất một phần tử khác 0 là𝑑𝑖𝑖 nên 𝑷𝒅𝒊 = 𝒑𝒊 𝑑𝑖𝑖 . Như
vậy:
𝑨𝒑𝒊 = 𝒑𝒅𝒊
Đây chính là phương trình xác định trị riêng của A. Ta có thể thấy diidii chính là trị
riêng của ma trận A và 𝒑𝒊 là các vector riêng tương ứng của 𝑑𝑖𝑖 .
Như vậy điểm đặc biệt của phân tích riêng đó là đường chéo chính của D là các trị
riêng của ma trận A và các cột của P là các vector riêng tương ứng với trị riêng nằm
trên đường chéo chính. Ngồi ra phép phân tích riêng khơng là duy nhất. Nếu ma
trận trực giao P thỏa mãn phương trình phân tích riêng thì ma trận kP cũng thỏa
mãn phương trình phân tích riêng đó.

1.4 Phát biểu SVD
Phương pháp phân tích trị riêng (SVD – Singular Value Decomposition) là
một đề tài rất được quan tâm của đại số tuyến tính. Đặc điểm quan trọng của



14

phương pháp này là nó có thể áp dụng cho bất kỳ ma trận thực m x n nào. Nội dung
của nó là: phân tích một ma trận A cho trước thành 3 ma trận U, D, V, sao cho:
A = UDV T


U = (u1,u2,...,uN) là một ma trận trực giao N x N.,uj,j = 1,...,N, tạo cơ sở
trực chuẩn cho không gian được kéo dài bởi vectơ cột của ma trận X.



V = (v1,v2,...,vp) là một ma trận trực giao p × p.vj,j = 1,...,p,tạo cơ sở trực
chuẩn cho khơng gian được kéo dài bởi vectơ dịng của ma trận X.



D là một ma trận hình chữ nhật Nxp với các phần tử khác không dọc theo
đường chéo thứ nhất p x p. diag(d1,d2,...,dp), d1 ≥ d2 ≥ ··· ≥ dp là các giá trị
riêng của ma trận X với N > p.
Các cột của V tức là vj,(j = 1,...,p) là các giá trị riêng của XTX. Chúng được
gọi là hướng thành phần chính của ma trận X.
Các giá trị đường chéo trong D tức là dj,j = (1,...,p) là căn bậc hai các giá
trị riêng của XTX.

Hình 1: SVD cho ma trận A khi: m<n (hình trên), và m>n(hình dưới). Σ là một ma
trận đường chéo với các phần tử trên đó giảm dần và khơng âm. Màu đỏ càng đậm
thể hiện giá trị càng cao. Các ô màu trắng trên ma trận này thể hiện giá trị 0



15

2.4 Phân tích suy biến trong python
Trong python phép phân tích suy biến của một ma trận được thực hiện dễ dàng
thông qua việc sử dụng hàm SVD của package scipy như sau:
import scipy.linalg as ln
import numpy as np
m, n = 2, 3
n_diag = min(m, n)
#Init normal standard random variable A with size (m, n)
A = np.random.rand(m, n)
U, S_diag, V = ln.svd(A)
#Create diagonal matrix S based on diagonal
S = np.zeros((n_diag, n_diag))
np.fill_diagonal(S, S_diag)
if m > n:
S = np.concatenate((S, np.zeros((1, n))), axis = 0)
elif m < n:
S = np.concatenate((S, np.zeros((m, 1))), axis = 1)
print('Matrix A: \n %s \n'%A)
print('orthogonal matrix U: \n %s \n'%U)
print('Check Frobenius U^TU-I: \n %s \n'%ln.norm(np.dot(U.T,U)-np.eye(m, m),
'fro'))
print('orthogonal matrix V: \n %s \n'%V)
print('Check Frobenius V^TV-I: \n %s \n'%ln.norm(np.dot(V.T,V)-np.eye(n, n),
'fro'))
print('Diagonal matrix S: \n %s \n'%S_diag)
print('Matrix S: \n %s \n'%S)
print('Check Frobenius U.S.V - A: \n %s \n'%ln.norm(np.dot(U, S.dot(V))-A,'f

ro'))

Matrix A:
[[0.14630186 0.28630696 0.95385295]
[0.74528454 0.31837132 0.51025156]]

orthogonal matrix U:
[[ 0.73134897 -0.68200343]
[ 0.68200343 0.73134897]]

Check Frobenius U^TU-I:
4.7152287001014445e-16


16

orthogonal matrix V:
[[ 0.47845355 0.33166831 0.81306724]
[ 0.84663666 0.07144886 -0.52735323]
[ 0.23299908 -0.94068655 0.24661758]]
Check Frobenius V^TV-I:
1.1025824029789615e-15
Diagonal matrix S:
[1.28598551 0.52594546]

Matrix S:
[[1.28598551 0.
[0.

0.


]

0.52594546 0.

]]

Check Frobenius U.S.V - A:
1.0576294775109601e-15

1.5 Các phép giảm chiều SVD.
Thông thường việc phân tích suy biến một ma trận có kích thước lớn sẽ rất lâu vì
địi hỏi phải giải phương trình đặc trưng để tìm ra các giá trị đặc trưng, từ đó suy ra
ma trận đường chéo Σ. Từ phương trình phân tích riêng 𝑨𝑻𝑨 = 𝑽𝜮𝑻𝜮𝑽𝑻 suy
ra 𝑨𝑻𝑨𝑽 = 𝑽𝜮𝑻 𝜮, sử dụng phương trình ứng với từng cột cả 2 vế trái và phải để
tính ra được các vector riêng ứng với mỗi trị riêng và suy ra được ma trận V. Cách
tìm ma trận U cũng được suy ra tương tự từ phương trình phân tích riêng
𝑨𝑨𝑻 = 𝑼𝜮𝜮𝑻𝑼𝑻. Quá trình này phải trải qua nhiều bước và khi kích thước ma trận
lớn, chi phí thời gian và lưu trữ sẽ rất lớn. Vì vậy các dạng giảm chiều SVD sẽ rút
gọn q trình tính tốn.


17

1.6 Phương pháp làm mỏng SVD.
Xuất phát từ ý tưởng số quan sát thường lớn gấp rất nhiều lần so với số chiều
hay m>>nm>>n trong hầu hết các trường hợp của ma trận A nên thay vì phải tính
tốn bộ ma trận 𝑼𝑚𝑚 ta sẽ chỉ tính n cột đầu tiên là 𝑼𝑛𝑛 . Số chiều của ma trận
đường chéo 𝜮𝑚𝑚 cũng giảm xuống thành 𝜮𝑛𝑛 . Khi đó ma trận A được biểu diễn
dưới dạng:

𝑨 = 𝑼𝑚𝑛 𝜮𝑛𝑛 𝑽𝑻𝑛𝑛
Như vậy số lượng các trị riêng cần tìm chỉ cịn nn và số lượng vector riêng chỉ
còn 2n2n (nn cột của ma trận 𝑼𝑚𝑛 và n cột của ma trận 𝑽𝑛𝑛 ).
1.7 Phương pháp Compact SVD.
Ta có thể biểu diễn ma trận 𝑨 dưới dạng tổng của các tích vector cột 𝒖𝒊 ∈
ℝ𝑚 của 𝑼𝑚𝑚 và vector dòng của 𝑽𝑻𝑛𝑛 như sau:
𝑛

𝑨 = ∑ 𝒖𝒊 𝜎𝒊 𝒗𝒊
𝑖=1

Các vector 𝒖𝒊 và 𝒗𝒊 là các hệ cơ sở độc lập tuyến tính. Thông thường trong ma trận
đường chéo 𝜮𝑛𝑛 chỉ một lượng lớn các trị riêng có lớn hơn 0. Các trị riêng cịn lại
đều xấp xỉ 0. Do đó chỉ tại rr vị trí dịng và cột tương ứng với các trị riêng đủ lớn ta
mới thực hiện tính tốn SVD. Biểu diễn ma trận 𝑨𝑛𝑛 dưới dạng compact SVD như
sau:
𝑨 = 𝑼𝑟 𝜮𝑟 𝑽𝑻𝑟
Trong đó các ma trận 𝑼𝑟 , 𝜮𝑟 , 𝑽𝑻𝑟 lần lượt là các ma trận sau khi đã rút gọn các dòng
và cột để chỉ giữ lại các vị trí tương ứng với σiσi đủ lớn. Nếu r<tính này tiết kiệm được nhiều số lượng tính tốn và lưu trữ hơn so với phương pháp
làm mỏng SVD.


18

1.8 Phương pháp Truncated SVD
Trong phương pháp này ta giả định ma trận A là ma trận bán xác định dương. Khi
đó mọi trị riêng của nó đều khơng âm. Phương pháp Truncated SVD cũng tương tự
như Compact SVD. Tuy nhiên thay vì các dịng và cột tương ứng với trị riêng đủ
lớn trên ma trận đường chéo 𝜮𝑛𝑛 thì chúng ta sẽ chỉ lấy ra t dòng và cột ứng với

top t các trị riêng 𝜎1 > 𝜎2 >. . . > 𝜎𝑡 > 0 lớn nhất của A từ 𝑼, 𝑽𝑻. Phần còn lại của
ma trận sẽ bị loại bỏ. Như vậy trong phương pháp Truncated SVD ta sẽ thu được
ma trận xấp xỉ của ma trận A là ma trận:
^

𝑨 = 𝑼𝑡 𝜮𝑡 𝑽𝑻𝑡
Hoặc ta có thể biểu diễn dưới dạng tổng của tích vơ hướng các vector cột và dòng
của U,VTU,VT như sau:
𝑡

𝑨 = ∑ 𝒖𝒊 𝜎𝒊 𝒗

(𝟓)

𝑖=1

Khi đó ta cịn tính được khoảng cách norm Frobenius giữa A^A^ và A chính bằng
tổng bình phương của các trị riêng còn lại từ σt+1σt+1 đến σnσn (với giả
định A có nn trị riêng) như sau:


19

^

||𝑨 − 𝑨||2𝐹

^

^


(𝑨 − 𝑨)𝑻(𝑨 − 𝑨)

=
𝑛

𝑛

= ( ∑ 𝒖𝒊 𝜎𝒊 𝒗𝒊)𝑻( ∑ 𝒖𝒊 𝜎𝒊 𝒗𝒊 )
𝑖=𝑡+1
𝑛

=

𝑖=𝑡+1
𝑛

( ∑ 𝜎𝒊 𝒗𝑻𝒊 𝒖𝑻𝒊 )( ∑ 𝜎𝒊 𝒖𝒊 𝒗𝒊 )
𝑖=𝑡+1
𝑛

𝑖=𝑡+1
𝑛

=

∑ ∑ 𝜎𝒊 𝜎𝒋 𝒗𝑻𝒊 𝒖𝑻𝒊 𝒖𝒋 𝒗𝒋
𝑗=𝑡+1
𝑖=𝑡+1


𝑛

∑ 𝜎𝒊𝟐 𝒗𝑻𝒊 𝒖𝑻𝒊 𝒖𝒊 𝒗𝒊

=

𝑖=𝑡+1
𝑛

∑ 𝜎𝒊𝟐 𝒗𝑻𝒊 𝒗𝒊

=

𝑖=𝑡+1
𝑛

∑ 𝜎𝒊𝟐

=

𝑖=𝑡+1

Dấu bằng thứ 3 là vì lấy đẳng thức (4) trừ đi (5). Dấu bằng thứ 5 xảy ra là do ma các
vector cột của U,V là những hệ trực giao nên
𝒖𝑻𝒊 𝒖𝒋 = 0, 𝒗𝑻𝒊 𝒗𝒋 = 0, ∀1 ≤ 𝑖 ≠ 𝑗 ≤ 𝑛. Các dấu bằng 6, 7 là do
𝒖𝑻𝒊 𝒖𝒊 = 1, 𝒗𝑻𝒊 𝒗𝒊 = 1, ∀1 ≤ 𝑖 ≤ 𝑛. Như vậy ta đã hiểu lý do tại sao chúng ta chỉ
chọn ra top t trị riêng có giá trị lớn nhất. Khi đó sai số của 2 ma trận sẽ là nhỏ nhất
vì bằng tổng bình phương của các trị riêng cịn lại. Phương pháp truncated SVD
còn cho ta biết được tỷ lệ phần trăm lượng thông tin lưu giữ trong ma trận xấp xỉ
thơng qua cơng thức:

𝐭

∑𝐢=𝟏 𝛔𝟐𝐢
𝐧


𝐣=𝟏

𝛔𝟐𝐣

2.5. Bài tốn xấp xỉ low-rank.`
Bài toán xấp xỉ low-rank là một trong những ứng dụng phổ biến của phân tích suy
biến. Mục tiêu chính của bài tốn là tìm một ma trận xấp xỉ tốt nhất với ma trận gốc


20

nhưng có hạng xác định trước và nhỏ hơn hạng của ma trận gốc. Mức độ xấp xỉ
được đo lường thông qua chuẩn Frobenius của hiệu 2 ma trận. Bài tốn có dạng như
sau:
𝑎𝑟𝑔

𝑚𝑖𝑛 ||𝑨 − 𝑿||𝟐𝑭

𝑟𝑎𝑛𝑘(𝑋) =𝑘

Người ta chứng minh được rằng nghiệm của bài tốn low-rank chính là phép
truncated SVD đối với kk trị riêng lớn nhất.
1.9 Ứng dụng của phân tích suy biến SVD
1.9.1 Giải phương trình tuyến tính.

SVD được sử dụng trong việc giải các phương trình hồi qui tuyến tính trong trường
hợp tổng qt. Như chung ta đã biết bài tốn hồi qui tuyến tính sẽ tìm một phương
trình có dạng tuyến tính sao cho khác biệt giữa các điểm dữ liệu dự báo và thực tế là
nhỏ nhất. Khác biệt này được đo lường thơng qua một hàm loss function có dạng:
ℒ(𝒘) =

1
||𝒚 − 𝑿𝒘||22
2𝑛

Trong đó 𝒚 ∈ ℝ𝑚 là vector biến mục tiêu (hoặc biến phụ thuộc). Ma trận 𝑿 ∈ ℝ𝑚×𝑛
là ma trận mở rộng của ma trận đầu vào có mỗi dòng là một quan sát và mỗi cột là
một chiều dữ liệu. Ma trận này có cột cuối cùng bằng 1 đại diện cho hệ số tự do
𝑿 ∈ ℝ𝑚×𝑛 là vector các hệ số của phương trình hồi qui và là đại lượng biến đổi
trong phương trình loss function. Thơng qua việc giải phương trình đạo hàm bậc
nhất của hàm loss function ta có thể tìm được ww.
Theo phương trình đạo hàm tích (Product rules) ta có:
𝛻𝒙 (𝑓 𝑻𝑔) = (𝛻𝒙 𝑓)𝑔 + (𝛻𝒙 𝑔)𝑓
Do đó đạo hàm 𝛻𝒙 (𝑓 𝑻𝑓) = 2(𝛻𝒙 𝑓)𝑓. Áp dụng vào triển khai đạo hàm ℒ(𝒘)


21

𝜕ℒ(𝒘)
1 𝜕(𝒚 − 𝑿𝒘)𝑻(𝒚 − 𝑿𝒘)
=
𝜕𝒘
2𝑛
𝜕𝒘
1 (𝜕(𝒚 − 𝑿𝒘))(𝒚 − 𝑿𝒘)

=
𝑛
𝜕𝒘
𝑻
1 𝑿 (𝒚 − 𝑿𝒘)
=
𝑛
𝜕𝒘
Đẳng thức dòng thứ 3 xảy ra là do 𝛻𝒙 𝑿𝒘 = 𝑿𝑻. Đặt 𝑨: = 𝑿𝑻𝑿 và 𝑿𝑻 𝒚: = 𝒃 Như
vậy nghiệm w của hàm loss function sẽ thỏa màn 𝑨𝒘 = 𝒃. Trong trường hợp A khả
nghịch phương trình có nghiệm 𝒘 = 𝑨−1 𝒃. Tuy nhiên trường hợp A không khả
nghịch để tìm nghiệm của bài tốn ta cần sử dụng đến ma trận giả nghịch đảo (còn
gọi là ma trận Pseudo - Inverse hoặc ma trận Moore - Penrose) của A được kí hiệu
là A †. Các định nghĩa và tính chất về ma trận giả nghịch đảo có thể tìm hiểu
tại Pseudo - Inverse. Ma trận giả nghịch đảo có thể được giải nhờ phép phân tích
suy biến của A. Nếu ma trận A có biểu diễn phân tích suy biến dạng:
𝑨 = 𝑼𝜮𝑽𝑻
Khi đó ma trận giả nghịch đảo của A sẽ là:
𝑨† = 𝑽𝜮−𝟏 𝑼𝑻
Ta thấy ma trận giả nghịch đảo vẫn có tính chất như ma trận nghịch đảo đó
là 𝑨† 𝑨 = 𝑰. Bên dưới ta sẽ sử dụng SVD để giải phương trình hồi qui tuyến tính.
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
n = 100
x = np.arange(n)
# add 1 column in the last of X to create X matrix
X = np.concatenate((x.reshape(n, 1), np.ones((n, 1))), axis = 1)
y = np.random.randn(n)*10 + 2*x
plt.plot(x, y)



22

# Calculate matrix A, b
A = np.dot(X.T, X)
b = np.dot(X.T, y)
# Matrix factorization SVD
U, S_diag, V = np.linalg.svd(A)
S = np.zeros((S_diag.shape[0], S_diag.shape[0]))
np.fill_diagonal(S, S_diag)
S_inv = np.linalg.inv(S)
# Pseudo - inverse matrix
A_pse = np.dot(V.T, np.dot(S_inv, U))
# Estimate coefficient
w_svd = np.dot(A_pse, b)
print('w calculated from SVD: %s' %str(w_svd))

w calculated from SVD: [ 2.03561275 -1.85810255]

from sklearn import linear_model
ln_reg = linear_model.LinearRegression(fit_intercept = False)
ln_reg.fit(X, y)
print('w calculated from sklearn: %s' %str(ln_reg.coef_))

w calculated from sklearn: [ 2.03561275 -1.85810255]
1.9.2 Giảm chiều dữ liệu hình ảnh.
Giả sử ta có một tập dữ liệu nhiều ảnh có kích thước rất lớn. Khả năng lưu trữ của
server là có hạn. Trong tình huống này làm thể nào để giảm kích thước của bộ ảnh
vừa với dung lượng server mà thông tin của các bức ảnh vẫn giữ được một lượng

lớn. Câu trả lời sẽ có sau khi khi ta thực hành nén một bức ảnh bằng thuật toán
truncated SVD.


23

Bức ảnh gốc
import matplotlib.pyplot as plt
import numpy as np
import scipy.linalg as ln
from PIL import Image
import urllib.request
from io import BytesIO
%matplotlib inline
url = str(' />ung-thu-chi-thuoc-ve-nu-than-han-quoc-song-hye-kyo-3-1499791578-width500heig
ht330.jpg')
with urllib.request.urlopen(url) as url:
f = BytesIO(url.read())
ig = np.array(Image.open(f))
print('Image shape: %s'%str(ig.shape))
# Convert to grey
ig = ig.dot([0.299, 0.5870, 0.114])
plt.imshow(ig)

Image shape: (330, 500, 3)
<matplotlib.image.AxesImage at 0x242211cb340>

Ta sẽ thực hiện nén ảnh theo phương pháp SVD sao cho chỉ lấy lần lượt với 10 và 2
0 trị riêng lớn nhất để lưu giữ thông tin.
def SVD_pic(n_evl):

"""
n_evl: number of highest eigenvalues taken
"""
#Take m, n shape
m = ig.shape[0]
n = ig.shape[1]


24

#Singular Value Decomposition
U, S, V = ln.svd(ig)
#Get id position of n highest eigenvalues
id_trunc = np.argsort(S)[::-1][:n_evl]
#Extract matrix U_t, V_t, S_t
U_t = U[np.ix_(np.arange(m), id_trunc)]
V_t = V[np.ix_(id_trunc, np.arange(n))]
S_diag = S[id_trunc]
S_t = np.zeros((n_evl, n_evl))
np.fill_diagonal(S_t, S_diag)
#Return picture
A = np.dot(U_t, S_t.dot(V_t))
#Norm Frobenius
fb = ln.norm(A-ig, 'fro')
prt_retain = (1-fb**2/np.sum(S**2))*100
plt.imshow(A)
print('Percentage of information retained: %.2f%s \n'%(prt_retain, '%'))

Kết quả nén ảnh với lần lượt 10 và 20 trị riêng lớn nhất
SVD_pic(10)

Percentage of information retained: 99.39%

SVD_pic(20)
Percentage of information retained: 99.74%


25

Như vậy với 10 trị riêng lớn nhất đã thể hiện được được 99.39% thông tin bức ảnh
và với 20 trị riêng lớn nhất thể hiện được 99.74% thông tin bức ảnh. So với bức ảnh
gốc ta phải lưu trữ ma trận có kích thước là 330x500. Trong khi với 20 chiều vector
ta chỉ phải lưu trữ các ma trận Ut,VtUt,Vt có kích thước là 330x20, 20x500 và ma
trận SS có kích thước là 20x20. Giả định mỗi phần tử của ma trận được lưu với
cùng số byte. Như vậy số lượng thơng tin ta cần lưu chỉ là:
330 × 20 + 20 × 500 + 20 × 20
= 10%
330 × 500
Dó đó phương pháp truncated SVD thường được sử dụng trong nén thông tin rất
hiệu quả.
2. Phương pháp phân tích thành phần chính – Principal Component Annalysis
(PCA)
2.1 Khái niệm
Phân tích thành phần chính ( PCA ) là một thủ tục thống kê có sử dụng
một chuyển đổi trực giao để chuyển đổi một tập hợp các quan sát của các biến thể
tương quan vào một tập hợp các giá trị của tuyến tính tương quan biến được gọi
là thành phần chủ yếu . Số lượng các thành phần chủ yếu là nhỏ hơn hoặc bằng số
lượng các biến ban đầu. Sự biến đổi này được định nghĩa trong một cách mà các
thành phần chủ yếu đầu tiên có thể lớn nhất sai (có nghĩa là, chiếm càng nhiều các



×