I. Motivation

Numpy array là một kiểu dữ liệu phổ biến được dùng trong nhiều thư viện Python. image 46.png

image 1 14.png

Vậy tại sao ta lại cần Numpy?

Thực hiện các phép tính trên ma trận nhanh hơn.

image 2 14.png image 3 14.png

II. Common Function

1. Create Numpy arrays

zeros() – Tạo mảng toàn số 0

import numpy as np
arr = np.zeros((2, 3))  # 2 dòng, 3 cột
print(arr)
 
>>> Output:
[[0. 0. 0.]
 [0. 0. 0.]]

image 4 10.png Ứng dụng thực tế:

  • Khởi tạo trọng số mạng nơ-ron với giá trị mặc định ban đầu.
  • Làm sạch dữ liệu đầu vào (zero-padding ảnh, signal,…).

ones() – Tạo mảng toàn số 1

import numpy as np
arr = np.ones((2, 3))  # 2 dòng, 3 cột
print(arr)
 
>>> Output:
[[1. 1. 1.]
 [1. 1. 1.]]

image 5 8.png Ứng dụng thực tế:

  • Dùng trong broadcast toán học (ví dụ: nhân với vector khác để giữ nguyên giá trị).
  • Biểu diễn mask có điều kiện (ban đầu giả định mọi phần tử đều hợp lệ = 1).

arange() – Tạo dãy số liên tiếp

Cú pháp:

np.arange(start, stop, step)
arr1 = np.arange(5)      # [0, 1, 2, 3, 4]
arr2 = np.arange(0, 5, 2)# [0, 2, 4]

image 6 7.png

Ứng dụng thực tế:

  • Tạo mảng thời gian, index, batch, hoặc simulate dữ liệu.
  • Đơn giản hóa vòng lặp for khi kết hợp với slicing.

2. reshape() function

Chuyển đổi shape (kích thước) của một mảng mà không thay đổi dữ liệu bên trong. Cú pháp cơ bản:

np.reshape(a, newshape)

image 7 6.png Ví dụ:

import numpy as np
# Tạo list 2D
l = [[1, 2, 3],
     [4, 5, 6]]
# Chuyển sang ndarray
data = np.array(l)
# In ra mảng và shape ban đầu
print("data:\n", data)
print("data shape:\n", data.shape)
# Reshape: từ (2,3) thành (3,2)
data_rs = np.reshape(data, (3, 2))
# In ra mảng và shape mới
print("data_rs:\n", data_rs)
print("data_rs shape:\n", data_rs.shape)
>>> Output:
data:
[[1 2 3]
 [4 5 6]]
data shape:
(2, 3)
data_rs:
[[1 2]
 [3 4]
 [5 6]]
data_rs shape:
(3, 2)

Ứng dụng:

  • reshape() rất hữu ích trong xử lý:

    • ảnh (reshape về 2D/3D),
    • văn bản (1D → 2D theo batch),
    • dữ liệu huấn luyện ML (samples, features).
  • Có thể dùng .shape để kiểm tra kết quả sau khi reshape. Câu hỏi:

  • Nếu reshape về (1, 6) hoặc (6, 1) thì khác gì về hình thức?

    [[1 2 3 4 5 6]]  # 1 dòng, 6 cột
     
     [[1].           # 6 dòng, 1 cột
    	[2]
    	[3]
    	[4]
    	[5]
    	[6]]           
  • Ta đang có 6 phần tử (2 × 3 = 6). Điều gì xảy ra nếu reshape sang (4, 2)?

    a.reshape(4, 2)
     
    >>>
    ValueError: cannot reshape array of size 6 into shape (4,2)

    Sẽ lỗi vì:

  • Có thể dùng 1 trong reshape không? Gợi ý: np.reshape(data, (-1, 2))

    \#VD1:
    a.reshape(-1, 2)
    # tự động suy ra số dòng sao cho phù hợp với 2 cột
     
    # Với mảng 6 phần tử → (3, 2)
     
    \#VD2:
    a.reshape(2, -1)  # Tự động suy ra 3 cột → (2, 3)

    Rất hữu ích khi bạn không chắc hoặc không muốn tính toán kích thước còn lại bằng tay.

3. reshape() and flatten() functions

Cả hai đều giúp chuyển đổi mảng đa chiều về dạng 1 chiều, nhưng có khác biệt quan trọng về bản chất và ứng dụng.

