Last active
April 27, 2019 17:29
-
-
Save hoangvanthien/f7215056cd5afaf0e2fe3b8b633a2204 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {"cells":[{"cell_type":"markdown","metadata":{},"source":["# Giới thiệu\n","NumPy là một thư viện Python được sử dụng nhiều khi làm việc với dữ liệu mảng và các phép toán tuyến tính. Kết hợp với SciPy và Matplotlib, bộ ba thư viện được xem là phiên bản thay thế cho MATLAB. Trong những năm gần đây, Python được xem là một ngôn ngữ tân tiến và đầy đủ hơn MATLAB.\n","\n","Trong notebook này, chúng ta sẽ tìm hiểu một số kiến thức căn bản trong numpy và cách sử dụng của nó trong các thuật toán tiền xử lý dữ liệu."]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["import numpy as np \n",""]},{"cell_type":"markdown","metadata":{},"source":["# Tổng quan về array\n","Một array trong numpy có kiểu là `numpy.ndarray`. Các yếu tố quan trọng của một `ndarray` bao gồm số chiều (`ndim`), kích thước của mỗi chiều (`shape`), kiểu dữ liệu của từng phần tử (`dtype`). Trong những ví dụ tiếp theo, chúng ta sẽ thấy `ndarray` là một kiểu dữ liệu có tính tùy biến cao, và tại sao chúng ta nên cẩn thận khi làm việc.\n","## Khởi tạo mảng\n","### `numpy.array`\n","Một trong những cách phổ biến để khởi tạo một `ndarray` là từ dữ liệu sẵn có, lưu trong một `list` nào đó, và convert qua kiểu `ndarray` bằng hàm `numpy.array` hoặc `numpy.asarray`.\n","\n","Hãy thử thay đổi dữ liệu khởi tạo của `a` trong ví dụ dưới đây thành:\n","- `[[1, 2], [3., 4], [5, 6]]`\n","- `[[1, 2], [3, 4], 5, 6.]`\n","- `[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]`"]},{"cell_type":"code","execution_count":2,"metadata":{},"outputs":[],"source":["def show_attributes(a):\n"," print(a)\n"," print(\"The number of dimension is: {0}\".format(a.ndim))\n"," print(\"The size of each dimension: {0}\".format(a.shape))\n"," print(\"The type of each element is: {0}\".format(a.dtype))\n",""]},{"cell_type":"code","execution_count":3,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[[ 1. 2.]\n [ 3. 4.]\n [ 5. 6.]]\nThe number of dimension is: 2\nThe size of each dimension: (3, 2)\nThe type of each element is: float64\n"}],"source":["a = np.array([[1, 2], [3., 4], [5, 6]]) \n","show_attributes(a)\n",""]},{"cell_type":"markdown","metadata":{},"source":[" Thử xóa parameter `dtype` trong phần khởi tạo của `a` dưới đây:"]},{"cell_type":"code","execution_count":4,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[1 2 3 4 list([5, 6])]\nThe number of dimension is: 1\nThe size of each dimension: (5,)\nThe type of each element is: object\n"}],"source":["a = np.array([1, 2, 3, 4, [5, 6]], dtype='object')\n","show_attributes(a)\n",""]},{"cell_type":"markdown","metadata":{},"source":["Trong trường hợp trên, lỗi xảy ra vì numpy không tự resolve được dimension và dtype của các element trong mảng. Lời khuyên tốt nhất là khi làm việc với numpy nói riêng và Python nói chung, cần kiểm soát kiểu dữ liệu chặt chẽ để tránh gặp lỗi.\n","\n","**Lưu ý:** Trong tất cả các hàm khởi tạo mảng của numpy đều hỗ trợ một parameter `dtype` để tùy chỉnh kiểu dữ liệu của từng phần tử.\n","\n","Ngoài cách khởi tạo từ dữ liệu có sẵn, numpy cũng hỗ trợ khởi tạo nhanh dữ liệu qua một số hàm như:\n","### `numpy.empty`\n","Khởi tạo một mảng với những số ngẫu nhiên. Bạn cần phải cung cấp shape của mảng dưới dạng một tuple (ví dụ `(2,2)`). Hãy thử thay đổi hoặc xóa parameter `dtype` trong đoạn code dưới đây."]},{"cell_type":"code","execution_count":5,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[[1 1]\n [1 0]]\n"}],"source":["a = np.empty((2,2), dtype=int)\n","print(a)\n",""]},{"cell_type":"markdown","metadata":{},"source":["### `numpy.zeros` và `numpy.ones`\n","Khởi tạo một mảng toàn số 0 hoặc số 1. Bạn cần phải cung cấp shape của mảng dưới dạng một tuple (ví dụ `(2,2)`)."]},{"cell_type":"code","execution_count":6,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[[ 0. 0.]\n [ 0. 0.]]\n[[1 1 1]\n [1 1 1]]\n"}],"source":["a = np.zeros((2,2))\n","print(a)\n","a = np.ones((2, 3), dtype=int)\n","print(a)\n",""]},{"cell_type":"markdown","metadata":{},"source":["### `numpy.arange`\n","Khởi tạo một mảng gồm các số trong một interval \\[start, stop) cho trước và được giãn cách bởi một giá trị \\[step\\].\n","\n","Syntax: `numpy.arange(start, stop, step, ...)`\n","\n","- Mặc định của `start` là 0\n","- Mặc định của `step` là 1"]},{"cell_type":"code","execution_count":7,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[ 3. 4.5 6. 7.5 9. 10.5 12. 13.5 15. 16.5 18. 19.5\n 21. 22.5 24. 25.5 27. ]\n"}],"source":["a = np.arange(3, 28, 1.5)\n","print(a)\n",""]},{"cell_type":"markdown","metadata":{},"source":["### `numpy.linspace`\n","Khởi tạo một mảng gồm n số trong một interval \\[start, stop\\] được giãn cách tuyến tính đều nhau\n","\n","Syntax: `numpy.linspace(start, stop, n, endpoint, ...)`\n","- Mặc định của `endpoint` là true. Nếu đặt về false, mảng sẽ chỉ bao gồm các số trong interval \\[start, stop)\n","- Mặc định của `n` là 50"]},{"cell_type":"code","execution_count":8,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[ 3. 4.31578947 5.63157895 6.94736842 8.26315789\n 9.57894737 10.89473684 12.21052632 13.52631579 14.84210526\n 16.15789474 17.47368421 18.78947368 20.10526316 21.42105263\n 22.73684211 24.05263158 25.36842105 26.68421053 28. ]\n"}],"source":["a = np.linspace(3, 28, 20)\n","print(a)\n",""]},{"cell_type":"markdown","metadata":{},"source":["### `numpy.logspace`\n","Khởi tạo một mảng gồm n số trong một interval $[10^{\\mathrm{start}}, 10^{\\mathrm{stop}}]$, được giãn cách đều nhau theo logarithm cơ số 10.\n","\n","Syntax: `numpy.logspace(start, stop, n, endpoint, base, ...)`\n","- Mặc định của `n` là 50.\n","- Mặc định của `endpoint` là true. Xem thêm ở phần `numpy.linspace`.\n","- Mặc định của `base` là 10.\n","\n","Bản chất của hàm này là nó sẽ generate một linspace trước, rồi lấy lũy thừa từng phần tử trong linspace đó theo cơ số `base`."]},{"cell_type":"code","execution_count":9,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]\n[ 2. 4. 8. 16. 32. 64. 128. 256. 512. 1024.]\n"}],"source":["a = np.linspace(1, 10, 10)\n","print(a)\n","a = np.logspace(1, 10, 10, base=2)\n","print(a)\n",""]},{"cell_type":"markdown","metadata":{},"source":["### `numpy.genfromtxt`\n","Hàm này thường được dùng để đọc ma trận từ một file text (thường là .csv).\n","\n","Syntax: `numpy.genfromtxt('filename.csv', delimeter=',')`\n","\n","## Lọc phần tử (Slicing và Indexing)\n","Các phần tử trong một `ndarray` có thể được lọc bằng cú pháp `a[obj]`, trong đó `obj` là một tham số đa dạng, quyết định những phần tử nào sẽ được chọn từ `a`, và quyết định format của kết quả lọc\n","### Basic Slicing\n","Basic Slicing sẽ được kích hoạt khi `obj` là:\n","- Một (hoặc tuple) integer\n","- Một (hoặc tuple) object của lớp `slice`\n","- Một tuple gồm hỗn hợp integer, object `slice`, `Ellipsis`, hoặc `numpy.newaxis` (hai lớp cuối sẽ không được đề cập)\n","\n","Basic slicing luôn cho ra kết quả là một _view_. \n"," \n","**`obj` là tuple các integer**\n"," \n","Trường hợp đơn giản, mảng một chiều, syntax: `a[i]`. Truy cập phần tử thứ `i` của mảng. Nếu mảng có _n_ chiều, có thể gọi `a[(i_1, i_2, ..., i_n)]` hoặc `a[i_1, i_2, ..., i_n]`."]},{"cell_type":"markdown","metadata":{},"source":["**`obj` là tuple các object `slice`**\n","\n","Syntax: `a[slice(start, stop, step)]` hoặc `a[start:stop:step]` (mảng một chiều)\n","\n","- Mặc định của `start` là 0\n","- Mặc định của `end` là kích thước của mảng\n","- Mặc định của `step` là 1"]},{"cell_type":"code","execution_count":10,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[0 1 2 3 4 5 6 7 8 9]\n[3 5 7]\n<class 'slice'>\n[3 5 7]\n"}],"source":["a = np.arange(0, 10, 1)\n","print(a)\n","print(a[3:8:2])\n","s = slice(3,8,2)\n","print(type(s))\n","print(a[s])\n",""]},{"cell_type":"markdown","metadata":{},"source":["**Lưu ý:** Trong Python, chỉ số của một phần tử trong mảng có thể là số âm. Thông thường, một mảng `a` gồm _n_ phần tử sẽ được đánh số từ 0 tới _n-1_. Ngoài ra, phần tử cuối cùng của mảng cũng được đánh số là -1, và phần tử đầu tiên cũng được đánh số là _-n_. Tổng quát hơn, ta có `a[i] == a[i-n]`, $\\forall\\ 0\\leq i < n$."]},{"cell_type":"markdown","metadata":{},"source":["Bản chất của `a[slice(start, stop, end)]` có thể _hiểu_ như sau. Chương trình sẽ sinh một `numpy.arange(start, stop, end)`. Sau đó, duyệt qua các chỉ số của `a`, nếu chỉ số đó nằm trong mảng `arange` thì sẽ được thêm vào kết quả. Tuy nhiên, cách tiến hành thực tế trong thư viện không nhất thiết phải như vậy.\n","\n","Cách hiểu trên sẽ trở nên hữu ích hơn khi chúng ta lọc mảng đa chiều. Ví dụ dưới đây, `a` là mảng hai chiều, được lọc bằng `a[slice(1, 3), slice(1, 4, 2)].` Tức là sẽ có hai mảng arange, `[1, 2]` và `[1, 3]`. Sau đó, chương trình sẽ duyệt qua tất cả các bộ chỉ số `(i,j)` của mảng `a`, nếu $(i, j)\\in \\{1,2\\}\\times \\{1,3\\}$ thì phần tử `a[i,j]` sẽ được thêm vào mảng kết quả."]},{"cell_type":"code","execution_count":11,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"a =\n [[ 0 1 2 3]\n [ 4 5 6 7]\n [ 8 9 10 11]]\na.shape = (3, 4)\n[[ 5 7]\n [ 9 11]]\n"}],"source":["a = np.array([[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]])\n","print('a =\\n', a)\n","print('a.shape =', a.shape)\n","print(a[1::, 1:4:2]) # 1:: means 1:3:1 in this case\n",""]},{"cell_type":"markdown","metadata":{},"source":["### Advanced Slicing\n","Advanced slicing sẽ được kích hoạt khi `obj` là:\n","- Một `ndarray` hoặc `list` với dtype là integer hoặc boolean\n","- Một tuple, trong đó ít nhất một phần tử của tuple thuộc kiểu sequence, ví dụ: `list`, `tuple`, hoặc `ndarray`\n","\n","Advanced slicing luôn copy dữ liệu từ mảng gốc sang kết quả.\n","\n","**`obj` là một `ndarray`**\n","\n","Giả sử `a` là một `ndarray` với $m$ chiều, $(n_1, n_2, \\dots, n_m)$, và `obj` là một `ndarray` với $2\\leq k\\leq m+1$ chiều, $(n'_1 = m, n'_2, \\dots, n'_k)$. Tất cả những phần tử của `obj[i]` ($1\\leq i\\leq m$) phải là số tự nhiên nhỏ hơn $n_i$. Mảng kết quả sẽ có $k-1$ chiều $(n'_2, n'_3, \\dots, n'_k)$.\n","\n","Thuật toán tìm `a[obj]` có thể hình dung như sau:\n","\n","- $\\forall i := (i_2, i_3, \\dots, i_k)$ thỏa mãn $i_j < n'_j$, với $j=2\\dots k$.\n","\n"," - $\\texttt{pos}=(\\texttt{obj}[1][i], \\texttt{obj}[2][i], \\dots, \\texttt{obj}[m][i])$ là vị trí của phần tử cần tìm\n"," - Gán `ans[i] = a[pos]`.\n","<br><br>\n","- Trả về kết quả `ans`\n"," \n","Giả sử ta có một mảng ba chiều ($m=3$) như sau: "]},{"cell_type":"code","execution_count":12,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[[[ 0 1 2 3]\n [ 4 5 6 7]\n [ 8 9 10 11]]\n\n [[12 13 14 15]\n [16 17 18 19]\n [20 21 22 23]]]\n"}],"source":["a = np.array([[[0, 1, 2, 3],\\\n"," [4, 5, 6, 7],\\\n"," [8, 9, 10, 11]],\\\n"," \n"," [[12, 13, 14, 15],\\\n"," [16, 17, 18, 19],\\\n"," [20, 21, 22, 23]]])\n","print(a)\n",""]},{"cell_type":"markdown","metadata":{},"source":["Shape của mảng trên là (2, 3, 4)\n","Trong đoạn code dưới đây, thử thay `obj` bằng:\n","- Một mảng 2 chiều ($k=2$): `[[0], [3], [2]]`, hoặc `[[0, 1], [2, 1], [3, 0]]`\n","- Một mảng 3 chiều ($k=3$):\n","\n","```\n","[[[0, 0, 1],\\\n"," [1, 1, 1]],\\\n","\n","[[1, 1, 0],\\\n"," [2, 1, 0]],\\\n","\n","[[0, 2, 3],\\\n"," [0, 2, 0]]]\n","```\n","\n","- Một mảng 4 chiều ($k=4$):\n","\n","```\n","[[[[0, 0],\\\\\n"," [0, 0]],\\\\ \n"," [[1, 1],\n"," [1, 1]]],\\\\\n","\n","[[[1, 1],\\\\\n"," [2, 2]],\\\\\n"," [[0, 0],\\\\\n"," [1, 1]]],\\\\\n","\n","[[[1, 2],\\\\\n"," [1, 2]],\\\\\n"," [[2, 3],\\\\\n"," [2, 3]]]]\n","```\n","\n","Dự đoán và kiểm tra kết quả"]},{"cell_type":"code","execution_count":13,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[[[ 5 6]\n [ 9 10]]\n\n [[14 15]\n [18 19]]]\n"}],"source":["obj = [[[[0, 0],\\\n"," [0, 0]],\\\n","\n"," [[1, 1],\n"," [1, 1]]],\\\n","\n","\n"," [[[1, 1],\\\n"," [2, 2]],\\\n","\n"," [[0, 0],\\\n"," [1, 1]]],\\\n","\n","\n"," [[[1, 2],\\\n"," [1, 2]],\\\n","\n"," [[2, 3],\\\n"," [2, 3]]]]\n","print(a[obj])\n",""]},{"cell_type":"markdown","metadata":{},"source":["Trong trường hợp `obj` là một `ndarray` một chiều ($k=1$) gồm các số tự nhiên không quá $m$, gọi `a[obj]` sẽ trả về `a[obj[0]]`, `a[obj[1]]`, v.v.."]},{"cell_type":"markdown","metadata":{},"source":["Chúng ta cũng có thể tiến hành advanced slicing khi `obj` là một `ndarray` với dtype là boolean. Khi đó, `obj` phải có cùng shape với `a`, và khi gọi `a[obj]` ta sẽ nhận được một mảng một chiều chứa các phần tử `a[i]` với `i` là một tuple thỏa mãn `obj[i] == True`.\n","\n","Ví dụ dưới đây minh họa việc lọc ra các số chia hết cho 6 trong mảng `a`:"]},{"cell_type":"code","execution_count":14,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[[[ True False False False]\n [False False True False]\n [False False False False]]\n\n [[ True False False False]\n [False False True False]\n [False False False False]]]\n[ 0 6 12 18]\n"}],"source":["obj = (a % 6 == 0)\n","print(obj)\n","print(a[obj])\n",""]},{"cell_type":"markdown","metadata":{},"source":["## Duyệt mảng\n","Duyệt mảng trong Python/Numpy cũng giống như trong C/C++, i.e. ưu tiên hàng trước, cột sau. Hàm `numpy.ndenumerate(a)` trả về danh sách chỉ số của `a` và giá trị tương ứng.\n","\n","Hàm numpy.reshape sẽ tạo một \"khung\" array với shape yêu cầu, rồi lần lượt \"thả\" các phần tử theo thứ tự `ndenumerate` và array mới."]},{"cell_type":"code","execution_count":15,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[[[ 0 1 2 3]\n [ 4 5 6 7]\n [ 8 9 10 11]]\n\n [[12 13 14 15]\n [16 17 18 19]\n [20 21 22 23]]]\n\n((0, 0, 0), 0)\n((0, 0, 1), 1)\n((0, 0, 2), 2)\n((0, 0, 3), 3)\n((0, 1, 0), 4)\n((0, 1, 1), 5)\n((0, 1, 2), 6)\n((0, 1, 3), 7)\n((0, 2, 0), 8)\n((0, 2, 1), 9)\n((0, 2, 2), 10)\n((0, 2, 3), 11)\n((1, 0, 0), 12)\n((1, 0, 1), 13)\n((1, 0, 2), 14)\n((1, 0, 3), 15)\n((1, 1, 0), 16)\n((1, 1, 1), 17)\n((1, 1, 2), 18)\n((1, 1, 3), 19)\n((1, 2, 0), 20)\n((1, 2, 1), 21)\n((1, 2, 2), 22)\n((1, 2, 3), 23)\n\n\n[[[ 0 1 2]\n [ 3 4 5]]\n\n [[ 6 7 8]\n [ 9 10 11]]\n\n [[12 13 14]\n [15 16 17]]\n\n [[18 19 20]\n [21 22 23]]]\n"}],"source":["a = np.arange(24).reshape(2,3,4)\n","print(a)\n","print('')\n","for i in np.ndenumerate(a):\n"," print(i)\n","print('\\n')\n","a = a.reshape(4,2,3)\n","print(a)\n",""]},{"cell_type":"markdown","metadata":{},"source":["# Tính toán trên array\n","Cho bài toán sau: Hãy tính tổng các phần tử có trong một mảng. Chúng ta sẽ so sánh hai cách làm giữa việc dùng code Python bình thường và dùng hàm `numpy.sum`."]},{"cell_type":"code","execution_count":16,"metadata":{},"outputs":[],"source":["import time\n","a = np.arange(100000)\n",""]},{"cell_type":"code","execution_count":17,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"4999950000\nTime taken: 0.045427799224853516\n"}],"source":["start_time = time.time()\n","sum = 0\n","for i in a:\n"," sum += i\n","print(sum)\n","time_taken_1 = time.time()-start_time\n","print(\"Time taken: \", time_taken_1)\n",""]},{"cell_type":"code","execution_count":18,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"4999950000\nTime taken: 0.0007328987121582031\nnumpy.sum is 61.98373454782043 times faster.\n"}],"source":["start_time = time.time()\n","sum = np.sum(a)\n","print(sum)\n","time_taken_2 = time.time()-start_time\n","print(\"Time taken: \", time_taken_2)\n","print(\"numpy.sum is \", time_taken_1/time_taken_2, \" times faster.\")\n",""]},{"cell_type":"markdown","metadata":{},"source":["## Vectorization\n","Vectorization là thuật ngữ chỉ việc tận dụng tính chất đồng nhất về kiểu của các phần tử trong mảng để tối ưu hóa các hàm trong Python bằng những ngôn ngữ bậc thấp như C. Có thể hiểu nôm na rằng, khi viết code Python thuần túy, Python luôn phải kiểm tra kiểu dữ liệu của các biến như `sum` và `i` để tìm quy luật `+=` thích hợp. Trong khi đó, `numpy` biết chắc chắn các phần tử trong `a` đều có cùng một kiểu dữ liệu, và nó \"đẩy\" công việc này xuống cho ngôn ngữ C. C là ngôn ngữ bậc thấp hơn Python, có chú trọng nghiêm ngặt về kiểu dữ liệu hơn Python, và chạy nhanh hơn Python đáng kể. Chính vì vậy những hàm trông đơn giản như `numpy.sum` trong thư viện `numpy` lại có tốc độ rất tối ưu. Thuật ngữ Vectorization được gặp nhiều trong các ngôn ngữ khác như MATLAB và R.\n","\n","Một hàm `f(x)`, trong đó `x` là một k-tuple, sau khi đã vectorized có thể hoạt động khi `x` là một k-tuple các ndarray với cùng size _n_ nào đó. Khi đó, hàm sẽ áp dụng _n_ lần với _n_ k-tuple, tạo thành bằng cách lấy _k_ phần tử từ các ndarray ra. Kết quả trả về là một ndarray _n_ phần tử.\n","\n","Trong những mục tiếp theo, chúng ta sẽ tìm hiểu phân loại các hàm đã được vectorized.\n","\n","### Unary function\n","\n","Là các hàm chỉ cần một đối số. Các unary functions phổ biến có thể kể đến như: (`numpy.`) `aboslute`, `sqrt`, `sin`, `cos`, `tan`, `log`, `log10`, `log2`, `exp`."]},{"cell_type":"code","execution_count":19,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"2.0\n[ 0 4 16 36 64 100]\n[ 0. 2. 4. 6. 8. 10.]\n"}],"source":["print(np.sqrt(4)) # Works with a number\n","a = np.array([(i**2) for i in range(0,12,2)])\n","print(a)\n","print(np.sqrt(a)) # Also works with an array of numbers\n",""]},{"cell_type":"markdown","metadata":{},"source":["### Binary function\n","\n","Là các hàm cần hai đối số. Phổ biến nhất có thể kể đến các phép toán đại số (cộng, trừ, nhân, chia, lũy thừa, chia lấy dư), các phép so sánh (<, >, <=, >=, ==, !=), các phép toán trên bit và boolean (&, |, ^), hàm `numpy.maximum`, hàm `numpy.minimum`."]},{"cell_type":"code","execution_count":20,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"a = [17 12 16 1 14 13 15]\nb = [ 7 1 2 16 5 18 8]\na+b = [24 13 18 17 19 31 23]\na-b = [ 10 11 14 -15 9 -5 7]\nmax(a,b) = [17 12 16 16 14 18 15]\n"}],"source":["a = np.array([np.random.randint(0, 20, dtype=int) for _ in range (7)])\n","b = np.array([np.random.randint(0, 20, dtype=int) for _ in range (7)])\n","print(\"a = \", a)\n","print(\"b = \", b)\n","print(\"a+b = \", a+b)\n","print(\"a-b = \", np.subtract(a, b))\n","print(\"max(a,b) = \", np.maximum(a, b))\n",""]},{"cell_type":"markdown","metadata":{},"source":["### Sequential function\n","\n","Là các hàm cần đối số là một dãy số (`ndarray`) và trả về đúng một số. Phổ biến nhất có thể kể đến như (`numpy.`): `mean`, `median`, `var`, `std`, `max`, `min`, `argmax`, `argmin`, `sum`.\n","\n","Hãy xem lại ví dụ về hàm `numpy.sum` ở trên. Tiếp theo, chúng ta bàn đến việc chọn `axis` trong một sequential function. \n","\n","Có thể hình dung rằng, một `ndarray` có _m_ chiều thì sẽ có _m_ trục (axis). Trong một số trường hợp, chúng ta không thích tính tổng của tất cả các phần tử trong một ma trận mà chỉ thích tổng từng cột, ta có thể chỉ định `axis=0`."]},{"cell_type":"code","execution_count":21,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[[ 0 1 2 3]\n [ 4 5 6 7]\n [ 8 9 10 11]]\n[12 15 18 21]\n"}],"source":["a = np.arange(12).reshape(3,4)\n","print(a)\n","print(np.sum(a, axis=0))\n",""]},{"cell_type":"markdown","metadata":{},"source":["Ta cũng có thể chỉ định nhiều trục mà chúng ta muốn hàm duyệt qua. Ví dụ ta có 3 ma trận và cần tính tổng của từng ma trận, ta đặt `axis=(1,2)`, nếu cần tính tổng của từng hàng của từng ma trận, ta đặt `axis=2`."]},{"cell_type":"code","execution_count":22,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[[[ 0 1 2 3]\n [ 4 5 6 7]\n [ 8 9 10 11]]\n\n [[12 13 14 15]\n [16 17 18 19]\n [20 21 22 23]]]\n[ 66 210]\n[[ 6 22 38]\n [54 70 86]]\n"}],"source":["a = np.arange(24).reshape(2,3,4)\n","print(a)\n","print(np.sum(a, axis=(1,2)))\n","print(np.sum(a, axis=2))\n",""]},{"cell_type":"markdown","metadata":{},"source":["Numpy thậm chí cũng cung cấp một hàm tên `numpy.vectorize` để giúp vectorize những hàm mà chúng ta tự viết. Tuy nhiên, lại cần lưu ý rằng hàm này thực chất không hề tối ưu thời gian thực thi của hàm chúng ta. Nó không thể transpile code Python của chúng ta sang C được. Mục đích của `numpy.vectorize` là lặp đi lặp lại một hàm trên các phần tử của mảng để cho ra một mảng kết quả."]},{"cell_type":"code","execution_count":23,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[ 1 1 2 6 24 120 720 5040]\n"}],"source":["def factorial(n):\n"," ans = 1\n"," for i in range(1, n+1):\n"," ans *= i\n"," return ans\n","vf = np.vectorize(factorial)\n","print(vf(np.arange(8)))\n",""]},{"cell_type":"markdown","metadata":{},"source":["# Một số phương pháp tiền xử lý\n","\n","Trong phần này chúng ta sẽ xem xét một vài phương pháp xử lý dữ liệu bằng numpy. Lưu ý rằng những phương pháp này cũng được cung cấp sẵn trong thư viện `scikit-learn`.\n","\n","Trong nhiều phương pháp xử lý dữ liệu, chúng ta thường áp dụng những phép toán như tịnh tiến (cộng/trừ một hằng số với tất cả các điểm dữ liệu) và scaling (nhân/chia một hằng số với tất cả các điểm dữ liệu).\n","\n","## Feature scaling\n","\n","Feature scaling hay còn gọi là Min-max normalizing, là phương pháp thu nhỏ vùng dữ liệu lại về khoảng [0, 1] sao cho khoảng cách giữa các điểm dữ liệu vẫn giữ được tỉ lệ.\n","\n","Một số thuật toán quan tâm đến khoảng cách giữa các điểm dữ liệu (e.g. nearest neighbors, gradient descent), khi khoảng cách lớn quá mức không cần thiết có thể gây ra các bước tính toán cồng kềnh, chậm chạp hơn. Feature scaling tỏ ra hữu ích trong những trường hợp này."]},{"cell_type":"code","execution_count":24,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[-16 -5 -27 -6 1 1 -18 -4 -17 0 -11 2 -28 -20 -1 -24 -9 -21\n -23 -14 -25 -14 -4 2 -28 -20 -9 -23 -5 2 -23 -11 -21 -18 2 -11\n 1 -2 -18 0 -9 1 -24 -9 -24 -20 -28 -17 -9 -23 -20 -24 -26 -2\n -18 -28 0 -27 -8 -10 -14 -12 -15 -28 -13 -7 -21 -21 -6 -12 -24 -20\n 2 -22 -5 -26 -7 -10 -11 -23 -4 -24 1 -11 -14 -4 -21 -9 -27 -14\n 2 -25 -5 -8 -27 -20 -15 0 -8]\n[ 0.4 0.76666667 0.03333333 0.73333333 0.96666667 0.96666667\n 0.33333333 0.8 0.36666667 0.93333333 0.56666667 1. 0.\n 0.26666667 0.9 0.13333333 0.63333333 0.23333333 0.16666667\n 0.46666667 0.1 0.46666667 0.8 1. 0.\n 0.26666667 0.63333333 0.16666667 0.76666667 1. 0.16666667\n 0.56666667 0.23333333 0.33333333 1. 0.56666667 0.96666667\n 0.86666667 0.33333333 0.93333333 0.63333333 0.96666667 0.13333333\n 0.63333333 0.13333333 0.26666667 0. 0.36666667 0.63333333\n 0.16666667 0.26666667 0.13333333 0.06666667 0.86666667 0.33333333\n 0. 0.93333333 0.03333333 0.66666667 0.6 0.46666667\n 0.53333333 0.43333333 0. 0.5 0.7 0.23333333\n 0.23333333 0.73333333 0.53333333 0.13333333 0.26666667 1. 0.2\n 0.76666667 0.06666667 0.7 0.6 0.56666667 0.16666667\n 0.8 0.13333333 0.96666667 0.56666667 0.46666667 0.8\n 0.23333333 0.63333333 0.03333333 0.46666667 1. 0.1\n 0.76666667 0.66666667 0.03333333 0.26666667 0.43333333 0.93333333\n 0.66666667]\n"}],"source":["def normalizing(a):\n"," Min = np.min(a)\n"," Max = np.max(a)\n"," a = (a - Min) / (Max - Min)\n"," return a\n","\n","a = np.random.randint(-28, 3, 99)\n","print(a)\n","print(normalizing(a))\n",""]},{"cell_type":"markdown","metadata":{},"source":["## Standardization\n","\n","Standardization là phương pháp tịnh tiến dữ liệu sao cho giá trị trung bình của nó là 0 và sau đó là chia mỗi điểm dữ liệu cho độ lệch chuẩn của bộ dữ liệu ban đầu.\n","\n","Chuẩn hóa dữ liệu là một phương pháp hữu ích khi cần so sánh hai bộ dữ liệu có đơn vị đo khác nhau."]},{"cell_type":"code","execution_count":25,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"[-0.28253525 0.87415982 -1.43923032 0.76900572 1.50508441 1.50508441\n -0.49284345 0.97931392 -0.38768935 1.39993031 0.24323524 1.6102385\n -1.54438442 -0.70315164 1.29477621 -1.12376803 0.45354343 -0.80830574\n -1.01861393 -0.07222706 -1.22892213 -0.07222706 0.97931392 1.6102385\n -1.54438442 -0.70315164 0.45354343 -1.01861393 0.87415982 1.6102385\n -1.01861393 0.24323524 -0.80830574 -0.49284345 1.6102385 0.24323524\n 1.50508441 1.18962211 -0.49284345 1.39993031 0.45354343 1.50508441\n -1.12376803 0.45354343 -1.12376803 -0.70315164 -1.54438442 -0.38768935\n 0.45354343 -1.01861393 -0.70315164 -1.12376803 -1.33407623 1.18962211\n -0.49284345 -1.54438442 1.39993031 -1.43923032 0.55869753 0.34838933\n -0.07222706 0.13808114 -0.17738115 -1.54438442 0.03292704 0.66385163\n -0.80830574 -0.80830574 0.76900572 0.13808114 -1.12376803 -0.70315164\n 1.6102385 -0.91345984 0.87415982 -1.33407623 0.66385163 0.34838933\n 0.24323524 -1.01861393 0.97931392 -1.12376803 1.50508441 0.24323524\n -0.07222706 0.97931392 -0.80830574 0.45354343 -1.43923032 -0.07222706\n 1.6102385 -1.22892213 0.87415982 0.55869753 -1.43923032 -0.70315164\n -0.17738115 1.39993031 0.55869753]\n"}],"source":["def standardizing(a):\n"," Mean = np.mean(a)\n"," Std = np.std(a)\n"," a = (a - Mean) / Std\n"," return a\n","\n","print(standardizing(a))\n",""]},{"cell_type":"code","execution_count":26,"metadata":{},"outputs":[],"source":""}],"nbformat":4,"nbformat_minor":2,"metadata":{"language_info":{"name":"python","codemirror_mode":{"name":"ipython","version":3}},"orig_nbformat":2,"file_extension":".py","mimetype":"text/x-python","name":"python","npconvert_exporter":"python","pygments_lexer":"ipython3","version":3}} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment