Bài hướng dẫn Học nhanh Python trong 30 phút này được dịch lại từ Python Numpy Tutorial thuộc khóa học lập trình python của đại học StanFord. Nếu bạn có khả năng đọc hiểu tiếng anh, tôi khuyên bạn nên đọc bài viết gốc để có cái nhìn sâu sắc nhất.
Chú ý: Trong bài viết còn nhiều keyword mình chưa biết phải dịch như nào(để nguyên tiếng anh) và một số mục có thể chưa sát nghĩa(để cả tiếng việt và tiếng anh). Mình rất cần các bạn giúp đỡ mình dịch các keyword này giúp mình. Các bạn hãy comment cách dịch tại mục bình luận giúp mình ạ. Rất cảm ơn các bạn!
Giới thiệu về khóa học lập trình python
khóa học lập trình python này được viết dành cho các bạn sử dụng python cho các bài toán machine learning. Do đó, ngoài hướng dẫn về học lập trình python ra bạn sẽ học được các kỹ thuật, cách sử dụng một số thư viện phục vụ cho khoa học máy tính.
Nếu bạn chỉ đơn giản muốn học lập trình python, bạn vẫn có thể tham khảo phần hướng dẫn về ngôn ngữ python của khóa học lập trình python này để hiểu tổng quan. Ngược lại, nếu bạn là người mới học lập trình và muốn học chi tiết cụ thể nhất về ngôn ngữ python, tôi khuyên bạn nên xem qua khóa học này sẽ phù hợp hơn.
Python là một ngôn ngữ lập trình tuyệt vời có thể sử dụng trong nhiều lĩnh vực và nhiều bài toán khác nhau. Với sự trợ giúp đắc lực của nhiều thư viện như numpy, scipy, matplotlib,… Nó trở thành một môi trường lý tưởng và mạnh mẽ của khoa học máy tính.
Chúng tôi vẫn hi vọng rằng các bạn đã có một số kinh nghiệm làm việc với python và numpy. Tuy nhiên, nếu bạn chưa có nhiều kinh nghiệm thì cũng không cần quá lo lắng. Khóa học lập trình python này sẽ cung cấp cho bạn một khóa học nhanh về ngôn ngữ lập trình python và sử dụng python trong trong khoa học máy tính.
Toàn bộ source code của khóa học lập trình python này cũng sẽ có ở bản jupyter notebook tại đây.
Trong quá trình học, tôi mong muốn các bạn tự gõ các ví dụ và tự mình kiểm chứng kết quả. Điều này sẽ giúp bạn học tốt hơn rất nhiều.
Python là gì?
Python là một ngôn ngữ lập trình bậc cao, python hoàn toàn tạo kiểu động và dùng cơ chế cấp phát bộ nhớ tự động. Đây là ngôn ngữ có hình thức rất sáng sủa, cấu trúc rõ ràng, thuận tiện cho người mới học lập trình. Cấu trúc của Python còn cho phép người sử dụng viết mã lệnh với số lần gõ phím tối thiểu. Đây là một ví dụ triển khai thuật toán tìm kiếm nhanh – quick sort sử dụng python:
def quicksort(arr): if len(arr) <= 1: return arr pivot = arr[len(arr) // 2] left = [x for x in arr if x < pivot] middle = [x for x in arr if x == pivot] right = [x for x in arr if x > pivot] return quicksort(left) + middle + quicksort(right) print(quicksort([3,6,8,10,1,2,1])) # Prints "[1, 1, 2, 3, 6, 8, 10]"
Các phiên bản Python
Hiện nay, có 2 phiên bản python khác nhau đó là python 2 và python 3. Hai phiên bản này có một chút khác nhau về cú pháp. Bạn không thể dùng python 2 để chạy code của phiên bản python 3 và ngược lại. Một lưu ý nữa là hiện nay python 2 đã bị khai tử nên chúng tôi khuyến khích bạn sử dụng python 3. Để thuận lợi cho việc học khóa học nhanh python này, chúng tôi đề nghị bạn sử dụng python phiên bản 3.5 trở lên.
Bạn có thể kiểm tra phiên bản python hiện tại của bạn bằng cách chạy lệnh python -V hoặc python –version trên cửa sổ command line.
Các kiểu dữ liệu cơ bản trong Python
Cũng giống như hầu hết các ngôn ngữ lập trình khác, python cũng có các kiểu dữ liệu cơ bản bao gồm: integers, floats, booleans, và strings. Nhưng những kiểu dữ liệu này có cách sử dụng đơn giản và giảm bớt các ràng buộc so với các ngôn ngữ khác.
Kiểu dữ liệu số: Kiểu dữ liệu số nguyên và số thực trong python đơn giản hơn so với các ngôn ngữ khác. Một biến có kiểu là int hay float sẽ tự được xác định thông qua giá trị mà bạn gán cho biến.
x = 3 print(type(x)) # In ra "<class 'int'>" print(x) # In ra "3" print(x + 1) # Phép cộng; in ra "4" print(x - 1) # Phép trừ; in ra "2" print(x * 2) # Phép nhân; in ra "6" print(x ** 2) # Phép lũy thừa; in ra "9" x += 1 print(x) # In ra "4" x *= 2 print(x) # In ra "8" y = 2.5 print(type(y)) # In ra "<class 'float'>" print(y, y + 1, y * 2, y ** 2) # In ra "2.5 3.5 5.0 6.25"
Chú ý rằng python không có toán tử tăng 1 đơn vị(x++
) hay giảm đi 1 đơn vị(x--
) giống như hầu hết các ngôn ngữ khác.
Python cũng có sẵn kiểu dữ liệu cho số phức, bạn có thể xem mọi thông tin chi tiết về nó trong trong tài liệu này.
Booleans: Python cũng hỗ trợ tất cả các toán tử logic như các ngôn ngữ khác. Nhưng sẽ dùng chữ cái tiếng anh thay vì sử dụng các ký tự(&&, ||, ...
)
t = True f = False print(type(t)) # In ra"<class 'bool'>" print(t and f) # Phép toán logic AND; in ra "False" print(t or f) # Phép toán logic OR; in ra "True" print(not t) # Phép toán logic NOT; in ra "False" print(t != f) # Phép toán logic XOR; in ra "True"
Strings: Python hỗ trợ rất mạnh cho kiểu dữ liệu string:
hello = 'hello' # Khai báo chuỗi string có thể sử dụng dấu nháy đơn world = "world" # hoặc dấu nháy kép; Nó không ảnh hưởng gì cả. print(hello) # In ra "hello" print(len(hello)) # Lấy chiều dài của string; in ra "5" hw = hello + ' ' + world # Nối chuỗi print(hw) # in ra "hello world" hw12 = '%s %s %d' % (hello, world, 12) # Sử dụng format style của string print(hw12) # in ra "hello world 12"
Đối tượng kiểu string cũng có rất nhiều hàm hữu ích, ví dụ như:
s = "hello" print(s.capitalize()) # Chuyển thành chuỗi viết hoa chữ cái đầu; in ra "Hello" print(s.upper()) # Chuyển toàn bộ chuỗi thành viết hoa; in ra "HELLO" print(s.rjust(7)) # Căn phải một chuỗi string, bổ sung bằng khoảng trắng; in ra " hello" print(s.center(7)) # Căn giữa một chuỗi string, bổ sung bằng khoảng trắng; in ra " hello " print(s.replace('l', '(ell)')) # Thay thế mọi chuỗi con xuất hiện trong string bằng chuỗi khác; # in ra "he(ell)(ell)o" print(' world '.strip()) # Loại bỏ dấu cách thừa ở đầu/ cuối string; in ra "world"
Bạn có thể tìm danh sách tất cả các hàm của string tại tài liệu này.
Containers
Python đã được xây dựng sẵn một số loại containers: lists, dictionaries, sets, và tuples.
Lists
Lists trong python đóng vai trò tương tự như mảng(arrays). Nhưng lists có khả năng tự động thay đổi kích thước và các phần tử trong 1 list có thể có kiểu dữ liệu khác nhau.
xs = [3, 1, 2] # Khởi tạo 1 list print(xs, xs[2]) # In ra "[3, 1, 2] 2" print(xs[-1]) # Chỉ số âm có thể được dùng là bắt đầu từ cuối list; in ra "2" xs[2] = 'foo' # Lists có thể chứa các phần tử có kiểu dữ liệu khác nhau print(xs) # In ra "[3, 1, 'foo']" xs.append('bar') # Thêm một phần tử vào cuối list print(xs) # In ra "[3, 1, 'foo', 'bar']" x = xs.pop() # Xóa và trả về phần tử ở cuối list print(x, xs) # In ra "bar [3, 1, 'foo']"
Trượt trên list: Để có thể truy cập tới nhiều phần tử liên tiếp trên list. Python cung cấp cơ chế trượt(slice) cho phép truy cập vào sublist của một list dễ dàng và nó được gọi là slicing
:
nums = list(range(5)) # range là một built-in function giúp bạn tạo một list các số nguyên print(nums) # In ra "[0, 1, 2, 3, 4]" print(nums[2:4]) # Trượt từ chỉ số 2 đến 4(không bao gồm 4); in ra "[2, 3]" print(nums[2:]) # Trượt từ chỉ số 2 tới cuối cùng; in ra "[2, 3, 4]" print(nums[:2]) # Trượt từ đầu tới chỉ số 2 (không bao gồm 2); in ra "[0, 1]" print(nums[:]) # Trượt qua toàn bộ list ; in ra "[0, 1, 2, 3, 4]" print(nums[:-1]) # Chỉ số của slice(trượt) cũng có thể là số âm; in ra "[0, 1, 2, 3]" nums[2:4] = [8, 9] # Gán các giá trị của sublist sử dụng slice print(nums) # In ra "[0, 1, 8, 9, 4]"
Lưu ý thêm: Chỉ số âm giống như chỉ số dương nhưng là từ cuối list. Giả sử list a
có n
phần tử. Thì a[-1] = a[n-1]
, a[-2] = a[n-2]
, a[:n-1] = a[:-1]
.
Chúng ta sẽ tiếp tục nhắc tới slice trong phần học về numpy.
Lặp: Bạn có thể lặp qua tất cả các phần tử của 1 list như sau:
animals = ['cat', 'dog', 'monkey'] for animal in animals: print(animal) # Output: # Chương trình sẽ in ra: "cat", "dog", "monkey". Mỗi phần tử trên 1 dòng.
Nếu bạn muốn lấy cả chỉ số để dùng ở bên trong vòng lặp, hãy sử dụng build-in function enumerate
và làm như sau:
animals = ['cat', 'dog', 'monkey'] for idx, animal in enumerate(animals): print('#%d: %s' % (idx + 1, animal)) # Chương trình sẽ in ra "#1: cat", "#2: dog", "#3: monkey", mỗi phần tử trên một dòng
List comprehensions: Trong nhiều tình huống, bạn có thể sẽ cần sử dụng một list để chuyển đổi sang một list tương đương sử dụng một công thức nào đó. Để dễ hiểu hơn, chúng ta hãy xem xét ví dụ tính toán bình phương của từng phần tử trong list các số nguyên sau:
nums = [0, 1, 2, 3, 4] squares = [] for x in nums: squares.append(x ** 2) print(squares) # In ra [0, 1, 4, 9, 16]
Bạn có thể làm công việc trên đơn giản hơn rất nhiều với list comprehensions:
nums = [0, 1, 2, 3, 4] squares = [x ** 2 for x in nums] print(squares) # In ra [0, 1, 4, 9, 16]
List comprehensions cũng có thể kết hợp thêm với điều kiện:
nums = [0, 1, 2, 3, 4] even_squares = [x ** 2 for x in nums if x % 2 == 0] print(even_squares) # In ra "[0, 4, 16]"
Dictionaries
Một dictionaries chứa các cặp (key,value), nó tương tự với map trong Java và C++. Bạn có thể sử dụng như sau:
d = {'cat': 'cute', 'dog': 'furry'} # Khởi tạo 1 dict print(d['cat']) # Lấy giá trị của dict có key là 'cat'; In ra "cute" print('cat' in d) # Kiểm tra key có trong dict hay không; In ra "True" d['fish'] = 'wet' # Set giá trị cho 1 key. Nếu key chưa có thì thêm, # nếu có rồi thì ghi đè giá trị print(d['fish']) # In ra "wet" # print(d['monkey']) # KeyError: 'monkey' not a key of d print(d.get('monkey', 'N/A')) # Lấy giá trị theo key kèm theo default value; In ra "N/A" print(d.get('fish', 'N/A')) # Lấy giá trị theo key kèm theo default value; In ra "wet" del d['fish'] # Xóa 1 phần tử khỏi dict print(d.get('fish', 'N/A')) # "fish" không còn ở trong dict; In ra "N/A"
Bạn có thể tìm tất cả những gì bạn cần biết về dictionaries tại tài liệu này.
Lặp: Bạn có thể lặp qua từng key của dictionary như sau:
d = {'person': 2, 'cat': 4, 'spider': 8} for animal in d: legs = d[animal] print('A %s has %d legs' % (animal, legs)) # Prints "A person has 2 legs", "A cat has 4 legs", "A spider has 8 legs"
Nếu bạn muốn cả key và value trong khi lặp, sử dụng hàm items
:
d = {'person': 2, 'cat': 4, 'spider': 8} for animal, legs in d.items(): print('A %s has %d legs' % (animal, legs)) # Prints "A person has 2 legs", "A cat has 4 legs", "A spider has 8 legs"
Dictionary comprehensions: Cái này tương tự như list comprehensions, nhưng thêm nữa là bạn có thể dễ dàng xây dựng từ điển mới. Ví dụ:
nums = [0, 1, 2, 3, 4] even_num_to_square = {x: x ** 2 for x in nums if x % 2 == 0} print(even_num_to_square) # Prints "{0: 0, 2: 4, 4: 16}"
Sets
Set là một tập hợp các phần tử không có thứ tự và các phần tử không trùng lặp(distinct). Hãy xem một ví dụ đơn giản sau đây:
animals = {'cat', 'dog'} print('cat' in animals) # Kiểm tra 1 phần tử có trong set hay không; prints "True" print('fish' in animals) # prints "False" animals.add('fish') # Thêm phần tử vào set print('fish' in animals) # Prints "True" print(len(animals)) # Số phần tử có trong set; prints "3" animals.add('cat') # Thêm phần tử đã có trong set => không làm gì hết print(len(animals)) # Prints "3" animals.remove('cat') # Xóa phần tử khỏi set print(len(animals)) # Prints "2"
Như thường lệ, mọi thứ bạn cần về set có thể xem tại đây.
Lặp: Việc lặp qua từng phần tử trong một set có cú pháp giống như với list. Tuy nhiên, vì set chứa các phần tử không có thứ tự. Nên bạn không thể biết trước thứ tự in ra của các phần tử:
animals = {'cat', 'dog', 'fish'} for idx, animal in enumerate(animals): print('#%d: %s' % (idx + 1, animal)) # Prints "#1: fish", "#2: dog", "#3: cat"
Set comprehensions: Giống như list và dictionaries, chúng ta có thể dễ dàng xây dựng sets sử dụng set comprehensions:
from math import sqrt nums = {int(sqrt(x)) for x in range(30)} print(nums) # Prints "{0, 1, 2, 3, 4, 5}"
Tuples
Tuple là một kiểu dữ liệu bất biến chứa một danh sách các phần tử có thứ tự. Một tuple trong nhiều trường hợp sẽ tương tự với 1 list. Có một sự khác biệt quan trọng nhất đó là tuple có thể sử dụng giống như key trong dictionaries và có thể như các phần tử trong sets, còn list thì không thể. Đây là ví dụ:
d = {(x, x + 1): x for x in range(10)} # Tạo một dict với keys là tuple t = (5, 6) # Tạo 1 tuple print(type(t)) # Prints "<class 'tuple'>" print(d[t]) # Prints "5" print(d[(1, 2)]) # Prints "1"
Tài liệu này sẽ cho bạn thêm thông tin về tuples.
Functions
Hàm trong python được định nghĩa sử dụng keyword def
. Ví dụ:
def sign(x): if x > 0: return 'positive' elif x < 0: return 'negative' else: return 'zero' for x in [-1, 0, 1]: print(sign(x)) # Prints "negative", "zero", "positive"
Chúng ta cũng thường định nghĩa một hàm có các optional tham số(có thể truyền giá trị cho tham số đó hoặc không truyền). Nếu không truyền thì hàm dùng giá trị mặc định. Ví dụ:
def hello(name, loud=False): if loud: print('HELLO, %s!' % name.upper()) else: print('Hello, %s' % name) hello('Bob') # Prints "Hello, Bob" hello('Fred', loud=True) # Prints "HELLO, FRED!"
Có rất nhiều thông tin hữu ích về hàm trong python ở đây
Classes
Cú pháp để định nghĩa một class trong python vô cùng đơn giản:
class Greeter(object): # Constructor def __init__(self, name): self.name = name # Create an instance variable # Instance method def greet(self, loud=False): if loud: print('HELLO, %s!' % self.name.upper()) else: print('Hello, %s' % self.name) g = Greeter('Fred') # Construct an instance of the Greeter class g.greet() # Call an instance method; prints "Hello, Fred" g.greet(loud=True) # Call an instance method; prints "HELLO, FRED!"
Có rất nhiều điều thú vị về class trong python ở đây nè.
Nếu bạn chỉ muốn học python cơ bản, nội dung về python trong khóa học nhanh python này sẽ tạm dừng ở đây. Tại phần tiếp theo, Nguyễn Văn Hiếu Blog sẽ tiếp tục trình bày về các thư viện phổ biến hay được sử dụng trong lập trình python. Nếu bạn có hứng thú, hãy tiếp tục theo dõi khóa học nhanh lập trình python này.
Numpy
Phần tiếp theo trong khóa học nhanh python này sẽ trình bày về thư viện toán học numpy. Đây là một thư viện hỗ trợ đắc lực cho tính toán ma trận. Để biết cụ thể numpy là cái gì chúng ta hãy cũng nhau tìm hiểu nhé.
Numpy là một thư viện lõi phục vụ cho khoa học máy tính của Python. Nó hỗ trợ mạnh mẽ cho các array nhiều chiều, và các phương thức để làm việc với các mảng nhiều chiều này. Nếu bạn đã có kinh nghiệm sử dụng MATLAB, có thể tutorial này sẽ hữu ích để bạn bắt đầu với Numpy.
Arrays
Một numpy array là một mạng lưới các giá trị, và tất cả các giá trị phải có cùng kiểu dữ liệu. Chỉ số của numpy array được biểu diễn bằng các số nguyên không âm. Số chiều thì(1-D array -> vector, 2-D array – ma trận, …) được gọi là rank
của numpy array. Và shape
của array là một tuple các số nguyên thể hiện cho kích thước của array theo mỗi chiều của aray.
Chúng ta có thể khởi tạo numpy array từ một container list trong python. Numpy array vẫn dùng cặp ngoặc vuông để truy cập tới từng phần tử.
import numpy as np a = np.array([1, 2, 3]) # Tạo 1 numpy array rank = 1 print(type(a)) # Prints "<class 'numpy.ndarray'>" print(a.shape) # Prints "(3,)" print(a[0], a[1], a[2]) # Prints "1 2 3" a[0] = 5 # Thay đổi giá trị của 1 phần tử print(a) # Prints "[5, 2, 3]" b = np.array([[1,2,3],[4,5,6]]) # Tạo 1 numpy array rank = 2 print(b.shape) # Prints "(2, 3)" print(b[0, 0], b[0, 1], b[1, 0]) # Prints "1 2 4"
Numpy cũng có sẵn rất nhiều hàm hỗ trợ tạo numpy array:
import numpy as np a = np.zeros((2,2)) # Tạo numpy array mà tất cả phần tử là 0 print(a) # Prints "[[ 0. 0.] # [ 0. 0.]]" b = np.ones((1,2)) # Tạo numpy array mà tất cả phần tử là 1 print(b) # Prints "[[ 1. 1.]]" c = np.full((2,2), 7) # Tạo một mảng hằng print(c) # Prints "[[ 7. 7.] # [ 7. 7.]]" d = np.eye(2) # Tạo ma trận đơn vị 2 x 2 print(d) # Prints "[[ 1. 0.] # [ 0. 1.]]" e = np.random.random((2,2)) # Tạo array với các giá trị ngẫu nhiên print(e) # Might print "[[ 0.91940167 0.08143941] # [ 0.68744134 0.87236687]]"
Bạn có thể xem các phương pháp khởi tạo numpy array tại đây.
Truy xuất mảng(Array indexing)
Numpy cung cấp một số cách khác nhau để truy xuất vào các phần tử trong mảng(numpy array).
Trượt(Slicing): Tương tự như list trong Python, numpy array cũng có thể trượt trên mảng. Trong trường hợp mảng nhiều chiều, bạn phải chỉ định việc trượt trên tất cả các chiều của mảng:
import numpy as np # Khởi tạo numpy array có shape = (3, 4) có giá trị như sau: # [[ 1 2 3 4] # [ 5 6 7 8] # [ 9 10 11 12]] a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]]) # Sử dụng slicing để tạo numpy array b bằng cách lấy 2 hàng đầu tiên # và cột 1, 2. Như vậy b sẽ có shape = (2, 2): # [[2 3] # [6 7]] b = a[:2, 1:3] # Một array tạo ra từ slicing sẽ có cùng địa chỉ với array gốc. # Nếu thay đổi 1 trong 2 thì array còn lại cũng thay đổi. print(a[0, 1]) # Prints "2" b[0, 0] = 77 # b[0, 0] ở đây tương đương với a[0, 1] print(a[0, 1]) # Prints "77"
Bạn cũng có thể kết hợp việc dùng slicing và dùng chỉ số. Tuy nhiên, cách làm đó sẽ cho ra một mảng mới có rank thấp hơn mảng gốc. Chú ý rằng nó sẽ khác việc slicing trong matlab:
import numpy as np # Tạo một numpy array có shape (3, 4) với giá trị như sau: # [[ 1 2 3 4] # [ 5 6 7 8] # [ 9 10 11 12]] a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]]) # Dùng 2 cách khác nhau để tạo array mới từ array gốc # Dùng kết hợp chỉ số và slice -> được array mới có rank thấp hơn, # Nếu chỉ dùng slice ta sẽ có 1 array mới có cùng rank # với array gốc row_r1 = a[1, :] # Rank 1, hàng thứ 2 của a row_r2 = a[1:2, :] # Rank 2, vẫn là hàng thứ 2 của a print(row_r1, row_r1.shape) # Prints "[5 6 7 8] (4,)" print(row_r2, row_r2.shape) # Prints "[[5 6 7 8]] (1, 4)" # Chúng ta có thể làm tương tự với cột của numpy array: col_r1 = a[:, 1] col_r2 = a[:, 1:2] print(col_r1, col_r1.shape) # Prints "[ 2 6 10] (3,)" print(col_r2, col_r2.shape) # Prints "[[ 2] # [ 6] # [10]] (3, 1)"
import numpy as np a = np.array([[1,2], [3, 4], [5, 6]]) # Truy xuất mảng dùng chỉ số. # Kết quả thu được là 1 mảng có shape (3,) print(a[[0, 1, 2], [0, 1, 0]]) # Prints "[1 4 5]" # Sẽ thu được kết quả tương đương như trên với cách này: print(np.array([a[0, 0], a[1, 1], a[2, 0]])) # Prints "[1 4 5]" # Bạn được phép sử dụng chỉ số mảng để # truy xuất tới 1 phần tử # của mảng gốc nhiều hơn 1 lần print(a[[0, 0], [1, 1]]) # Prints "[2 2]" # Một cách làm khác tương đương: print(np.array([a[0, 1], a[0, 1]])) # Prints "[2 2]"
Có một mẹo khá là hay bạn có thể dùng chỉ số mảng để chọn hoặc thay đổi giá trị từng phần tử trong từng hàng của mảng:
import numpy as np # Tạo 1 mảng numpy array a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]]) print(a) # prints "array([[ 1, 2, 3], # [ 4, 5, 6], # [ 7, 8, 9], # [10, 11, 12]])" # Tạo một mảng lưu giữ chỉ số b = np.array([0, 2, 0, 1]) # Lấy một phần tử từ mỗi hàng của a sử dụng các chỉ số đã lưu ở b print(a[np.arange(4), b]) # Prints "[ 1 6 7 11]" # Thay đổi một phần tử từ mỗi hàng của a sử dụng các chỉ số đã lưu ở b a[np.arange(4), b] += 10 print(a) # prints "array([[11, 2, 3], # [ 4, 5, 16], # [17, 8, 9], # [10, 21, 12]])
Boolean array indexing: Boolean array indexing cho phép bạn chọn ra các phần tử mà bạn mong muốn. Cách này thường sử dụng để chọn các phần tử thỏa mãn một điều kiện nào đó. Đây là một ví dụ:
import numpy as np a = np.array([[1,2], [3, 4], [5, 6]]) bool_idx = (a > 2) # Tìm tất cả các phần tử có giá trị > 2; # Trả về một boolean numpy array có cùng kích thước # mà giá trị tại mỗi phần tử là True nếu phần tử # của a tại đó > 2, và False cho TH ngược lại print(bool_idx) # Prints "[[False False] # [ True True] # [ True True]]" # Sử dụng một boolean array indexing để lấy # các phần tử thỏa mãn điều kiện nhất định trong a # Ví dụ ở đây in ra các giá trị của a > 2 # sử dụng array bool_idx đã tạo print(a[bool_idx]) # Prints "[3 4 5 6]" # Một cách viết ngắn gọn hơn cho cùng kết quả: print(a[a > 2]) # Prints "[3 4 5 6]"
Nếu bạn muốn tìm kiếm thêm thông tin về numpy array indexing thì hãy tham khảo bài viết này.
Kiểu dữ liệu
Tất cả các phần tử trong một numpy array phải có cùng kiểu dữ liệu. Numpy cung cấp một số lượng lớn các kiểu dữ liệu số mà bạn có thể sử dụng để xây dựng các mảng. Numpy sẽ cố gắng đoán kiểu dữ liệu khi bạn khởi tạo, nhưng các hàm khởi tạo numpy array cũng có một tham số tùy chọn để bạn chỉ định kiểu dữ liệu cụ thể mà bạn muốn. Ví dụ:
import numpy as np x = np.array([1, 2]) # numpy tự xác định kiểu dữ liệu print(x.dtype) # Prints "int64" x = np.array([1.0, 2.0]) # numpy tự xác định kiểu dữ liệu print(x.dtype) # Prints "float64" x = np.array([1, 2], dtype=np.int64) # Chỉ định kiểu dữ liệu bởi người dùng print(x.dtype) # Prints "int64"
Bạn có thể xem thêm chi tiết về các kiểu dữ liệu của numpy tại tài liệu này.
Phép toán trên numpy array
Các phép toán cơ bản trên numpy array được thực thi theo kiểu “từng phần tử của mảng này kết hợp với phần tử ở vị trí tương ứng của mảng kia” với các phép +, -, *, /. Xem ví dụ sau:
import numpy as np
x = np.array([[1,2],[3,4]], dtype=np.float64)
y = np.array([[5,6],[7,8]], dtype=np.float64)
# Cộng từng phần tử của x với từng phần tử của y với nhau. Cả 2 cách cho cùng một kết quả
# x[0][0] + y[0][0], x[0][1] + y[0][1], ...
# [[ 6.0 8.0]
# [10.0 12.0]]
print(x + y)
print(np.add(x, y))
# Tính hiệu từng phần tử của x với trừ cho từng phần tử của y. Cả 2 cách cho cùng một kết quả
# [[-4.0 -4.0]
# [-4.0 -4.0]]
print(x - y)
print(np.subtract(x, y))
# Tính tích từng phần tử của a nhân với từng phần tử của b.
# Cả 2 cách cho cùng 1 kết quả
# Lưu ý: Đây không phải là phép nhân hai ma trận trong toán học
# [[ 5.0 12.0]
# [21.0 32.0]]
print(x * y)
print(np.multiply(x, y))
# Thực hiện tính thương của từng phần tử trong x chia cho phần tử tương ứng trong y
# Cả 2 cách cho cùng 1 kết quả
# [[ 0.2 0.33333333]
# [ 0.42857143 0.5 ]]
print(x / y)
print(np.divide(x, y))
# Bình phương từng phần tử trong x
# [[ 1. 1.41421356]
# [ 1.73205081 2. ]]
print(np.sqrt(x))
Chú ý: Không giống như matlab, toán tử *
của numpy là phép nhân tích chập(từng phần tử nhân với nhau cho ra kết quả). Còn toán tử *
trong matlab là phép nhân 2 ma trận. Để nhân 2 ma trận hoặc nhân vector với ma trận trong numpy, chúng ta sử dụng hàm dot
:
# Ví dụ về dot function
import numpy as np
x = np.array([[1,2],[3,4]])
y = np.array([[5,6],[7,8]])
v = np.array([9,10])
w = np.array([11, 12])
# Tính tích trong của(inner product) 2 vector.
# Cả 2 đều in ra 219
print(v.dot(w))
print(np.dot(v, w))
# Nhân ma trận với vector. Cả 2 in ra array rank = 1: [29 67]
print(x.dot(v))
print(np.dot(x, v))
# Phép nhân trên 2 ma trận; Kết quả là một ma trận có rank = 2
# [[19 22]
# [43 50]]
print(x.dot(y))
print(np.dot(x, y))
Numpy cung cấp rất nhiều hàm hỗ trợ tính toán trên mảng. Một hàm ví dụ mà ta hay sử dụng là sum
:
# sum function
import numpy as np
x = np.array([[1,2],[3,4]])
print(np.sum(x)) # Tính tổng tất cả các phần tử; prints "10"
print(np.sum(x, axis=0)) # Tính tổng theo từng cột; prints "[4 6]"
print(np.sum(x, axis=1)) # Tính tổng theo từng hàng; prints "[3 7]"
Bạn có thể xem đầy đủ các hàm tính toán toán học của numpy tại đây.
Trong quá trình làm việc với mảng, chúng ta thường xuyên phải thay đổi kích thước của mảng. Ví dụ đơn giản nhất của trường hợp này là phép chuyển vị ma trận. Để lấy chuyển vị của một ma trận, chúng ta sử dụng thuộc tính T
của đối tượng mảng:
# Chuyển vị ma trận
import numpy as np
x = np.array([[1,2], [3,4]])
print(x) # Prints "[[1 2]
# [3 4]]"
print(x.T) # Prints "[[1 3]
# [2 4]]"
# Chuyển vị của vector là một vector không đổi:
v = np.array([1,2,3])
print(v) # Prints "[1 2 3]"
print(v.T) # Prints "[1 2 3]"
Numpy cung cấp rất nhiều hàm cho phép thao tác với mảng, bạn có thể xem danh sách đầy đủ tại đây.
Broadcasting
Broadcasting là một cơ chế mạnh mẽ cho phép bạn thực thi nhanh chóng với các phép toán số học trên các numpy array có kích thước khác nhau. Giả sử bạn có một mảng có kích thước nhỏ và mảng kia có kích thước lớn. Bạn muốn dùng mảng nhỏ kia nhiều lần để thay đổi giá trị của mảng lớn.
Ví dụ, chúng ta muốn cộng thêm một vector hằng vào từng hàng của một ma trận. Bạn có thể làm như sau:
import numpy as np
# Cộng thêm giá trị vector v vào từng hàng của x,
# chứa kết quả vào ma trận y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = np.empty_like(x) # Tạo một ma trận rỗng có kích thước như x
# Thêm vector v vào từng hàng của ma trận x sử dụng vòng lặp
for i in range(4):
y[i, :] = x[i, :] + v
# Và đây là y nhận được
# [[ 2 2 4]
# [ 5 5 7]
# [ 8 8 10]
# [11 11 13]]
print(y)
Cách này hoạt động khá tốt, nhưng khi ma trận x
là rất lớn thì việc lặp này sẽ rất chậm. Nếu bạn để ý thì công việc này tương tự việc thực hiện cộng từng phần tử của x
với một ma trận vv
có kích thước như y
và mỗi hàng là một vector v
. Bạn có thể xem code để hiểu rõ hơn:
import numpy as np
# Cộng thêm giá trị vector v vào từng hàng của x,
# chứa kết quả vào ma trận y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
vv = np.tile(v, (4, 1)) # Copy thành xếp chồng chứa 4 vector v
print(vv) # Prints "[[1 0 1]
# [1 0 1]
# [1 0 1]
# [1 0 1]]"
y = x + vv # Thực hiện phép cộng
print(y) # Prints "[[ 2 2 4
# [ 5 5 7]
# [ 8 8 10]
# [11 11 13]]"
Numpy broadcasting cho phép chúng ta thực thi tính toán này mà không cần phải tạo ra nhiều bản sao của v
. Và đây là code khi sử dụng broadcasting:
# Broadcasting
import numpy as np
# Cộng thêm giá trị vector v vào từng hàng của x,
# chứa kết quả vào ma trận y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = x + v # Thêm v vào từng hàng của x sử dụng broadcasting
print(y) # Prints "[[ 2 2 4]
# [ 5 5 7]
# [ 8 8 10]
# [11 11 13]]"
Bằng cách dùng Broadcasting, dòng code y = x + v
vẫn làm việc thậm chí x
có kích thước (4, 3)
và v
có kích thước (3,)
.
Nguyên tắc
Broadcast thực thi trên 2 mảng theo quy tắc sau:
- Nếu các mảng không có cùng rank, tăng kích thước của mảng có rank thấp hơn cho tới khi cả 2 có cùng kích thước.
- Hai mảng được cho là tương thích trong một chiều nếu chúng có cùng kích thước trong chiều đó hoặc nếu một trong 2 mảng có kích là 1 trong chiều đó.
- Các mảng có thể thực hiện broadcast nếu chúng tương thích trên tất cả các chiều.
- Kết quả sau khi thực thi broadcast sẽ là một ma trận có kích thước bằng với kích thước của ma trận lớn hơn.
- Trong bất kỳ chiều nào mà mảng đầu có kích thước là 1 và mảng còn lại có kích thước lớn hơn 1, mảng đầu đó sẽ coi như là copy các giá trị của nó(ở chiều đó) theo chiều đó.
Nếu đoạn giải thích này chưa khiến bạn hiểu rõ ràng, hãy đọc giải thích ở tài liệu này hoặc bài giải thích này.
Các hàm thực thi broadcasting được gọi là universal functions. Bạn có thể tìm danh sách các hàm đó trong tài liệu này.
Một vài trường hợp sử dụng broadcasting khác:
import numpy as np
# Tính tích ngoài(outer product) của 2 vector
v = np.array([1,2,3]) # v has shape (3,)
w = np.array([4,5]) # w has shape (2,)
# Để tính tích ngoài(outer product), đầu tiên cần reshape v về shape (3, 1);
# Sau đó broadcast nó với w được 1 output có shape (3, 2),
# Đây là kết quả:
# [[ 4 5]
# [ 8 10]
# [12 15]]
print(np.reshape(v, (3, 1)) * w)
# Thêm một vector vào từng hàng của ma trận
x = np.array([[1,2,3], [4,5,6]])
# x có shape (2, 3) và v có shape (3,) vì vậy kết quả có shape (2, 3),
# có giá trị như sau:
# [[2 4 6]
# [5 7 9]]
print(x + v)
# Thêm một vector vào từng cột của ma trận
# x có shape (2, 3) và w có shape (2,).
# Nếu ta chuyển vị x thì shape x là (3, 2) và có thể broadcast
# với w cho ra kết quả có shape (3, 2); thực hiện chuyển vị kết quả này thu được
# ma trận shape (2, 3) là kết quả của x thêm v ở mỗi cột.
# Cho ta kết quả như sau:
# [[ 5 6 7]
# [ 9 10 11]]
print((x.T + w).T)
# Một cách khác là reshape w thành vector cột (2, 1);
# Sau đó ta có thể broadcast nó trực tiếp với x
# để cho ra cùng kết quả
print(x + np.reshape(w, (2, 1)))
# Nhân ma trận với hằng số:
# x có shape (2, 3). Numpy chỉ định hằng số có shape là ();
# Nó có thể broadcast với x có shape (2, 3), cho ra kết quả như sau:
# [[ 2 4 6]
# [ 8 10 12]]
print(x * 2)
Broadcasting giúp cho code của bạn trở nên ngắn gọn hơn và thực thi nhanh hơn. Vì vậy, bạn hãy cố gắng sử dụng nó khi có thể.
Tài liệu về Numpy
Những kiến thức trên đây của khóa học lập trình python đã cung cấp cho bạn rất nhiều hiểu biết cần thiết về numpy. Nhưng đó chưa phải tất cả, hãy đọc tài liệu này để có nhiều hơn kiến thức về numpy.
Phần tiếp theo trong khóa học lập trình python sẽ là bài hướng dẫn về thư viện Scipy. Hãy cùng Nguyễn Văn Hiếu tiếp tục tìm hiểu nhé.
SciPy
Scipy trong xử lý ảnh (Image operations)
Scipy cung cấp một số hàm cơ bản để làm việc với ảnh. Ví dụ, nó có các hàm để đọc ảnh từ ổ cứng thành 1 numpy arrays, lưu numpy arrays thành file ảnh trong ổ cứng, thay đổi kích thước của ảnh. Đây là một ví dụ đơn giản chứng minh cho điều đó:
from scipy.misc import imread, imsave, imresize
# Đọc 1 ảnh JPEG vào 1 numpy arrays
img = imread('../assets/cat.jpg')
print(img.dtype, img.shape) # Prints "uint8 (400, 248, 3)"
# Chúng ta có thể thay đổi màu sắc của ảnh bằng cách
# thay đổi giá trị trên từng kênh màu(R,G, B)
# Ảnh có kích thước (400, 248, 3) - 3 là số kênh màu;
# Chúng ta nhân nó với array [1, 0.95, 0.9] có kích thước (3,);
# Điều này có nghĩa là giá trị kênh màu Red không đổi,
# nhân thêm ở kênh màu green và blue thêm 0.95 và 0.9
img_tinted = img * [1, 0.95, 0.9]
# Thay đổi kích thước ảnh img_tinted về 300 by 300 pixels.
img_tinted = imresize(img_tinted, (300, 300))
# Lưu ảnh img_tinted vào ổ cứng
imsave('../assets/cat_tinted.jpg', img_tinted)
Bạn có thể xem sử thay đổi vì ảnh đã lưu trong thư mục assets. Bên trái là ảnh gốc và bên phải là ảnh đã thay đổi màu + thay đổi kích thước.
MATLAB files
Các hàm scipy.io.loadmat
vàscipy.io.savemat
. Hai hàm này cho phép bạn đọc và ghi matlab files. Bạn có thể đọc về nó tại tài liệu này.
Khoảng cách giữa các điểm
Scipy định nghĩa một số hàm hữu ích cho việc tính khoảng cách giữa các điểm.
Hàm scipy.spatial.distance.pdist
: tính toán khoảng cách giữa 2 cặp điểm bất kỳ trong một tập hợp các điểm được cho.
import numpy as np
from scipy.spatial.distance import pdist, squareform
# Tạo một numpy array mà mỗi hàng là một điểm trong không gian 2 chiều:
# [[0 1]
# [1 0]
# [2 0]]
x = np.array([[0, 1], [1, 0], [2, 0]])
print(x)
# tính khoảng cách Euclidean giữa tất cả các hàng trong x.
# d[i, j] là khoảng cách Euclidean giữa x[i, :] và x[j, :],
# Và d sẽ có giá trị như sau:
# [[ 0. 1.41421356 2.23606798]
# [ 1.41421356 0. 1. ]
# [ 2.23606798 1. 0. ]]
d = squareform(pdist(x, 'euclidean'))
print(d)
Bạn có thể đọc đầy đủ thông tin chi tiết về hàm này trong tài liệu này.
scipy.spatial.distance.cdist
). Nó giúp tính toán khoảng cách giữa các cặp điểm trong 1 tập hợp các điểm cho trước; bạn có thể đọc thêm trong tài liệu này.Thư viện Matplotlib sẽ là bài học cuối cùng trong khóa học nhanh python. Đây là một thư viện hỗ trợ đắc lực trong việc biểu diễn dữ liệu. Matplot lib sẽ giúp bạn biểu diễn dữ liệu lên đồ thì và cho cái nhìn trực quan nhất.
Matplotlib
Matplotlib là một thư viện vẽ đồ thị.Trong khóa học nhanh python này tôi sẽ trình bày ngắn gọn về mô đun matplotlib.pyplot
. Nó cung cấp chức năng vẽ đồ thị tương tự như trong MATLAB.
Vẽ đồ thị
Một hàm quan trọng nhất trong matplotlib là plot
, nó cho phép bạn vẽ các đồ thị với dữ liệu 2 chiều. Đây là một ví dụ:
import numpy as np
import matplotlib.pyplot as plt
# Tính toán x và y để lấy 1 số cặp điểm trên đồ thị hình sin
x = np.arange(0, 3 * np.pi, 0.1)
y = np.sin(x)
# Vẽ đồ thị theo các điểm dữ liệu dùng matplotlib
plt.plot(x, y)
plt.show() # Bạn phải gọi hàm plt.show() để đồ thị xuất hiện.
Sau khi chạy bạn sẽ thu được kết quả như sau:
Chúng ta có thể bổ sung thêm một số thông tin cho đồ thị như: vẽ nhiều đồ thị trên một, thêm chú thích, nhãn của các trục đồ thị, tiêu đề. Việc này có thể làm rất là đơn giản như sau:
import numpy as np
import matplotlib.pyplot as plt
# Tính toán x và y để lấy 1 số cặp điểm trên đồ thị hình sin và cosin
x = np.arange(0, 3 * np.pi, 0.1)
y_sin = np.sin(x)
y_cos = np.cos(x)
# Vẽ đồ thị theo các điểm dữ liệu dùng matplotlib
plt.plot(x, y_sin)
plt.plot(x, y_cos)
plt.xlabel('x axis label') # nhãn trục x
plt.ylabel('y axis label') # nhãn trục y
plt.title('Sine and Cosine') # set tiêu đề
plt.legend(['Sine', 'Cosine']) # Hiển thị chú thích của đồ thị
plt.show()
Kết quả sau khi chạy như sau:
Bạn có thể đọc thêm thông tin về hàm plot
trong tài liệu này.
Đồ thị con (Subplots)
Bạn có thể vẽ các đồ thị khác nhau trên cùng một hình bằng cách sử dụng hàm subplot
. Đây là một ví dụ:
import numpy as np
import matplotlib.pyplot as plt
# Tính toán x và y để lấy 1 số cặp điểm trên đồ thị hình sin và cosin
x = np.arange(0, 3 * np.pi, 0.1)
y_sin = np.sin(x)
y_cos = np.cos(x)
# Thiết lập lưới các đồ thị chia làm 2 đồ thị con theo chiều cao.
# và set đồ thị con đầu tiên active.
# active nghĩa là bảo code rằng tao đang làm việc với nó.
plt.subplot(2, 1, 1)
# Vẽ đồ thị đầu tiên
plt.plot(x, y_sin)
plt.title('Sine')
# Set đồ thị thứ 2 active, và vẽ.
plt.subplot(2, 1, 2)
plt.plot(x, y_cos)
plt.title('Cosine')
# Hiển thị.
plt.show()
Và bạn có thể thấy kết quả như hình sau:
Bạn có thể đọc nhiều hơn thông tin về hàm subplot
trong tài liệu này.
Hình ảnh
Bạn có thể dùng hàm imshow
của thư viện matplotlib để hiển thị hình ảnh. Đây là một ví dụ:
import numpy as np
from scipy.misc import imread, imresize
import matplotlib.pyplot as plt
img = imread('../assets/cat.jpg')
img_tinted = img * [1, 0.95, 0.9]
# Hiển thị ảnh gốc
plt.subplot(1, 2, 1)
plt.imshow(img)
# Hiện thị ảnh sau khi thay đổi màu
plt.subplot(1, 2, 2)
# Để tránh xảy ra lỗi trong trường hợp img_tinted không phải kiểu uint8.
# chúng ta cast - ép kiểu nó về uint8 trước khi hiển thị
plt.imshow(np.uint8(img_tinted))
plt.show()
Tổng kết khóa học lập trình python
- https://www.codecademy.com/learn/learn-python
- https://www.learnpython.org/
- Ebook learn python the hard way – Zed Shaw
- http://cs231n.github.io/python-numpy-tutorial/
Nếu bạn có bất kỳ thắc mắc nào liên quan tới khóa học lập trình python. Hãy để lại câu hỏi ở phần bình luận cuối bài nhé. Tôi sẽ cùng các bạn giải quyết những thắc mắc đó.
Để lại một bình luận