# SESSION 01: BASIC LINEAR ALGEBRA & NUMPY
## I. Basic Linear Algebra:
### 1. Giới thiệu:
Đại số tuyến tính là một nhánh của toán học liên quan đến pt tuyến tính, ánh xạ tuyến tính và biểu diễn chúng trong không gian.
**Đại Số Tuyến Tính là toán học của vector và ma trận**, được ứng dụng trong nhiều lĩnh vực, đặc biệt là AI.
<center><img src=https://i.imgur.com/T7oygjs.png></center>
### 2. Vector:
Là một dãy số được sắp xếp theo hàng ngang (vector hàng) hoặc hàng dọc (vector cột). Từng phần tử vector biểu diễn tọa độ của vector trong chiều không gian tương ứng.
Kí hiệu: $v$ = [$v_1, v_2, ...,v_n$ ] là vector n chiều, $v_i$ là tọa độ của $v$ trong chiều thứ $i$
Ví dụ: trong hệ trục tọa độ Oxy, vector (3, 4) thể hiện:
- Tọa độ của vector trong trục x là 3
- Tọa độ của vector trong trục y là 4
<img src=https://i.imgur.com/W4gk2yi.png height=300>
**Module** (độ lớn) của vector $v$: $|v|=\sqrt{\sum_i{v_i^2}}=\sqrt{v_1^2+v_2^2+…+v_n^2}$
### 3. Similarity:
Là độ giống nhau giữa các vector được thể hiện trên mặt phẳng tọa độ.
<center>
<img src=
https://developer.huawei.com/Enexport/sites/default/images/en/Develop/AI/facial-comparison/facial-comparisonimage.jpg height=300>
</center>
Các phương pháp để tính độ tương tự giữa các vector:
* ***Dot Product (Scalar Product)***:
**Định nghĩa:** Tích vô hướng (tích chấm) của 2 vector **cùng kích thước** $a = [a_1,a_2,...,a_n]$ và $b=[b_1,b_2,...,b_n]$ là một số thực $p$ được xác định bằng công thức: $$p = a.b = \sum_{i=1}^{n}a_ib_i = a_1b_1+a_2b_2+...+a_nb_n$$
-- Nếu Dot Product của 2 vector càng lớn (dương) thì 2 vector càng giống nhau
-- Nếu Dot Product của 2 vector bằng 0: 2 vector vuông góc
-- Nếu Dot Product của 2 vector càng nhỏ (âm) thì 2 vector ngược hướng
Ví dụ:
<center>
<img src="https://i.imgur.com/MpIh6If.png">
</center>
$$p_{ab} = a_1b_1 + a_2b_2 = 3\times3 + 1\times0 = 9$$
$$p_{ac} = a_1c_1 + a_2c_2 = 3\times(-1) + 1\times3 = 0$$
$$p_{ad} = a_1d_1 + a_2d_2 = 3\times(-4) + 1\times0 = -12$$
**Lưu ý**: phương pháp Dot Product này không tốt vì có thể phải xử lý số rất lớn trong khoảng $-\infty +\infty$
* ***Cosine Similarity:***
Cosine Similarity của 2 vector $a,b$ được xác định bằng công thức:
$$cosine(a,b) = \frac{a \cdot b}{|a||b|} = \frac{\sum_i{a_ib_i}}{\sqrt{\sum_i{a_i^2}}\sqrt{\sum_i{b_i^2}}} = \frac{a_1b_1 + a_2b_2 + ... + a_nb_n}{\sqrt{a_1^2+a_2^2+…+a_n^2}\sqrt{b_1^2+b_2^2+…+b_n^2}}$$
-- Nếu $cosine(a,b)$ càng gần 1: 2 vector $a,b$ càng giống nhau
-- Nếu $cosine(a,b) = 0$: 2 vector $a,b$ vuông góc
-- Nếu $cosine(a,b)$ càng gần -1: 2 vector $a,b$ ngược chiều
Ví dụ: nếu $cosine(a, b) = 0.8$: ta nói 2 vector $a, b$ giống nhau 80%
<center>
<img src="https://i.imgur.com/2CQkfiU.png">
</center>
**Lưu ý**: Phương pháp này tốt hơn vì có thể dễ quản lý số nhỏ.
### 4. Matrix:
#### 4.1. Definition:
Là tập các số được sắp xếp thành hình
* List item
* List item
chữ nhật, từ đây có thể thấy: ma trận là tập hợp của các vector hàng hoặc vector cột được sắp xếp lại theo hàng hoặc cột.
<center>
<img src="https://i.imgur.com/N7WtYOY.png" height="200">
</center>
**Quy ước:**
- $A_{ij}$ là phần tử nằm ở hàng $i$, cột $j$ của ma trận A
- $A_{i*} = [A_{i1}, A_{i2}, ..., A_{in}]$ là hàng $i$ của ma trận A
- $A_{*j} = \begin{bmatrix}
A_{1j}\\
A_{2j}\\
...\\
A_{mj}\\
\end{bmatrix}$ là cột $j$ của ma trận A
Từ quy ước trên suy ra:
$$A = \begin{bmatrix}
A_{1*}\\
A_{2*}\\
...\\
A_{m*}\\
\end{bmatrix} = [A_{*1}, A_{*2}, ..., A_{*n}]$$
#### 4.2. Transpose:
**Định nghĩa:** Cho $A$ là ma trận kích thước $m \times n$, ma trận chuyển vị của $A$, ký hiệu $A^T$, là ma trận tạo ra bằng cách xoay ma trận $A$ theo trục đường chéo chính
<center>
<img src="https://i.imgur.com/UNBc78E.gif" height="200">
</center>
**Các tính chất:**
- $A^T$ có kích thước $n \times m$
- $(A^T)^T = A$
- $A_{ij}^T = A_{ji}$
- $A^T_{i*} = A_{*i}$
- $A^T_{*j} = A_{j*}$
#### 4.3. Matrix Multiplication:
Tích của 2 ma trận $A(l \times m)$ và $B(m \times n)$ là ma trận $C(l \times n)$ với các phần tử được xác định như sau:
**Phần tử ở dòng i, cột j của ma trận C = tích chấm của dòng i của ma trận A với cột j của ma trận B**
<center>
<img src="https://i.imgur.com/ZiFd9HT.png" height=300>
</center>
**Lưu ý**: Một số quy ước ta phải chú ý

## II. Numpy:
### 1. Giới thiệu:
**Numpy** là thư viện hỗ trợ tính toán khoa học, cung cấp các kiểu dữ liệu mảng nhiều chiều cùng với rất nhiều hàm tính toán trên mảng (bao gồm các thao tác xử lý về toán học, logic, sắp xếp, I/O, đại số tuyến tính, thống kê ...)
### 2. Operations:
#### 2.1. Array creation:
* 1D Array:
import numpy as np
Interger 1D array
a = np.array([1, 3, 4, 5, 6])
a = np.array([1, 3, 4, 5, 6.1], dtype=int)
print(a)
print(type(a))
print(*a)
Float 1D array
a = np.array([1, 2, 3], dtype=float)
print(a)
a = np.array([1, 2, 3.])
print(a)
String 1D array
a = np.array(['hello', 'cotai', 9, 1.1])
print(a)
* 2D Array - Matrix:
a = np.array([[1, 2, 3],[4, 5, 6]])
print(a)
a = np.array([1,2,3])
b = np.array([4,5,'6'])
c = np.array([a, b])
print ( c )
* 3D Array:
a = np.array([ [[1,2], [3,4]] , [[1,3],[2,4]] , [[3,5],[2,6]] ])
print(a)
* Convert array to list
a = a.tolist()
print(a, type(a))
#### 2.2. Len & size:
```python=
import numpy as np
a = np.array([1,2,3,4,5,6])
b = np.array([[0,1,2,3,4],
[2,4,6,8,10],
[3,5,7,9,11],
[-1,0,-2,8,3]])
c = np.array( [ [[1,2],[3,4]] , [[1,3],[2,4]] , [[3,5],[2,6]] ] )
# size: total of elements/items
print(a.size, b.size, c.size)
# length: number of items of first dimension
print(len(a), len(b), len(c))
```
#### 2.3. Shape:
Là các thông tin về hình dạng của **vector / matrix / tensor**
```python=
import numpy as np
a = np.array([1,2,3,4,5,6])
b = np.array([[0,1,2,3,4],
[2,4,6,8,10],
[3,5,7,9,11],
[-1,0,-2,8,3]])
# shape
print(a.shape, type(a.shape))
print(b.shape, type(b.shape))
```
***
# SESSION 02: COMMON NUMPY FUNCTIONS & MATHPLOTLIB
## Kiến thức cần nhớ:
### 1. sum, mean, min, max:
* sum(): hàm tính tổng
```python=
import numpy as np
a = np.array([0, 1, 2, 3],
[2, 4, 5, 1],
[1, 1, 2, 3],
[1, 1, 1, 1])
np.sum(a)
a.sum()
np.sum(a, axis = 0) # Tính tổng trên cột => cột: axis = 0
np.sum(a, axis = 1) # Tính tổng trên hàng => hàng: axis = 1
a.sum(axis = 0)
a.sum(axis = 1)
```
**Lưu ý 01:** ta chỉ dùng `a.sum()` khi a đã là `np.array()`còn nếu không phải thì ta phải dùng `np.sum()`
**Lưu ý 02:** ta cần nhớ axis = 0 là cột và axis = 1 là hàng.
Tương tự với hàm `sum()`, ta sẽ áp dụng tương tự với các hàm còn lại:
* mean(): hàm tính trung bình
* min(): hàm tìm giá trị nhỏ nhất
* max(): hàm tìm giá trị lớn nhất
***
# SESSION 03: PANDAS & DATA ANALYSIS
## Kiến thức cần nhớ:
### 1. Pandas:
Là thư viện `Python` dùng để phân tích dữ liệu `(DataAnalysis)`, được xây dựng dựa trên `Numpy`, với hai cấu trúc dữ liệu chính là `Series (1D)` và `DataFrame (2D)`.
* **Series (1D):** là kiểu cấu trúc dữ liệu một chiều, tương ứng với một dòng hay một cột của matrix (2D array) hoặc table.
* Row Access:
* loc:
```python=
import pandas as pd
data = {'name' : ["An", "Bình", "Châu", "Nam", "Mai"],
'grade': [ 7, 6, 5, 7, 9],
'class': ['10A1', '10A2', '10A3', '10B', '10C']}
df = pd.DataFrame(data) # Create the initial dataframe
df = pd.DataFrame(data, index=[1,0,2,3,4]) # Create the dataframe with the specific number index
df = pd.DataFrame(data, index=['a1', 'a2', 'a3', 'b', 'c']) # Create the dataframe with the alphabet index
r = df.loc[0] # Lấy ra thông tin dòng có index thứ 0 cho trước
# r = df.loc[-1] # error (sai vì index -1 không tồn tại)
r = df.loc[0:2] # in ra các dòng từ index 0 đến index 2 (CTTQ: r = df.loc[a:b])
r = df.loc[[0,2]] # in ra các dòng có vị trí 0 và vị trí 2 (CTTQ: r = df.loc[[a, b, c, ...]])
r = df.loc['a3', ['name', 'grade']] # in ra dòng có index a3 và cột 'name' và cột 'grade' (CTTQ: r = df.loc[[index_row_1, index_row_2, ...], [name_col1, name_col2, ...]])
print(r) # in ra dòng
print(type(r)) # in ra kiểu dữ liệu của cột (Series hay DataFrame) (<class 'pandas.core.series.Series'> hay <class 'pandas.core.frame.DataFrame')
df.loc[1, 'grade'] = 8 # Sửa thông tin trên dòng index 1 và cột 'grade' (CTTQ: df.loc[index, name_col] = A)
df.loc[1] = ['An', 8, '10A1'] # Sửa thông tin nguyên một dòng có index 1 (CTTQ: df.loc[index] = ['A', 'B', 'C', ...])
df # in ra bảng DataFrame
```
* iloc:
```python=
import pandas as pd
data = {'name' : ["An", "Bình", "Châu", "Nam", "Mai"],
'grade': [ 7, 6, 5, 7, 9],
'class': ['10A1', '10A2', '10A3', '10B', '10C']}
df = pd.DataFrame(data, index=[1,2,0,3,4]) # Create DataFrame with the specific index
r = df.iloc[0] # in ra thông tin dòng thứ nhất trong DataFrame (không liên quan đến index mình tự tạo mà nó theo quy chuẩn index ngầm từ 0 đến n)
r = df.iloc[-1] # in ra thông tin dòng cuối cùng trong DataFrame (kiểu dữ liệu của index trong hàm iloc() giống kiểu dữ liệu số trong Numpy() nên mình có thể dùng số âm được)
r = df.iloc[0:2] # slicing dòng 0 đến 2
r = df.iloc[[0,2]] # dòng thứ 0 và thứ 2
r = df.iloc[0][['name', 'grade']] # dòng thứ 0 và cột 'name' và 'grade'
r
df.iloc[1]['grade'] = 8 # not change # không nên dùng cách này để đổi khuyến khích nên dùng loc()
df.iloc[1] = ['An', 8, '10A1'] # đổi thông tin trên nguyên dòng
df
```
* loop:
```python=
import pandas as pd
data = {'name' : ["An", "Bình", "Châu", "Nam", "Mai"],
'grade': [ 7, 6, 5, 7, 9],
'class': ['10A1', '10A2', '10A3', '10B', '10C']}
df = pd.DataFrame(data) # Create DataFrame
df = pd.DataFrame(data, index=['a1', 'a2', 'a3', 'b', 'c']) # Create DataFrame with the specific index
for i in df.index: # loop qua từng dòng có index thứ i
print(i, df.loc[i, 'name']) # in ra tên của học sinh ở từng dòng thứ i -> cách 1
for i in range(df.shape[0]):
print(i, df.iloc[i]['name']) # lấy số dòng của df -> cách 2
```
* Column Access:
* Get Column:
```python=
import pandas as pd
data = {'name': ["An", "Bình", "Châu", "Nam", "Mai"],
'grade': [7, 6, 5, 7, 9],
'class': ['10A1', '10A2', '10A3', '10B', '10C']}
df = pd.DataFrame(data)
# grades = df['name']
grades = df['name'].values
print(grades)
print(type(grades))
# grades
# df = df[['name', 'grade']]
# df = df[['name', 'grade']].values
# df
```
* Add Column:
```python=
import pandas as pd
data = {'name': ["An", "Bình", "Châu", "Nam", "Mai"],
'class': ['10A1', '10A1', '11A', '11A', '11C'],
'math': [ 7, 6, 5, 7, 9],
'physics': [ 8, 9, 6, 9, 8],
'chemistry':[ 8, 8, 9 , 10, 9]
}
df = pd.DataFrame(data)
df['gender'] = ['Nữ', 'Nam', 'Nam', 'Nam', 'Nữ']
df['average'] = (df['math'] + df['physics'] + df['chemistry']) / 3
df
```
* Filter:
```python=
import pandas as pd
data = {
"name": ["An", "Bình", "Châu", "Nam", "Mai"],
"grade": [7, 6, 5, 7, 9],
"class": ["10A1", "10A2", "10A3", "10B", "10C"],
"gender": ["Nữ", "Nam", "Nam", "Nam", "Nữ"]
}
df = pd.DataFrame(data)
# create filter
filter = df["gender"] == "Nữ"
print(filter, type(filter))
# apply filter
df[filter]
# df[df["gender"] == "Nữ"]
df[(df["gender"] == "Nam") & (df["grade"] > 6)]
# df[(df["class"] == '10B') | (df["class"] == '10C')]
# df[df["class"].isin(['10B', '10C'])]
```
* Map: dùng hàm này khi cần biến đổi dữ liệu của một cột hay tạo ra một cột mới dựa trên dữ liệu của một cột.
* Các bước thực hiện:
* Tạo `dictionary()` để quy định mapping từ data cũ sang data mới.
* Gọi hàm `map()`
* Lưu ý: Nếu giá trị bất kỳ của data cũ không nằm trong dictionary, thì giá trị mới tại đó sẽ bằng `NULL`.
* Apply: Có công dụng tương tự hàm `map` nhưng:
* Biến đổi dữ liệu dựa trên một điều kiện nào đó.
* Có thể biến đổi dữ liệu trên từng dòng.
```python=
import pandas as pd
data = {'Name': ['John', 'Jane', 'Mike', 'Lisa'],
'Salary': [50000, 60000, 70000, 80000],
'Rank': ['Employee', 'Employee', 'Employee', 'Manager']}
df = pd.DataFrame(data)
def calculate_annual_salary(row):
if row['Rank'] == 'Manager':
return row['Salary'] * 2
return row['Salary']
df['Annual Salary'] = df.apply(calculate_annual_salary, axis=1)
df
```
* **DataFrame (2D):** là kiểu cấu trúc dữ liệu 2 chiều, tương tự 2D Array hoặc table với các dòng và các cột.
* Create DataFrame:
```python=
import pandas as pd #include thư viện pandas
data = {'name' : ["An", "Bình", "Châu", "Nam", "Mai"],
'grade': [ 7, 6, 5, 7, 9],
'class': ['10A1', '10A2', '10A3', '10B', '10C']} # Mảng 2D data
df = pd.DataFrame(data) # Create dataframe
df = pd.DataFrame(data, index=[2,0,1,4,3 #nhập index bằng số
df = pd.DataFrame(data, index=['a1', 'a2', 'a3', 'c', 'c']) # nhập index bằng chữ
print(df) # in ra bảng dataframe
print(type(df)) # in ra kiểu dữ liệu data frame
df
```
* DataFrame Info:
```python=
len(df) # so hang trong dataframe
df.shape # (số hàng, số cột) của dataframe
df.columns # mảng 1 chiều tên các cột trong dataframe
df.index # RangeIndex(start = 0, stop = last row index, step = 1)
df.dtypes # in ra kiểu dữ liệu của từng cột
df.info() # in ra thông tin chi tiết cụ thể của bảng dataframe
```
### 2. Data Analysis:
-- Là quá trình chuyển đổi ***dữ liệu thô*** (dữ liệu chưa qua xử lý) sang các ***dữ liệu mềm*** hữu ích hơn, áp dụng và phân tích chuyên môn.
-- Quá trình phân tích dữ liệu gồm có các bước cơ bản như sau:
* Collecting Data / Loading Data:
```python=
from google.colab import drive
drive.mount('/content/drive', force_remount=True)
```
```python=
import pandas as pd
df = pd.read_csv('/content/drive/My Drive/dataset_clean.csv')
df
```
* Viewing data:
```python=
df.head()
df.tail()
df.sample(3)
df.columns
```
* Data Info:
```python=
df.info()
df.describe() # mô tả chi tiết các cột dữ liệu số không làm cho dạng chữ
```
* Count Values:
```python=
df['Gender'].unique()
df['Gender'].value_counts()
df['HasChildren'].unique()
df['HasChildren'].value_counts()
```
* Check NULL Data:
```python=
df.isna()
df.isnull()
df.isna().sum()
df.isnull().sum()
df.shape
```
* Cleaning Data (làm sạch dữ liệu: missing, duplicated values, logical errors, grammar errors,..) $\to$ chỉnh dữ liệu lại đẹp và sạch hơn để dễ dàng tổng hợp thông tin
* Remove rows with NULL values:
```python=
df = df.dropna() # xoá tất cả các dòng (Cách 1)
df.dropna(inplace=True) # có giá trị nan !!! (Cách 2)
df
df.dropna(subset=['Resource', 'IsSoftwareDev', 'AttendedBootcamp'], inplace = True)
df.shape
```
* Replace NULL Values:
```python=
df['HasChildren'].fillna(0, inplace=True)
df['ChildrenNumber'].fillna(0, inplace=True)
df['CountryCitizen'].fillna('Somewhere', inplace=True)
df['Gender'].fillna('other', inplace=True)
df['Income'].fillna(0, inplace=True)
value = df['Age'].mean()
value = df['Age'].median() # Khi chay meadian() phai load lai du lieu
df['Age'].fillna(value, inplace=True)
```
* Duplicated Rows:
```python=
df.duplicated()
df.duplicated().sum()
df.drop_duplicates(inplace=True)
df.shape
```
* Structuring data (cấu trúc lại dữ liệu $\to$ dễ thao tác cho Bước 4)
* Aggregating data (tổng hợp, gom nhóm dữ liệu để phân tích)
```python=
df['EmploymentField'].value_counts()
df['EmploymentField'].isna().sum()
df['EmploymentField'].fillna('others', inplace=True)
df3 = df[['EmploymentField', 'Income']]
df3 = df3.groupby(['EmploymentField']).median()
df3.reset_index(inplace=True)
df3
```
* Visualizing data (Biểu hiện data bằng biểu đồ)
* Pie chart:
```python=
import plotly.express as px
px.pie(df, names='Gender')
```
* Box chart:
```python=
# px.box(df, x = 'Age') # x là biến kiểu số thì đồ thị ngang
# px.box(df, y = 'Age') # y là biến kiểu số thì đồ thị dọc
# px.box(df, y = 'Gender') # x hoặc y phải là biến kiểu số
# px.box(df, x = 'Gender', y='Age')
# px.box(df, x = 'Gender', y='Income', color='HasChildren')
px.box(df[(df['Income'] < 200000) & (df['Income'] > 0)], x = 'Gender', y='Income', color='HasChildren')
```
* Histogram:
```python=
import plotly.express as px
# px.histogram(df, x="JobInterest") # nếu chỉ truyền x kiểu text: đếm số dòng
# px.histogram(df, x='JobInterest', y='Income') # lấy tổng cột kiểu số
# px.histogram(df, x='JobInterest', color='AgeRange')
# px.histogram(df, x='JobInterest', color='Gender')
df['JobPref'].isna().sum()
df['JobPref'].fillna('Dont know', inplace=True)
px.histogram(df, x="JobPref")
```
```python=
px.histogram(df3, x='EmploymentField', y='Income')
```
* Bar chart:
```python=
px.bar(df3, x='EmploymentField', y='Income')
```
* Optionals (liên quan đến việc dùng các mô hình XSTK hay Machine Learning để dự đoán)
* Modeling
* Evaluating
* Deployment
### 3. Data Types:
-- Khi phân tích dữ liệu, ta cần phân biệt các loại dữ liệu sau:
* `Free Text`: kiểu dữ liệu này không thường được dùng để phân tích thông tin (Examples: Name, Address, Hobbies, Habit, ...)
* `Numerical/Quantiative Data`: là những dữ liệu dạng số và có thể dùng để tính toán, so sánh (Examples: doanh số, nhiệt độ, chiều cao, cân nặng, ...). Và được chia thành hai loại như sau:
* **Discrete Data**: Số nguyên (If you can count it, it is discrete)
* **Continuous Data**: Số thực (If you can measure it, it is continous)
* `Categorical/Qualitative Data`: là kiểu dữ liệu dạng số hoặc dạng chữ, dùng để phân loại & không thể tính toán, gồm hai loại:
* **Nominal Data**: là dữ liệu không có thứ tự, không thể so sánh (Examples: Gender (Female/Male), Color(Red, Green, ...)
* **Ordinal Data**: là dữ liệu có thứ tự, có thể so sánh, xếp hạng với nhau (Examples: nhận xét, đánh giá, điểm số, ...)
**Lưu ý**: Khái niệm `Data Types` trong `Data Analysis` khác với `Data Types` trong lập trình bình thường (int, float, double, str, ...)
***
# SESSION 04: KNN & KMEANS
## Kiến thức cần nhớ:
### 1. Machine Learning Algorithm:
Được chia thành hai nhóm chính:
* Học có giám sát (Supervised Learning): Develop predictive model based on both input and output data. Các thuật toán này được dùng để giải hai loại bài toán:
* Classification: là bài toán phân loại dữ liệu. VD: phân loại các chữ số viết tay, phân loại các loài hoa iris, ...
* Regression: là bài toán dự báo ra một hoặc nhiều số thực. VD: dự đoán cân nặng dựa vào chiều cao, dự đoán doanh thu và lợi nhuận dựa vào chi phí sản xuất, ...
* Học không có giám sát (Unsupervised Learning): Group and interpret data based only on input data.
* Clustering: bài toán gom nhóm. VD: chia một tập khách hàng thành các nhóm khác nhau (VIP, Khá giả, bình dân, ...)
### 2. KNN:
-- Là thuật toán phân loại dữ liệu mới dựa trên dữ liệu đã được huấn luyện: đầu ra của một điểm dữ liệu mới sẽ được xác định trên k điểm dữ liệu huấn luyện gần nhất.
* Create Data:
* Visualize Data:
### 3. KMEANS:
# SESSION 05: DERIVATIVES, GRADIENT DESCENT, PLOTLY
## Kiến thức cần nhớ:
### I. Derivative, Gradient:
#### 1. Derivative:
-- Là đại lượng cho biết sự biến thiên (độ tăng hay giảm) của một đồ thị hàm số f(x) bất kỳ: $f'(x) = \frac{\partial y}{\partial x} = lim_{\Delta x \to 0} \frac{f(x + \Delta x) - f(x)}{\Delta x}$
* $f'(x) > 0$ : hàm đồng biến (x tăng $\to$ y tăng, x giảm $\to$ y giảm)
* $f'(x) = 0$ : x "có thể" là ***điểm cực trị*** (cực đại địa phương (thường nằm trong một đoạn (khoảng) / toàn cục (trên cả tập xác đinh của f) hay cực tiểu địa phương ([a, b] hay (a, b)) / toàn cục (trên $D_f$))
* $f'(x) < 0$ : hàm nghịch biến (x tăng $\to$ y giảm, x giảm $\to$ y tăng)
-- Độ lớn (module) của $f'(x)$ chính là độ dốc của đồ thị.
#### 2. Extremum:
-- Cho hàm số $y = f(x)$, nếu tồn tại số $h > 0$ sao cho:
* $f(x) < f(x_0)$, $\forall x \in (x_0 - h; x_0 + h)$ và $x \# x_0$ thì hàm $f(x)$ đạt cực đại tại $x_0$.
* $f(x) > f(x_0)$. $\forall x \in (x_0 - h; x_0 + h)$ và $x \# x_0$ thì hàm $f(x)$ đạt cực tiểu tại $x_0$
#### 3. . Implement:
```python=
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-5, 6, 100)
y = x**2 + 10 * np.sin(x)
plt.figure(figsize=(5, 4))
plt.xlabel('x')
plt.ylabel('y')
plt.plot(x, y)
min_idx = np.argmin(y)
plt.scatter(x[min_idx], y[min_idx])
plt.show()
```
#### 4. Gradient Vector:
-- Cho hàm nhiều biến $y = f(x_1, x_2, ..., x_n)$. Gradient Vector được xác đinh như sau:
$$\nabla f = \begin{bmatrix}
\frac{\delta f}{x_1}\\
\frac{\delta f}{x_2}\\
...\\
\frac{\delta f}{x_n}\\
\end{bmatrix}$
-- **Ý nghĩa**: Gradient Vector cho biết sự thay đổi của hàm số theo từng biến phụ thuộc $\to$ **hướng tăng nhanh nhất (fastest increase)** của hàm số.
```python=
import numpy as np
import matplotlib.pyplot as plt
def f(x1, x2):
return x1**2 + np.sin(x2)
def grad(x1, x2):
return np.array([2*x1, np.cos(x2)])
x1, x2 = 1, 1
step = 0.01
x = np.array([[x1+step,x2], [x1-step,x2], [x1,x2+step], [x1,x2-step], [x1+step,x2+step], [x1+step,x2-step], [x1-step,x2+step], [x1-step,x2-step]])
x_grad = [x1,x2] + grad(x1, x2)*step*0.6
x_grad_neg = [x1,x2] - grad(x1, x2)*step*0.6
plt.scatter(x1, x2)
plt.scatter(x[:,0], x[:,1])
plt.scatter(x_grad[0], x_grad[1])
plt.scatter(x_grad_neg[0], x_grad_neg[1])
plt.axis('equal')
plt.show()
y = f(x[:,0], x[:,1])
y_grad = f(x_grad[0], x_grad[1])
y_grad_neg = f(x_grad_neg[0], x_grad_neg[1])
print(y_grad_neg, y.min(), y.max(), y_grad)
```
### 2. Gradient Descent:
#### 1. Gradient Descent_Normal:
-- Bài toán: tìm điểm cực tiểu của hàm số $y = f(x_1, x_2, ..., x_n)$ bất kỳ
*Cách 01: Giải phương trình $\nabla f = 0$ $\to$ đa số không thể giải được.
* Cách 02 (phương pháp Gradient Descent): cho phép tìm điểm cực tiểu gần đúng của hàm số, ý tưởng chính là đi ngược hướng đạo hàm.
* Bắt đầu đi từ một vị trí bất kỳ (random) $x_0$
* Lặp n lần: $x = x - \eta \nabla_xf(x)$ cho đến khi n đủ lớn hoặc gradient gần bằng 0. ($\eta$ là tốc độ di chuyển)
#### 2. Gradient Descent_Momentum:
-- Để vượt qua các điểm cực tiểu cục bộ, thuật toán GD with Momentum tận dụng thêm nguyên tắc vật lý: quán tính
$$v_t = \eta\nabla_xf(x) + \gamma v_{t-1}$$
-- Công thức cập nhật vị trí:
$$x = x - v_t$$
với $v_0 = 0, \gamma$ là hằng số dương bé hơn $1$, và thường được chọn là $0.9$
#### 3. Gradient Descent_Advance:
```python=
import numpy as np
import matplotlib.pyplot as plt
def gradient_descent_advance(x0, epsilon, eta):
x = x0
iterations = 0
result = []
while True:
x -= eta * grad(x)
result.append(f(x))
iterations += 1
if np.abs(np.linalg.norm(grad(x))) < epsilon:
break
print(f"Iterations: {iterations}")
return np.array(result)
result = gradient_descent_advance(-1, .001, .01)
draw_graph(result)
```
### 3. Plotly:
-- Là thư viện mã nguồn mở giúp cho việc hiểu & trực quan hóa dữ liệu một cách dễ dàng, hỗ trợ nhiều kiểu đồ thị như line, scatter, histogram ...
* Express:
```python=
import plotly.express as px
df = px.data.iris()
df.head()
```
* Graph_objects:
* 3D Surface:
```python=
import plotly.graph_objects as go
import numpy as np
x = np.linspace(-2, 2, 50)
y = np.linspace(-2, 2, 30)
xx, yy = np.meshgrid(x, y)
xy = np.c_[xx.ravel(), yy.ravel()]
z = xy[:,0]**2 + xy[:,1]**2
z_2 = xy[:,0] - xy[:, 1] + .5
z = z.reshape(xx.shape)
z_2 = z_2.reshape(xx.shape)
fig = go.Figure(data=[go.Surface(x=x, y=y, z=z), go.Surface(x = x, y = y, z = z_2)])
fig.show()
```
* 3D Scatter:
```python=
import plotly.graph_objects as go
import plotly.express as px
import numpy as np
p = np.array([[0,0,1],
[1,-1,-1],
[2,1,-1],
[3,-2,2],
[4,2,-1]])
x = [10, 11, 12, 13, 14]
y = [0,-1, 1,-2, 2]
z = [1, 0,-1, 2,-1]
fig = go.Figure(data=[go.Scatter3d(x=x, y=y, z=z, mode = 'markers'), go.Scatter3d(x=p[:, 0], y=p[:,1], z=p[:,2], mode = 'markers')])
fig.show()
```