2.1. Thao Tác Với Dữ Liệu

2.1.2. Phép toán¶

Cuốn sách này không nói về kỹ thuật phần mềm. Chúng tôi không chỉ hứng thú với việc đơn giản đọc và ghi dữ liệu vào/từ các mảng mà còn muốn thực hiện các phép toán trên các mảng này. Một vài phép toán đơn giản và hữu ích nhất là các phép toán tác động lên từng phần tử (elementwise). Các phép toán này hoạt động như những phép toán chuẩn trên số vô hướng áp dụng lên từng phần tử của mảng. Với những hàm nhận hai mảng đầu vào, phép toán theo từng thành phần được áp dụng trên từng cặp phần tử tương ứng của hai mảng. Ta có thể tạo một hàm theo từng phần tử từ một hàm bất kỳ ánh xạ từ một số vô hướng tới một số vô hướng.

Trong toán học, ta ký hiệu một toán tử đơn ngôi vô hướng (lấy một đầu vào) bởi \(f: \mathbb{R} \rightarrow \mathbb{R}\). Điều này nghĩa là hàm số ánh xạ từ một số thực bất kỳ (\(\mathbb{R}\)) sang một số thực khác. Tương tự, ta ký hiệu một toán tử hai ngôi vô hướng (lấy hai đầu vào, trả về một đầu ra) bởi \(f: \mathbb{R}, \mathbb{R} \rightarrow \mathbb{R}\). Cho trước hai vector bất kỳ \(\mathbf{u}\)\(\mathbf{v}\) với cùng kích thước, và một toán tử hai ngôi \(f\), ta có thể tính được một vector \(\mathbf{c} = F(\mathbf{u},\mathbf{v})\) bằng cách tính \(c_i \gets f(u_i, v_i)\) cho mọi \(i\) với \(c_i, u_i\), và \(v_i\) là các phần tử thứ \(i\) của vector \(\mathbf{c}, \mathbf{u}\), và \(\mathbf{v}\). Ở đây, chúng ta tạo một hàm trả về vector \(F: \mathbb{R}^d, \mathbb{R}^d \rightarrow \mathbb{R}^d\) bằng cách áp dụng hàm \(f\) lên từng phần tử.

Trong MXNet, các phép toán tiêu chuẩn (+, -, *, /, và **) là các phép toán theo từng phần tử trên các tensor đồng kích thước bất kỳ. Ta có thể gọi những phép toán theo từng phần tử lên hai tensor đồng kích thước. Trong ví dụ dưới đây, các dấu phẩy được sử dụng để tạo một tuple \(5\) phần tử với mỗi phần tử là kết quả của một phép toán theo từng phần tử.

x = np.array([1, 2, 4, 8]) y = np.array([2, 2, 2, 2]) x + y, x - y, x * y, x / y, x ** y # The ** operator is exponentiation (array([ 3., 4., 6., 10.]), array([-1., 0., 2., 6.]), array([ 2., 4., 8., 16.]), array([0.5, 1. , 2. , 4. ]), array([ 1., 4., 16., 64.]))

Rất nhiều các phép toán khác có thể được áp dụng theo từng phần tử, bao gồm các phép toán đơn ngôi như hàm mũ cơ số \(e\).

np.exp(x) array([2.7182817e+00, 7.3890562e+00, 5.4598148e+01, 2.9809580e+03])

Ngoài các phép tính theo từng phần tử, ta cũng có thể thực hiện các phép toán đại số tuyến tính, bao gồm tích vô hướng của hai vector và phép nhân ma trận. Chúng ta sẽ giải thích những điểm quan trọng của đại số tuyến tính (mà không cần kiến thức nền tảng) trong Section 2.3.

Ta cũng có thể nối nhiều ndarray với nhau, xếp chồng chúng lên nhau để tạo ra một ndarray lớn hơn. Ta chỉ cần cung cấp một danh sách các ndarray và khai báo chúng được nối theo trục nào. Ví dụ dưới đây thể hiện cách nối hai ma trận theo hàng (trục \(0\), phần tử đầu tiên của kích thước) và theo cột (trục \(1\), phần tử thứ hai của kích thước). Ta có thể thấy rằng, cách thứ nhất tạo một ndarray với độ dài trục \(0\) (\(6\)) bằng tổng các độ dài trục \(0\) của hai ndarray đầu vào (\(3 + 3\)); trong khi cách thứ hai tạo một ndarray với độ dài trục \(1\) (\(8\)) bằng tổng các độ dài trục \(1\) của hai ndarray đầu vào (\(4 + 4\)).

x = np.arange(12).reshape(3, 4) y = np.array([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]]) np.concatenate([x, y], axis=0), np.concatenate([x, y], axis=1) (array([[ 0., 1., 2., 3.], [ 4., 5., 6., 7.], [ 8., 9., 10., 11.], [ 2., 1., 4., 3.], [ 1., 2., 3., 4.], [ 4., 3., 2., 1.]]), array([[ 0., 1., 2., 3., 2., 1., 4., 3.], [ 4., 5., 6., 7., 1., 2., 3., 4.], [ 8., 9., 10., 11., 4., 3., 2., 1.]]))

Đôi khi, ta muốn tạo một ndarray nhị phân thông qua các mệnh đề logic. Lấy x == y làm ví dụ. Với mỗi vị trí, nếu giá trị củaxy tại vị trí đó bằng nhau thì phần tử tương ứng trong ndarray mới lấy giá trị \(1\), nghĩa là mệnh đề logic x == y là đúng tại vị trí đó; ngược lại vị trí đó lấy giá trị \(0\).

x == y array([[False, True, False, True], [False, False, False, False], [False, False, False, False]])

Lấy tổng mọi phần tử trong một ndarray tạo ra một ndarray với chỉ một phần tử.

x.sum() array(66.)

Ta cũng có thể thay x.sum() bởi np.sum(x).

Từ khóa » Np.zeros_like Là Gì