image 8 6.png

reshape(-1): tạo view 1D

vector2 = data.reshape(-1)
  • Dùng 1 để NumPy tự tính số phần tử còn lại.
  • Kết quả là view của mảng gốc (nếu có thể), tức là liên kết bộ nhớ với mảng ban đầu.
  • Nhanh và tiết kiệm bộ nhớ.
  • Cẩn thận: Thay đổi vector2 có thể ảnh hưởng data.

flatten(): tạo bản sao 1D

vector1 = data.flatten()
  • Trả về mảng mới (copy), không ảnh hưởng đến data.
  • An toàn hơn khi cần thao tác độc lập.
  • Không chấp nhận reshape kiểu khác (chỉ ra 1 chiều duy nhất). Ví dụ:
import numpy as np
data = np.array([[4, 2, 4],
                 [2, 2, 1]])
vector1 = data.flatten()
vector2 = data.reshape(-1)
print("data:\n", data)
print("vector1 (flatten):", vector1)
print("vector2 (reshape):", vector2)
Output:
data:
[[4 2 4]
 [2 2 1]]
vector1:
[4 2 4 2 2 1]
vector2:
[4 2 4 2 2 1]

4. repeat() function

Cú pháp:

np.repeat(data, repeats, axis)
  • data: mảng gốc cần lặp
  • repeats: số lần lặp mỗi phần tử
  • axis:
    • 0: lặp theo chiều dọc (dòng)
    • 1: lặp theo chiều ngang (cột) image 9 6.png

Lặp theo axis=0 (chiều dọc – dòng)

data = np.array([[4, 3],
                 [7, 1]])
data_repeat = np.repeat(data, 2, axis=0)
print(data_repeat)
Output:
[[4 3]
 [4 3]
 [7 1]
 [7 1]]

Lặp theo axis=1 (chiều ngang – cột)

data_repeat = np.repeat(data, 2, axis=1)
print(data_repeat)
Output:
[[4 4 3 3]
 [7 7 1 1]]

Câu hỏi:

  • Nếu không chỉ rõ axis, kết quả là gì?

    NumPy sẽ flatten mảng trước (biến về 1D), sau đó lặp từng phần tử.

    a = np.array([[1, 2],
                  [3, 4]])
     
    np.repeat(a, 2)
     
    >>> Output:
    [1 1 2 2 3 3 4 4]
  • Có thể lặp lại mỗi phần tử một số lần khác nhau được không?np.repeat([1, 2, 3], repeats=[1, 2, 3])

    Hoàn toàn có thể! Tham số repeats có thể là một mảng (list/ndarray), chỉ định số lần lặp riêng biệt cho từng phần tử.

    np.repeat([1, 2, 3], repeats=[1, 2, 3])
     
    >>> Output:
    [1 2 2 3 3 3]

III. Indexing and Broadcasting

IV. AI Applications

1. OpenCV and NumPy

Image data

Grayscale images: image 10 5.png Color images: image 11 5.png image 12 4.png image 13 4.png RGB: Đây là cách phổ biến nhất để biểu diễn màu sắc trong hình ảnh. Mỗi hình ảnh được biểu diễn bằng ba kênh màu - đỏ (Red), xanh lục (Green), và xanh lam (Blue). Mỗi kênh này có giá trị từ 0 đến 255. image 14 4.png

OpenCV and Numpy

Read an image:

image = cv2.imread('image1.png', 1)
print(image.shape)
 
>>> (162, 311, 3)

image 15 4.png

image = cv2.imread('image2.png', 0)
print(image.shape)
 
>>> (162, 311)

image 16 4.png image 17 4.png Đọc và hiển thị ảnh với OpenCV:

import cv2
# Đọc hình ảnh từ file
img = cv2.imread("flowers.jpg")
# Hiển thị ảnh
cv2.imshow("Original", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Thư viện OpenCV sử dụng kênh màu BGR khi đọc ảnh. image 18 4.png

Đọc ảnh với OpenCV và hiển thị bằng Matplotlib

import cv2
import matplotlib.pyplot as plt
img = cv2.imread("flowers.jpg")
plt.imshow(img)
  • Vì sao hình ảnh hiển thị sai màu khi dùng OpenCV và Matplotlib?

    Khi bạn dùng cv2.imread() để đọc ảnh (BGR) và hiển thị bằng plt.imshow() (kỳ vọng RGB), ảnh sẽ bị đảo màu.

Giải pháp: Chuyển BGR → RGB

img = cv2.imread("flowers.jpg")
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img_rgb)

