Khóa học
Phần lớn những gì bạn cần biết để thực sự dấn sâu vào machine learning là đại số tuyến tính, và đó chính là điều hướng dẫn này đề cập. Bài viết hôm nay đi qua các chủ đề đại số tuyến tính mà bạn cần biết và hiểu để cải thiện trực giác về cách và thời điểm các phương pháp machine learning hoạt động bằng cách nhìn ở cấp độ vectơ và ma trận.
Đến cuối hướng dẫn, hy vọng bạn sẽ tự tin hơn để xem xét kỹ một thuật toán!
Contents
Introduction
Một trong ba chủ đề cơ bản mà bạn cần làm chủ nếu muốn học khoa học dữ liệu là machine learning. Và khi thực sự bước vào machine learning, quan trọng là đào sâu để xây dựng trực giác và hiểu cách các thuật toán hoạt động.
Tôi nghĩ bạn, một nhà khoa học dữ liệu (tương lai), có lẽ sẽ đồng ý rằng để đạt đến mức này là một việc không hề dễ.
Nhưng không nhất thiết phải vậy.
SciPy versus NumPy
Từ hướng dẫn NumPy của DataCamp, bạn sẽ thấy thư viện này là một trong các thư viện cốt lõi cho tính toán khoa học trong Python. Thư viện này chứa tập hợp công cụ và kỹ thuật có thể dùng để giải trên máy tính các mô hình toán học của bài toán trong Khoa học và Kỹ thuật. Nhưng công cụ bạn dùng thường xuyên nhất là đối tượng mảng đa chiều hiệu năng cao: một cấu trúc dữ liệu mạnh mẽ cho phép tính toán hiệu quả trên mảng và ma trận.
Giờ đây, về cơ bản SciPy chính là NumPy.
Nó cũng là một trong các gói cốt lõi cho tính toán khoa học, cung cấp thuật toán toán học và các hàm tiện ích, nhưng được xây dựng trên phần mở rộng NumPy của Python. Điều này có nghĩa SciPy và NumPy thường được dùng cùng nhau!
Ở phần sau của hướng dẫn, bạn sẽ thấy rõ vì sao sự phối hợp giữa hai thư viện này trở nên hiển nhiên.
Interact with NumPy and SciPy
Để tương tác hiệu quả với cả hai gói, trước hết bạn cần biết một số điều cơ bản về thư viện này và cấu trúc dữ liệu mạnh mẽ của nó. Để làm việc với các mảng này, có một lượng lớn các hàm toán học cấp cao vận hành trên những ma trận và mảng đó.
Phần tiếp theo sẽ điểm nhanh các chủ đề bạn cần nắm để làm việc hiệu quả với SciPy. Cốt lõi là bạn phải biết về cấu trúc mảng, cách xử lý kiểu dữ liệu và cách thay đổi hình dạng mảng. Nếu nghe lạ, hãy cân nhắc học Python NumPy Tutorial của DataCamp và trong lúc học, đừng quên xem NumPy cheat sheet.
Nếu bạn đã biết hết, hãy bỏ qua phần sau và chuyển đến “Linear Algebra With SciPy”, nhưng hãy sẵn sàng SciPy cheat sheet về đại số tuyến tính!
The Essentials of NumPy ndarray Objects
Về mặt cấu trúc, một mảng chẳng qua là các con trỏ. Đó là sự kết hợp của địa chỉ bộ nhớ, kiểu dữ liệu, hình dạng và bước nhảy (strides). Nó chứa thông tin về dữ liệu thô, cách định vị một phần tử và cách diễn giải phần tử đó.
Địa chỉ bộ nhớ và bước nhảy quan trọng khi bạn đi sâu vào chi tiết mức thấp của mảng, trong khi kiểu dữ liệu và hình dạng là những thứ người mới nên biết và hiểu. Hai thuộc tính khác bạn có thể quan tâm là data và size, giúp bạn thu thập thêm thông tin về mảng.
Ôn lại cách dùng các thuộc tính của ndarray trong khối DataCamp Light sau. Mảng myArray đã được nạp sẵn. Bạn có thể kiểm tra bằng cách gõ nó trong IPython shell và nhấn ENTER.
Bạn sẽ thấy trong kết quả của đoạn mã trên rằng kiểu dữ liệu của myArray là int64. Khi làm việc nhiều với mảng, bạn chắc chắn sẽ nhớ rằng có cách để chuyển kiểu dữ liệu mảng bằng phương thức astype().
Tuy nhiên, khi dùng SciPy và NumPy cùng nhau, bạn cũng sẽ thấy các hàm xử lý kiểu dữ liệu sau của NumPy rất hữu ích, đặc biệt khi làm với số phức:
Hãy thử thêm các lệnh print() để xem kết quả mã ở trên. Khi đó bạn sẽ thấy số phức có phần thực và phần ảo. Các hàm np.real() và np.imag() lần lượt trả về các phần này.
Ngoài ra, bạn cũng có thể dùng np.cast để ép kiểu một đối tượng mảng sang kiểu dữ liệu khác, như float trong ví dụ trên.
Điểm duy nhất hơi khó ở đoạn mã trên là hàm np.real_if_close(). Khi bạn đưa vào đầu vào phức, như myArray, bạn sẽ nhận về một mảng thực nếu phần phức gần bằng 0. Phần “gần bằng 0” này có thể tự điều chỉnh bằng tham số tol bạn truyền vào hàm. Hãy thử thay đổi ngưỡng để xem điều gì xảy ra!
Array Creation
Bạn vừa thấy cách kiểm tra mảng và điều chỉnh kiểu dữ liệu, nhưng chưa thấy rõ cách tạo mảng. Bạn hẳn đã biết có thể dùng np.array() để làm việc này, nhưng còn có các thủ tục tạo mảng khác bạn nên biết: np.eye() và np.identity().
Hàm np.eye() cho phép bạn tạo ma trận vuông với kích thước bằng số nguyên dương bạn đưa làm đối số. Các phần tử thường được điền bằng 0, chỉ đường chéo ma trận được điền 1. Hàm np.identity() hoạt động tương tự và cũng trả về một mảng đơn vị.
Tuy nhiên, lưu ý rằng np.eye() có thể nhận đối số bổ sung k để bạn chỉ định chỉ số của đường chéo muốn điền 1.
Các hàm tạo mảng khác chắc chắn hữu ích khi làm việc với ma trận trong đại số tuyến tính gồm:
- Hàm
np.arange()tạo mảng với các giá trị cách đều giữa hai số. Bạn có thể chỉ định bước giữa các phần tử, - Điều này cũng đúng với
np.linspace(), nhưng với hàm này bạn chỉ định số phần tử bạn muốn trong mảng. - Cuối cùng, hàm
np.logspace()cũng tạo mảng với các giá trị cách đều, nhưng theo thang đo logarit. Nghĩa là khoảng cách giờ là logarit: hai số cách đều giữa logarit cơ số 10 của chúng.
Các hàm này tạo ra mảng dạng lưới, có thể dùng để tạo lưới ô (mesh grid), về điều này bạn đã đọc trước đó trong bài.
Lưu ý rằng numpy đã được import là np trong khối mã dưới đây!
Giờ khi đã ôn lại cách xử lý kiểu dữ liệu mảng, đã đến lúc bàn về đánh chỉ số và cắt (slicing).
Indexing and Slicing
Với indexing, bạn dùng ngoặc vuông [] để truy cập giá trị mảng. Nói cách khác, bạn có thể dùng indexing nếu muốn truy cập các phần tử được chọn — một tập con — của mảng. Cắt (slicing) dữ liệu rất giống với tạo tập con, nhưng có thể coi là nâng cao hơn một chút. Khi bạn cắt một mảng, bạn không chỉ xét các giá trị riêng lẻ, mà làm việc với “vùng” dữ liệu thay vì các “vị trí” thuần túy.
Ôn lại cả hai khái niệm với các ví dụ sau:
Giờ khi đầu óc đã “tươi mới” với slicing và indexing, bạn có thể quan tâm một vài mẹo chỉ số giúp công việc hiệu quả hơn khi tính toán khoa học với SciPy. Có bốn hàm sẽ thường gặp: np.mgrid(), np.ogrid(), np.r và np.c.
Bạn có thể đã biết hai hàm sau nếu có chút kinh nghiệm với NumPy. np.r và np.c thường dùng khi bạn cần xếp chồng mảng theo hàng hoặc theo cột, tương ứng. Với các hàm này, bạn có thể nhanh chóng dựng mảng thay vì dùng np.concatenate().
Khi xem hai hàm đầu trong bốn hàm này, bạn có thể tự hỏi vì sao cần meshgrid. Bạn có thể dùng meshgrid để tạo hai mảng chứa tọa độ x và y tại mỗi vị trí trong một lưới trực chuẩn. Hàm np.meshgrid() nhận hai mảng 1D và tạo ra hai ma trận 2D tương ứng với mọi cặp (x, y) trong hai mảng.
- Hàm
np.mgrid()là một hiện thực của meshgrid trong MATLAB và trả về các mảng có cùng hình dạng. Nghĩa là số chiều và số lượng mảng đầu ra bằng với số chiều đánh chỉ số. - Hàm
np.ogrid(), ngược lại, tạo ra một meshgrid mở và không dày đặc như kết quả củanp.mgrid(). Bạn có thể thấy khác biệt trực quan giữa hai hàm trong khối mã ở trên.
Bạn cũng có thể đọc thêm về khác biệt giữa hai hàm này tại đây.
Một hàm khác hữu dụng cho mục đích indexing/slicing là np.select(). Bạn có thể dùng nó để trả về các giá trị từ một danh sách mảng dựa trên các điều kiện, do bạn chỉ định ở đối số đầu tiên. Ở đối số thứ hai, bạn truyền vào mảng muốn xét cho quá trình chọn lọc.
Xem ví dụ sau:
Tuyệt vời! Giờ khi bạn đã chọn được giá trị phù hợp từ mảng gốc, bạn vẫn có thể chọn hình dạng và thao tác mảng mới.
Shape Selection and Manipulation
NumPy cung cấp rất nhiều cách để chọn và thao tác hình dạng mảng, và có lẽ bạn đã biết nhiều trong số đó. Phần sau chỉ điểm qua ngắn gọn các hàm có thể hữu ích, nên sẽ không bao quát tất cả.
Vậy có những hàm nào “tiện tay” khi làm với SciPy?
Hữu ích nhất là các hàm giúp bạn làm phẳng mảng, xếp chồng và tách mảng. Bạn đã thấy các hàm np.c và np.r thường được ưa dùng thay vì np.concatenate(), nhưng còn nhiều cái khác bạn nên biết!
Như np.hstack() để xếp chồng ngang mảng hoặc np.vstack() để xếp chồng dọc. Tương tự, bạn có thể dùng np.vsplit() và np.hsplit() để tách mảng theo chiều dọc và ngang. Nhưng có lẽ bạn đã biết những điều này.
Chứng minh đi trong khối mã sau:
Nhớ rằng hàm np.eye() tạo mảng đơn vị 2x2, rất phù hợp để xếp chồng với mảng 2-D đã được nạp sẵn ở trên.
Nếu muốn biết thêm về các điều kiện cần lưu ý khi xếp chồng mảng, xem tại đây. Tuy nhiên, bạn cũng có thể chỉ cần quan sát các mảng và những gì hàm thực hiện để hình thành trực giác về các “quy tắc” cần tuân theo khi ghép hai mảng theo hàng hoặc cột.
Điều quan trọng nhất khi tách mảng có lẽ là hình dạng mảng, vì bạn muốn chọn đúng chỉ số nơi tách xảy ra.
Ngoài các hàm xếp chồng và tách mảng, bạn cũng nên nhớ những hàm giúp đảm bảo bạn đang làm việc với mảng ở một số chiều nhất định là không thể thiếu khi đào sâu tính toán khoa học.
Cân nhắc các hàm sau:
Lưu ý sự khác biệt giữa reshaping và resizing mảng. Với reshape, bạn thay đổi hình dạng dữ liệu nhưng không thay đổi dữ liệu. Khi resize, dữ liệu trong mảng có thể thay đổi, tùy hình dạng bạn chọn.
Ngoài các thủ tục tách và xếp chồng và các hàm cho phép thao tác sâu hơn với mảng, còn có “vector hóa” bạn cần cân nhắc. Khi áp dụng một hàm lên mảng, bạn thường áp dụng lên từng phần tử. Ví dụ áp dụng np.cos(), np.sin() hoặc np.tan() lên mảng. Bạn sẽ thấy chúng hoạt động trên mọi phần tử. Khi thấy điều này, bạn biết hàm đã được vector hóa.
Nhưng khi bạn tự định nghĩa hàm, như bạn sẽ thường làm khi tính toán khoa học, bạn cũng có thể muốn vector hóa chúng. Khi đó, bạn có thể gọi np.vectorize():
Về các hàm toán học đã được vector hóa khác mà bạn nên biết, hãy cân nhắc np.angle() để trả về góc của các phần tử phức, cùng các hàm lượng giác, mũ hay logarit cơ bản.
Linear Algebra with SciPy
Giờ khi bạn biết cần dùng cả hai gói như thế nào để có lợi, đã đến lúc đi vào chủ đề của hướng dẫn: đại số tuyến tính.
Nhưng trước khi tìm hiểu cách dùng Python, hãy đảm bảo môi trường làm việc của bạn đã sẵn sàng!
Install SciPy
Tất nhiên bạn cần đảm bảo trước hết đã cài Python. Truy cập trang này nếu bạn vẫn cần làm điều đó :) Nếu bạn dùng Windows, hãy đảm bảo đã thêm Python vào biến môi trường PATH environment variable. Ngoài ra, đừng quên cài một trình quản lý gói, như pip, để đảm bảo bạn có thể dùng các thư viện mã nguồn mở của Python.
Lưu ý các phiên bản gần đây của Python 3 đi kèm pip, nên hãy kiểm tra xem bạn đã có chưa và nếu có, hãy nâng cấp trước khi cài các gói khác:
pip install pip --upgrade pip --version
Nhưng chỉ cài trình quản lý gói là chưa đủ; Bạn cũng cần tải về wheel cho thư viện: vào đây để lấy wheel SciPy. Sau khi tải, mở terminal tại thư mục tải về trên máy và cài nó. Ngoài ra, bạn có thể kiểm tra cài đặt có thành công và xác nhận phiên bản gói bạn đang dùng:
# Install the wheel install "scipy‑0.18.1‑cp36‑cp36m‑win_amd64.whl"# Confirm successful installimport scipy# Check package versionscipy.__version__
Sau các bước này, bạn đã sẵn sàng “goy”!
Mẹo: cài gói bằng cách tải bản phân phối Anaconda Python. Đây là cách dễ để bắt đầu nhanh, vì Anaconda không chỉ bao gồm 100 gói Python, R và Scala phổ biến cho khoa học dữ liệu, mà còn đi kèm nhiều môi trường phát triển mở như Jupyter và Spyder. Nếu bạn muốn bắt đầu với Jupyter Notebook, xem hướng dẫn Jupyter notebook này.
Nếu bạn chưa tải, vào đây để lấy.
Vectors and Matrices: The Basics
Giờ khi bạn đã chuẩn bị xong môi trường làm việc, bạn có thể bắt đầu với đại số tuyến tính trong Python. Về bản chất, lĩnh vực này nghiên cứu không gian vectơ và các ánh xạ tuyến tính tồn tại giữa chúng. Các ánh xạ tuyến tính có thể mô tả bằng ma trận, qua đó việc tính toán cũng dễ hơn.
Nhớ rằng không gian vectơ là khái niệm nền tảng trong đại số tuyến tính. Đó là một không gian nơi bạn có tập hợp đối tượng (vectơ) và nơi bạn có thể cộng hoặc nhân (tỷ lệ) hai vectơ mà vectơ kết quả vẫn nằm trong không gian. Cũng nhớ rằng vectơ là các hàng (hoặc cột) của một ma trận.
Vậy điều này hoạt động thế nào trong Python?
Bạn có thể dễ dàng tạo một vectơ với hàm np.array(). Tương tự, bạn có thể gán cấu trúc ma trận cho mọi ndarray một hoặc hai chiều với lệnh np.matrix() hoặc np.mat().
Thử trong khối mã sau:
Vậy mảng và ma trận giống nhau, ngoài phần định dạng?
Không hẳn. Có vài khác biệt:
- Ma trận là 2-D, trong khi mảng thường là
n-D, - Như các hàm trên ngụ ý, ma trận là một lớp con của
ndarray, - Cả mảng và ma trận đều có
.T(), nhưng chỉ ma trận có.H()và.I(), - Nhân ma trận khác với nhân phần tử của mảng, và
- Thêm nữa, phép
**có kết quả khác nhau với ma trận và mảng
Khi làm việc với ma trận, đôi khi bạn có các ma trận trong đó hầu hết phần tử là 0. Những ma trận này gọi là “ma trận thưa” (sparse), trong khi những ma trận có đa số phần tử khác 0 gọi là “ma trận đặc” (dense).
Bản thân điều này có vẻ tầm thường, nhưng khi làm với SciPy cho đại số tuyến tính, đôi khi nó ảnh hưởng đến các mô-đun bạn dùng để hoàn thành công việc. Cụ thể, bạn có thể dùng scipy.linalg cho ma trận đặc, nhưng khi làm với ma trận thưa, bạn cũng nên xem mô-đun scipy.sparse, vốn cũng có scipy.sparse.linalg riêng.
Với ma trận thưa, có khá nhiều lựa chọn để tạo chúng. Khối mã dưới đây liệt kê một số:
Ngoài ra, còn có một số hàm khác để tạo ma trận thưa: ma trận Hàng Thưa Khối với bsr_matrix(), ma trận thưa định dạng Tọa độ với coo_matrix(), ma trận thưa lưu trữ Đường chéo với dia_matrix(), và ma trận thưa danh sách liên kết theo hàng với lil_matrix().
Có rất nhiều lựa chọn, nhưng chọn cái nào khi bạn tự tạo ma trận thưa?
Không khó đâu.
Cơ bản là đầu tiên bạn khởi tạo như thế nào. Tiếp theo, cân nhắc bạn muốn làm gì với ma trận thưa.
Cụ thể, bạn có thể đi qua danh sách kiểm tra sau để quyết định loại ma trận thưa cần dùng:
- Nếu bạn định điền ma trận theo từng số một, chọn
coo_matrix()hoặcdok_matrix()để tạo ma trận. - Nếu bạn muốn khởi tạo ma trận với một mảng làm đường chéo, chọn
dia_matrix(). - Với ma trận dựa trên lát cắt, dùng
lil_matrix(). - Nếu bạn dựng ma trận từ các khối ma trận nhỏ hơn, cân nhắc dùng
bsr_matrix(). - Nếu bạn muốn truy cập hàng và cột nhanh, hãy chuyển đổi ma trận bằng
csr_matrix()vàcsc_matrix(), tương ứng. Hai hàm sau không phù hợp khi khởi tạo ma trận, nhưng khi nhân, bạn sẽ thấy khác biệt về tốc độ.
Dễ như ăn kẹo!
Vector Operations
Giờ khi bạn đã học hoặc ôn lại khác biệt giữa vectơ, ma trận đặc và ma trận thưa, đã đến lúc xem kỹ vectơ và các phép toán có thể thực hiện. Phần này tập trung cụ thể vào các phép toán để bạn thấy điểm giống và khác với ma trận, và vì phần lớn đại số tuyến tính rốt cuộc là làm việc với ma trận.
Bạn đã thấy có thể dễ dàng tạo vectơ với np.array(). Nhưng khi đã có vectơ, bạn cũng nên biết một số thao tác cơ bản có thể thực hiện. vector1 và vector2 đã được nạp sẵn trong khối mã sau:
Giờ khi bạn đã xem thành công một số phép toán trên vectơ, đã đến lúc bắt tay vào phần ma trận thực thụ!
Matrices: Operations and routines
Tương tự nơi bạn dừng ở đầu phần trước, bạn biết cách tạo ma trận, nhưng chưa biết dùng chúng như thế nào cho hiệu quả. Phần này cung cấp cái nhìn tổng quan về một số hàm ma trận và các thủ tục cơ bản để bạn làm việc hiệu quả.
Đầu tiên, cùng điểm qua một số hàm. Điều này sẽ khá dễ nếu bạn từng làm việc với NumPy, nhưng ngay cả khi chưa có kinh nghiệm, bạn sẽ thấy các hàm này dễ dùng.
Hãy xem vài ví dụ hàm.
Có np.add() và np.subtract() để cộng và trừ mảng hoặc ma trận, cũng như np.divide() và np.multiply cho phép chia và nhân. Điều này thực sự không có gì bí ẩn, đúng không? Hàm np.dot() mà bạn đã thấy ở phần trước dùng để tính tích vô hướng cũng có thể dùng với ma trận. Nhưng đừng quên truyền vào hai ma trận thay vì vectơ.
Những thứ này là cơ bản, đúng chứ?
Hãy đi xa hơn chút. Với phép nhân, còn có vài hàm khác bạn có thể cân nhắc, như np.vdot() cho tích vô hướng của vectơ, np.inner() hoặc np.outer() cho tích trong hoặc tích ngoài của mảng, np.tensordot() và np.kron() cho tích Kronecker của hai mảng:
Mẹo: thêm các lệnh in ra vào khối mã trên để xem kết quả từng phép nhân.
Ngoài ra, bạn có thể cân nhắc một số hàm của mô-đun linalg: các hàm mũ ma trận linalg.expm(), linalg.expm2() và linalg.expm3(). Khác biệt giữa ba hàm nằm ở cách tính mũ. Dùng hàm đầu cho mũ ma trận tổng quát, nhưng nhất định hãy thử cả ba để thấy khác biệt kết quả!
Các hàm lượng giác như linalg.cosm(), linalg.sinm() và linalg.tanm(), các hàm lượng giác siêu (hyperbolic) như linalg.coshm(), linalg.sinhm() và linalg.tanhm(), hàm dấu linalg.signm(), logarit ma trận linalg.logm(), và căn bậc hai ma trận linalg.sqrtm().
Thêm nữa, bạn cũng có thể đánh giá một hàm ma trận với linalg.funm(). Xem ví dụ sau:
Bạn thấy rằng bạn truyền vào ma trận muốn áp dụng hàm làm đối số đầu tiên và một hàm (trong ví dụ là lambda) muốn áp dụng cho ma trận đã truyền. Lưu ý hàm bạn truyền cho linalg.funm() phải được vector hóa.
Giờ hãy xem một số thủ tục ma trận cơ bản. Điều đầu tiên có lẽ bạn muốn kiểm tra là các thuộc tính ma trận: T cho chuyển vị, H cho chuyển vị liên hợp, I cho nghịch đảo, và A để ép sang mảng.
Hãy thử chúng:
Khi bạn chuyển vị một ma trận, bạn tạo một ma trận mới có các hàng là các cột của ma trận gốc. Chuyển vị liên hợp, ngược lại, hoán đổi chỉ số hàng và cột cho từng phần tử, kèm liên hợp phức. Nghịch đảo của một ma trận là ma trận mà khi nhân với ma trận gốc sẽ cho ma trận đơn vị.
Ngoài các thuộc tính đó, còn có các hàm thực để thực hiện một số thủ tục cơ bản, như np.transpose() và linalg.inv() cho chuyển vị và nghịch đảo ma trận, tương ứng.
Ngoài ra, bạn có thể lấy vết (trace) hay tổng các phần tử trên đường chéo chính bằng np.trace(). Tương tự, bạn cũng có thể lấy hạng ma trận hoặc số giá trị riêng (SVD) của một mảng lớn hơn một ngưỡng nhất định với linalg.matrix_rank của NumPy.
Đừng lo nếu hạng ma trận chưa rõ ràng lúc này; Bạn sẽ thấy thêm ở phần sau của hướng dẫn.
Hiện tại, tập trung vào hai thủ tục nữa bạn có thể dùng:
- Chuẩn (norm) của ma trận có thể tính bằng
linalg.norm: chuẩn là một số được định nghĩa theo các phần tử của ma trận. Chuẩn là một đại lượng hữu ích vì cho biết “độ lớn” của các phần tử. - Bạn cũng có thể tính định thức, một giá trị hữu ích có thể tính từ các phần tử của ma trận vuông, bằng
linalg.det(). Định thức quy gọn một ma trận vuông thành một số duy nhất, cho biết ma trận có khả nghịch hay không.
Cuối cùng, giải các hệ phương trình tuyến tính lớn là một trong những ứng dụng cơ bản của ma trận. Nếu bạn có hệ \(Ax = b\), với \(A\) là ma trận vuông và \(b\) là ma trận tổng quát, bạn có hai phương pháp có thể dùng để tìm \(x\), tùy thuộc loại ma trận bạn làm việc:
Để giải ma trận thưa, bạn có thể dùng linalg.spsolve(). Khi bạn không thể giải phương trình, vẫn có thể thu được \(x\) xấp xỉ với linalg.lstsq().
Mẹo: đừng bỏ lỡ SciPy cheat sheet của DataCamp.
Giờ khi bạn đã nắm cách tạo ma trận và dùng chúng cho các phép toán, đã đến lúc xử lý các chủ đề nâng cao hơn mà bạn cần để thực sự bước vào machine learning.
Eigenvalues and Eigenvectors
Chủ đề đầu tiên bạn sẽ xử lý là trị riêng và vectơ riêng.
Trị riêng là một cách mới để nhìn vào “trái tim” của ma trận. Nhưng trước khi đi sâu, hãy giải thích vectơ riêng là gì. Hầu hết các vectơ sẽ đổi hướng khi nhân với một ma trận. Tuy nhiên, có những vectơ đặc biệt mà kết quả nhân vẫn cùng hướng với vectơ ban đầu. Đó là các vectơ riêng.
Nói cách khác, nhân một vectơ riêng với ma trận, vectơ kết quả bằng vectơ riêng gốc nhân với \(\lambda\), trị riêng: \[Ax = \lambda x. \]
Điều này có nghĩa trị riêng cung cấp thông tin rất giá trị: nó cho bạn biết một vectơ riêng sẽ bị kéo giãn, co lại, đảo chiều hay giữ nguyên — khi nhân với một ma trận.
Bạn dùng hàm eig() từ mô-đun SciPy linalg để giải các bài toán trị riêng thường hoặc tổng quát cho ma trận vuông.
Lưu ý hàm eigvals() là cách khác để lấy các trị riêng của ma trận.
Khi làm việc với ma trận thưa, bạn có thể dựa vào mô-đun scipy.sparse để có các hàm phù hợp tìm trị riêng và vectơ riêng:
la, v = sparse.linalg.eigs(myMatrix,1)
Lưu ý đoạn mã trên chỉ định số lượng trị riêng và vectơ riêng cần lấy, cụ thể là 1.
Trị riêng và vectơ riêng là khái niệm quan trọng trong nhiều kỹ thuật thị giác máy tính và machine learning, như Phân tích Thành phần Chính (PCA) cho giảm chiều và EigenFaces cho nhận diện khuôn mặt.
Singular Value Decomposition (SVD)
Tiếp theo, bạn cần biết về SVD nếu muốn thực sự học khoa học dữ liệu. Phân rã giá trị riêng suy biến (SVD) của ma trận \(A\) là việc phân rã hay phân tích \(A\) thành tích của ba ma trận: \(A = U * \Sigma * V^t\).
Kích thước các ma trận riêng lẻ như sau nếu biết ma trận \(A\) có kích thước \(M\) x \(N\):
- Ma trận \(U\) có kích thước \(M\) x \(M\)
- Ma trận \(V\) có kích thước \(N\) x \(N\)
- Ma trận \(\Sigma\) có kích thước \(M\) x \(N\)
Ký hiệu \(*\) chỉ phép nhân ma trận và \(^t\) trong \(V^t\) nghĩa là chuyển vị, tức hoán đổi hàng và cột.
Nói đơn giản, SVD cung cấp cách “bẻ” một ma trận thành các phần nhỏ hơn có ý nghĩa. Những phần này có thể chứa dữ liệu ta quan tâm.
Lưu ý với ma trận thưa, bạn có thể dùng hàm sparse.linalg.svds() để phân rã.
Nếu bạn mới với khoa học dữ liệu, phân rã ma trận có thể khá mơ hồ: bạn có thể chưa thấy ngay các trường hợp áp dụng. Nhưng SVD hữu ích trong nhiều tác vụ như nén dữ liệu, khử nhiễu và phân tích dữ liệu. Sau đây, bạn sẽ thấy cách dùng SVD để nén ảnh:
# Import the necessary packagesimport numpy as npfrom scipy import linalgfrom skimage import dataimport matplotlib.pyplot as plt# Get an image from `skimage`img= data.camera()# Check number of singular valueslinalg.svdvals(img)# Singular Value DecompositionU, s, Vh = linalg.svd(img)# Use only 32 singular valuesA = np.dot(U[:,0:32], np.dot(np.diag(s[0:32]), Vh[0:32,:]))fig = plt.figure(figsize=(8, 3))# Add a subplot to the figureax = fig.add_subplot(121)# Plot `img` on grayscaleax.imshow(img, cmap='gray')# Add a second subplot to the figureax2 = fig.add_subplot(122)# Plot `A` in the second subplotax2.imshow(A)# Add a titlefig.suptitle('Image Compression with SVD', fontsize=14, fontweight='bold')# Show the plotplt.show()
Đoạn này sẽ cho kết quả sau:

Cũng xem các ví dụ sau nơi SVD được dùng:
- SVD liên hệ chặt với Phân tích Thành phần Chính (PCA), dùng để giảm chiều: cả hai cho ra một tập “trục mới” được xây dựng từ tổ hợp tuyến tính các trục không gian đặc trưng của dữ liệu. Các “trục mới” này phân rã phương sai của các điểm dữ liệu dựa trên mức đóng góp của mỗi hướng vào phương sai. Để xem ví dụ cụ thể PCA hoạt động thế nào, hãy xem Hướng dẫn Scikit-Learn của chúng tôi.
- Một liên hệ khác là với khai phá dữ liệu và xử lý ngôn ngữ tự nhiên (NLP): Lập chỉ mục ngữ nghĩa ẩn (LSI). Đây là kỹ thuật dùng trong truy xuất tài liệu và độ tương đồng từ. LSI dùng SVD để nhóm các tài liệu theo các khái niệm có thể gồm những từ khác nhau xuất hiện trong các tài liệu đó. Nhiều từ có thể nhóm thành một khái niệm. Ở đây, SVD cũng giảm bớt tương quan nhiễu giữa từ và tài liệu, và giảm số chiều của dữ liệu gốc.
Thấy không, SVD là khái niệm quan trọng trên hành trình khoa học dữ liệu của bạn mà bạn phải học. Vì vậy, bạn nên tìm hiểu sâu hơn SVD so với phạm vi hướng dẫn này: ví dụ, truy cập trang này để đọc thêm về phân rã ma trận.
What’s up Next?
Bạn đã đến cuối hướng dẫn! Tiếp theo bạn đi đâu là tùy bạn.
Nhưng khoan đã!
Đừng bỏ lỡ các khóa học đi sâu hơn vào đại số tuyến tính: hướng dẫn này chỉ là phần nhập môn và chưa bao quát mọi thứ!
Tất nhiên, cũng cân nhắc học hướng dẫn Machine Learning của DataCamp, chắc chắn sẽ bổ sung giá trị cho lộ trình học sau khi bạn hoàn thành hướng dẫn Scipy về đại số tuyến tính này. Còn nếu muốn quay lại căn bản, hãy xem hướng dẫn NumPy hoặc khóa Intermediate Python for Data Science.