image 19 4.png

import cv2
import matplotlib.pyplot as plt
# Bước 1: Đọc ảnh (ảnh sẽ ở dạng BGR)
image = cv2.imread('image1.png')
# Bước 2: Chuyển BGR → RGB
image_rgb = image[:, :, [2, 1, 0]]  # hoặc image[:, :, ::-1]
# Bước 3: Hiển thị bằng matplotlib
plt.imshow(image_rgb)

image 20 4.png Load and save an image Đọc ảnh xám (Grayscale)

import cv2
img = cv2.imread('nature.jpg', 0)
cv2.imwrite('processed_image.jpg', img)
  • Tham số 0 giúp đọc ảnh ở chế độ xám (1 channel).
  • Mỗi pixel là 1 giá trị từ 0 → 255 biểu diễn mức độ sáng.
  • imwrite để lưu ảnh img vừa đọc hoặc đã xử lý thành file mới. Đọc ảnh màu (color image)
import cv2
img = cv2.imread('nature.jpg', 1)
cv2.imwrite('processed_image.jpg', img)
  • Tham số 1 giúp đọc ảnh ở chế độ màu.
  • Ảnh sẽ có 3 kênh màu: BGR (Blue – Green – Red).

image 21 4.png

image 22 4.png

Brightness Changes

Data type Trong xử lý ảnh bằng OpenCV, mỗi pixel của ảnh được biểu diễn dưới dạng số nguyên, thường là kiểu uint8 để tiết kiệm bộ nhớ và đảm bảo tương thích với các phép toán ảnh.

  • uint8 = unsigned 8-bit integer

  • Unsigned → chỉ có giá trị dương

  • 8 bits → biểu diễn được các giá trị trong khoảng:

    A∈[0,255]A \in [0, 255]A∈[0,255]

  • Dùng để biểu diễn độ sáng (brightness) mỗi pixel trên một kênh màu (R, G, B).

import cv2
# Đọc ảnh
image = cv2.imread('image1.png', 1)
print(image.shape)  # (162, 311, 3)  
# -> ảnh màu, 162 dòng, 311 cột, 3 kênh
print(image.dtype)  # uint8

Ép kiểu (Casting)

image = image.astype(dtype=np.uint8)

Chuyện gì xảy ra khi ép kiểu float → uint8?

  • Số thực 2.5 bị làm tròn xuống thành 2.
  • Khi chuyển float về uint8, phần thập phân bị cắt bỏ chứ không làm tròn.

image 23 4.png Vì sao phải ép kiểu? Khi xử lý ảnh (ví dụ tăng sáng, nhân hệ số, làm mờ), ta thường chuyển kiểu dữ liệu tạm thời sang float32 hoặc int16 để tránh lỗi tràn (overflow) hoặc sai số. Nhưng cuối cùng, ảnh đầu ra cần đưa về kiểu gốc – thường là **uint8** để:

  • Hiển thị được đúng trong thư viện như OpenCV, matplotlib
  • Lưu đúng định dạng ảnh chuẩn (JPG, PNG)
  • Tránh lỗi hoặc cảnh báo khi dùng hàm của OpenCV yêu cầu đúng kiểu dữ liệu

Problem of out of range Khi cộng vượt 255 thì… chuyện kỳ lạ xảy ra

data = np.array([0, 255])
data = data.astype(np.uint8)
data = data + 10
print(data)  # [10   9]
  • 255 + 10 = 265

  • Nhưng uint8 chỉ lưu được giá trị từ 0 → 255, nên:

image 24 4.png image 25 4.png **clip()** function Cú pháp:

np.clip(array, a_min, a_max)
import numpy as np
data = np.array([1, 2, 3, 4, 5, 6, 7, 8])
result = np.clip(data, a_min=3, a_max=6)
# result: [3 3 3 4 5 6 6 6]
  • Tất cả phần tử sẽ bị thay bằng
  • Tất cả phần tử sẽ bị thay bằng image 26 4.png Ứng dụng:
  • Giới hạn độ sáng ảnh: np.clip(image + 50, 0, 255)
  • Ngăn chặn giá trị sai phạm (vd: log(x), chia cho 0…) **np.where()** function Cú pháp:
np.where(condition, value_if_true, value_if_false)
  • Nếu điều kiện đúng, trả về value_if_true
  • Nếu sai, trả về value_if_false
arr = np.arange(5)   # [0 1 2 3 4]
condition = arr < 3
out = np.where(condition, arr, arr*2)
# out: [0 1 2 6 8]

Ứng dụng:

  • Tự động xử lý giá trị bất thường
  • Tạo mask/ảnh nhị phân từ điều kiện
  • Thay thế giá trị “nếu lớn hơn 255 thì gán bằng 255”, v.v.

Tăng/giảm độ sáng ảnh

Tăng độ sáng

import cv2
import numpy as np
# Đọc ảnh xám
I = cv2.imread('river.png', 0)
# Tăng độ sáng thêm 50
v = 50
I_brighter = np.clip(I + v, 0, 255).astype(np.uint8)
# Hiển thị ảnh
cv2.imshow('Original', I)
cv2.imshow('Brighter', I_brighter)
cv2.waitKey(0)
cv2.destroyAllWindows()

Giảm độ sáng

import cv2
import numpy as np
# Đọc ảnh xám
I = cv2.imread('river.png', 0)
# Giảm độ sáng đi 50
v = 50
I_darker = np.clip(I - v, 0, 255).astype(np.uint8)
# Hiển thị ảnh
cv2.imshow('Original', I)
cv2.imshow('Darker', I_darker)
cv2.waitKey(0)
cv2.destroyAllWindows()

? Có thể thử dùng where() để viết.

2. Weather forecasting

Temperature forecasting

Dự đoán hoặc phân tích dữ liệu nhiệt độ trong ngày (1 ngày chia theo giờ).
Mỗi bản ghi tương ứng với 1 giờ, nhiệt độ được đo theo °C. image 27 4.png image 28 4.png Đọc dữ liệu:

import pandas as pd
import numpy as np
data = pd.read_csv('temperature-1d.csv').to_numpy()
temp = data[:, 1]
  • Trục x: Index (thời gian trong ngày)
  • Trục y: Temperature (°C) Tính trung bình nhiệt độ theo ngày: image 29 3.png
  • Dữ liệu nhiệt độ được ghi mỗi giờ, tức 24 giá trị cho mỗi ngày.
  • Mục tiêu: gom lại mỗi 24 giá trị → 1 hàng, để tính trung bình theo ngày. Dùng reshape() để tổ chức lại dữ liệu
  • -1 → NumPy sẽ tự động tính số hàng (tức số ngày)
  • 24 → mỗi hàng là 24 giờ của một ngày
  • → Output shape: (số ngày, 24)
# Tính trung bình mỗi ngày (mỗi 24 giờ)
mean_24 = np.mean(temp.reshape(-1, 24), axis=1)
# Mở rộng ra lại 240 phần tử (giống dữ liệu gốc)
mean_24_repeat = np.repeat(mean_24, 24)
\#Vẽ biểu đồ
plt.plot(temp, 
					label="Original Temperature")
plt.plot(mean_24_repeat, label="Mean Temperature")
plt.legend()

image 30 3.png

Daily average temperatures

V. Quiz

  1. Có bao nhiêu đoạn code có lỗi? image 31 3.png
  • Đáp án:

    2 đoạn code lỗi: a_list * a_lista_list + 2

  1. Khi tới dòng 8, có bao nhiêu array chứa [9,3,5] image 32 3.png
  • Đáp án:

    Có 3 →

  1. Viết code cho hình sau: image 33 3.png
  • Đáp án:

    data[data%2 == 1] = -1

  1. Viết code thực hiện yêu cầu của ảnh:

    image 34 3.png

  • Đáp án:

    data[:,1]

    data[:1,2]

  1. Có bao nhiêu cách thực hiện yêu cầu được mô tả ở dưới (chọn nhiều đáp án)? image 35 3.png image 36 3.png
  • Đáp án:

    Đỏ xanh dương.

  1. Tính nhiệt độ trung bình cho từng ngày? image 37 2.png
  • Đáp án:

    np.mean(data.reshape(-1,6), axis=1)

  • Đáp án:
  • Đáp án:
  • Đáp án: