Table of Content

Important

I. Series in Pandas

Nhắc lại: Series là một cấu trúc dữ liệu 1 chiều, có thể lưu trữ bất kỳ kiểu dữ liệu nào (số, chuỗi, đối tượng Python…). Mỗi phần tử trong Series có một index (chỉ mục) và một value (giá trị). Ngoài ra, Series còn có thể có tên để mô tả nội dung dữ liệu.

1. Simple functions

Create a series

Tạo danh sách số nguyên: Ví dụ dưới đây tạo một Series tên là num_dropped từ danh sách [5, 7, 5, 1, 6]:

import pandas as pd
data = pd.Series([5, 7, 5, 1, 6], name='num_dropped')

Kết quả:

IndexValue
05
17
25
31
46
  • data.name: 'num_dropped'
  • data.index: RangeIndex(start=0, stop=5, step=1)
  • data.values: array([5, 7, 5, 1, 6]) Khi không truyền index, Pandas sẽ tự tạo chỉ mục mặc định từ 0 đến n-1.

Tạo Series với index tùy chỉnh: Ví dụ tạo một Series chứa tên các ngôn ngữ lập trình, gắn index theo ký tự viết tắt:

import pandas as pd
data = pd.Series(
    ['C++', 'Golang', 'Java', 'Python', 'Swift'],
    index=list('CGJPS'),
    name='Programming Language'
)

Kết quả:

IndexValue
CC++
GGolang
JJava
PPython
SSwift
  • data.name: 'Programming Language'
  • data.index: Index(['C', 'G', 'J', 'P', 'S'])
  • data.values: array(['C++', 'Golang', 'Java', 'Python', 'Swift'], dtype=object) Index tùy chỉnh giúp dữ liệu dễ đọc hơn và phù hợp với ngữ cảnh sử dụng.

Lấy giá trị trong Series (Get Rows)

Có nhiều cách để truy cập giá trị: 1. Truy cập bằng chỉ số (index vị trí)

print(data[0])  # 5
print(data[1])  # 7
LệnhGiá trị
data[0]5
data[1]7
data[2]5
data[3]1
data[4]6
2. Truy cập bằng **.loc[]** (theo nhãn index)
print(data.loc[0])  # 5
print(data.loc[1])  # 7

Cú pháp này dùng cho label-based indexing (theo tên index).

3. Lấy nhiều hàng liên tiếp

result = data.loc[2:3]

Output:

IndexValue
25
31
4. Lấy nhiều hàng theo vị trí (slicing)
result = data[2:3]

Output:

IndexValue
25
5. Lọc theo điều kiện giá trị
result = data[data.between(3, 6)]

Output

IndexValue
05
25
46
result = data[data > 5]

Output

IndexValue
17
46
  • Câu hỏi gợi mở
    • Khi nào nên dùng .loc[] và khi nào dùng slicing [start:end]?

      • Dùng **.loc[]** khi bạn muốn truy cập theo nhãn index (label-based indexing).

        Ví dụ: nếu index là 'A', 'B', 'C', thì data.loc['A'] sẽ lấy đúng giá trị có nhãn 'A'.

        .loc[start:end] bao gồm cả end khi slicing.

      • Dùng slicing **[start:end]** khi bạn muốn truy cập theo vị trí (position-based indexing) hoặc khi index là số mặc định từ 0.

        Ví dụ: data[0:3] sẽ lấy phần tử ở vị trí 0, 1, 2 (không bao gồm vị trí 3).

    • Làm thế nào để lấy đồng thời các giá trị có index cụ thể (ví dụ [0, 2, 4])?

      Cách 1: Dùng .loc[] (theo nhãn index). Ví dụ: result = data.loc[[0, 2, 4]]

      Cách 2: Dùng .iloc[] (theo vị trí). Ví dụ: result = data.iloc[[0, 2, 4]]


Drop a row

Trong Pandas Series, có thể dùng phương thức .drop() để xóa một hoặc nhiều phần tử dựa trên index. image 62.png Xóa 1 phần tử:

data.drop('C')

Xóa nhiều phần tử:

data.drop(['C', 'P'])

Xóa phần tử theo chỉ số (position) image 1 28.png Xóa một phần tử:

data.drop(2)

Xóa nhiều phần tử:

data.drop([2, 4])

Insert a row

Trong Pandas Series, có thể chèn một phần tử mới bằng cách gán giá trị cho một index mới. Lấy lại data Programming Language Gán giá trị 'Kotlin' vào index 'K':

data['K'] = 'Kotlin'

Để sắp xếp các index theo thứ tự chữ cái:

data.sort_index(inplace=True)

image 2 26.png

Hoặc đối với Series số nguyên ta có thể thực hiện như sau: Giả sử muốn chèn giá trị 9 giữa index 23:

data[2.5] = 9

Sau đó sắp xếp lại index

data.sort_index(inplace=True)

Reset lại index để index liên tục từ 0

data.reset_index(drop=True, inplace=True)

image 3 24.png

Common Pandas functions

Pandas cung cấp nhiều hàm tích hợp sẵn để tính toán nhanh trên Series.

HàmÝ nghĩaKết quả
data.min()Giá trị nhỏ nhất1
data.max()Giá trị lớn nhất7
data.sum()Tổng các phần tử24
data.mean()Giá trị trung bình4.8
data.std()Độ lệch chuẩn2.28
data.var()Phương sai5.2
data.idxmax()Index của giá trị lớn nhất1
data.argmax()Index của giá trị lớn nhất (giống idxmax)1
Đếm từ khóa 'Java'
data.str.count('Java')
IndexCount
C0
G0
J1
P0
S0
Đếm ký tự 'a'
data.str.count('a')
  • .str.count(pattern) trả về số lần pattern xuất hiện trong mỗi phần tử.
  • pattern có thể là chuỗi thông thường hoặc regex (biểu thức chính quy).
  • Có thể kết hợp với các hàm .str.contains(), .str.replace(), .str.lower() để xử lý chuỗi linh hoạt hơn. |Index|Count| |---|---| |C|0| |G|1| |J|2| |P|0| |S|0|

Sử dụng .str.upper() để chuyển toàn bộ ký tự sang chữ hoa:

data.str.upper()
IndexValue
CC++
GGOLANG
JJAVA
PPYTHON
SSWIFT
Sử dụng .replace() để thay "Java" bằng "C#":
data.replace('Java', 'C#')
IndexValue
CC++
GGolang
JC#
PPython
SSwift
  • Câu hỏi gợi mở
    • Sự khác nhau giữa idxmax()argmax() trong Pandas là gì?
      • idxmax() : Trả về Nhãn index (label) của phần tử có giá trị lớn nhất. Hoạt động theo index của Pandas, không phụ thuộc vị trí.
      • argmax() : Trả về: Vị trí số nguyên (integer position) của phần tử lớn nhất. Dựa trên dữ liệu .values của Series, không quan tâm label index.

Addition Between Two Series

Tạo 2 Series ban đầu

import pandas as pd
center1 = pd.Series(
    [12, 23, 31, 11, 9],
    index=['C++', 'Golang', 'Java', 'Python', 'Swift'],
    name='num_registered'
)
center2 = pd.Series(
    [42, 18, 44, 49, 27],
    index=['C++', 'Golang', 'Java', 'Python', 'Swift'],
    name='num_registered'
)

Cộng hai Series

total = center1 + center2

center1

IndexValue
C++12
Golang23
Java31
Python11
Swift9
center2
IndexValue
------
C++42
Golang18
Java44
Python49
Swift27
total
IndexValue
------
C++54
Golang41
Java75
Python60
Swift36
  • Khi cộng hai Series, Pandas sẽ ghép theo index. Nếu một index có trong Series này nhưng không có trong Series kia → kết quả sẽ là NaN.

    image 4 19.png

    image 5 17.png

  • Có thể dùng .add() với tham số fill_value để thay NaN bằng giá trị mặc định:


Group Values

Dùng .groupby(level=0) để nhóm theo nhãn index:

data.groupby(level=0).sum()

groupby(level=0) thường dùng khi Series có index trùng nhau và muốn tính toán theo từng nhóm index.

Indexnum_dropped
C++5
Golang3
Java2

Nhóm dữ liệu dựa trên điều kiện data > 3:

data.groupby(data > 3).sum()

Khi nhóm theo điều kiện, kết quả index sẽ là True/False hoặc giá trị phân loại.

Điều kiện (data > 3)num_dropped
False6
True4

Lấy nhóm cụ thể và tính tổng

data['C++'].sum()     # 5
data['Golang'].sum()  # 3
data['Java'].sum()    # 2

Ngoài .sum(), có thể dùng .mean(), .count(), .max(), v.v.

2. 1D interpolation

Giới thiệu bài toán nội suy: Cho hai điểm dữ liệu đã biết (x₁, y₁)(x₂, y₂), cần tìm giá trị y tại các vị trí trung gian u, v, p, q trên trục x.

image 6 16.png

Phương pháp 1 – Nearest Neighbor (Láng giềng gần nhất)

Ý tưởng:

  • Với mỗi điểm cần tìm (u, v, p, q), tính khoảng cách đến x₁x₂.
  • Chọn giá trị y của điểm dữ liệu gần hơn. Đặc điểm:
  • Dễ tính toán.
  • Tạo ra đường nội suy bậc thang (step-like), không trơn tru.
  • Không phù hợp khi yêu cầu độ mượt cao. image 7 13.png Công thức:
y(u) = y₁ nếu |u - x₁| < |u - x₂|, ngược lại y₂

Phương pháp 2 – Linear Interpolation (Nội suy tuyến tính)

Ý tưởng:

  • Nối thẳng hai điểm (x₁, y₁)(x₂, y₂).
  • Giá trị y tại các vị trí trung gian được xác định theo tỷ lệ khoảng cách. Đặc điểm:
  • Kết quả mượt và liên tục.
  • Dễ áp dụng cho dữ liệu biến đổi tuyến tính giữa các điểm. image 8 13.png Cách làm: Giả sử ta có hai điểm:
  • Phương trình đường thẳng: y = a x + b \tag{1} Xác định hệ số góc . Từ hai điểm A và B: a = \frac{y_2 - y_1}{x_2 - x_1} \tag{2} Xác định tung độ gốc . Thay điểm A vào (1): b = y_1 - \frac{y_2 - y_1}{x_2 - x_1} x_1 \tag{3} Thay (2) và (3) vào (1): y = \frac{y_2 - y_1}{x_2 - x_1} x + \left( y_1 - \frac{y_2 - y_1}{x_2 - x_1} x_1 \right) \tag{4} Biến đổi thu gọn: Gọi: Từ đó ta có Công thức nội suy tuyến tính: image 9 12.png

  • Nearest neighbor nhanh và dễ nhưng không mượt, phù hợp khi dữ liệu là giá trị rời rạc, không cần tính liên tục.
  • Linear interpolation phù hợp hơn khi dữ liệu thay đổi dần đều. Ví dụ bài toán Cho bảng giá trị với , trong đó một số giá trị bị thiếu (None). Cần tìm giá trị tại dựa trên 2 điểm lân cận:
  • image 10 11.png 1. Nearest Neighbor Interpolation Khoảng cách từ đến:
  • : khoảng cách = 1
  • : khoảng cách = 1 Trường hợp bằng nhau, thường chọn giá trị bên trái (hoặc theo quy tắc định sẵn). Kết quả:

2. Linear Interpolation Công thức: Thay:x_1 = 1, \quad y_1 = 2.2$$x_2 = 3, \quad y_2 = 2.7$$x = 2 Tính:f(2) = 2.2 + \frac{2 - 1}{3 - 1} \cdot (2.7 - 2.2)$$f(2) = 2.2 + 0.5 \cdot 0.5 = 2.45 Kết quả:

Missing Values trong Pandas Series

Tạo một Series có giá trị thiếu

import pandas as pd
import numpy as np
data = pd.Series(
    [1, 6, 3, 8, np.nan, 7, np.nan, 2],
    name='num_dropped'
)
IndexValue
01
16
23
38
4NaN
57
6NaN
72
Khi ta dùng các hàm thống kê của Pandas thì nó mặc định bỏ qua các giá trị NaN khi tính toán:
data.min()     # 1
data.max()     # 8
data.sum()     # 27
data.mean()    # 4.5
data.std()     # 2.88
data.idxmax()  # 3
data.argmax()  # 3

Xóa giá trị thiếu:

data.dropna()
IndexValue
01
16
23
38
57
72
Điền giá trị cố định:
data.fillna(1.0)
IndexValue
01.0
16.0
23.0
38.0
41.0
57.0
61.0
72.0
Nội suy giá trị:
data.interpolate()
IndexValue
01.0
16.0
23.0
38.0
47.5
57.0
64.5
72.0

3. Case study: Temperature forecasting

Dataset

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv('weatherHistory2D.csv')
df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 96453 entries, 0 to 96452
Data columns (total 2 columns):

Column Non-Null Count Dtype

0 Formatted Date 96453 non-null object
1 Temperature (C) 96453 non-null float64
dtypes: float64(1), object(1)
memory usage: 1.5+ MB

  • Cột **Date**: Ngày quan sát.
  • Cột **Temperature (°C)**: Nhiệt độ trung bình ngày (theo °C).
  • Dữ liệu gồm nhiều năm, ghi nhận nhiệt độ theo ngày.

- Data: Dữ liệu mô tả thực tế.

  • Meta data: Dữ liệu để mô tả data.

Fill missing data

Điền bằng giá trị trung bình (**fillna(mean)**)

mean = df_train['Temperature (C)'].mean()
df_train = df_train.fillna(mean)

image 11 11.png Nội suy (**interpolate()**)

df_train = df_train.interpolate()

image 12 10.png

4. Noise Reduction

Khi làm việc với dữ liệu chuỗi thời gian (time series), đặc biệt là dữ liệu nhiệt độ, tốc độ gió, độ ẩm… thường tồn tại nhiễu – các dao động ngẫu nhiên không mang thông tin xu hướng. Giảm nhiễu (Noise Reduction) giúp:

  • Làm mượt đường biểu diễn.
  • Dễ quan sát xu hướng dài hạn.
  • Giảm tác động của biến động đột ngột (outlier) tới mô hình học máy.

Moving Average – Trung bình trượt

SMA (Simple Moving Average):

  • SMA (Simple Moving Average): Lấy trung bình của k giá trị gần nhất.

EMA (Exponential Moving Average):

  • Gán trọng số lớn hơn cho các giá trị mới hơn.
  • Ít bị trễ (lag) so với SMA. Ví dụ:
data_sma = data.rolling(window=5).mean()
  • window=5: lấy trung bình của 5 điểm liên tiếp.
  • Kết quả: đường biểu diễn mượt hơn, giảm các dao động nhỏ. image 13 9.png

II. DataFrame

1. Simple functions

Create a dataframe

Đọc dữ liệu advertising_simple.csv :

import pandas as pd
df = pd.read_csv('advertising_simple.csv')
print(df)

image 14 9.png Các thành phần quan trọng của DataFrame

Thành phầnCách truy cậpMô tả
**df.index**df.indexDanh sách chỉ số (số thứ tự) của các hàng.
**df.columns**df.columnsDanh sách tên các cột.
Cột cụ thểdf['Newspaper'] hoặc df.NewspaperTruy xuất dữ liệu của một cột.
Đảo cột thành dòng (chuyển vị dataframe):
df_t = df.T
print(df)

image 15 9.png

Sorting

Sắp xếp theo một cột

import pandas as pd
df = pd.read_csv('advertising_simple.csv')
df.sort_values('Sales')
  • **sort_values('Sales')**: sắp xếp DataFrame tăng dần dựa trên giá trị trong cột Sales.

  • Mặc định ascending=True → tăng dần.

    Nếu muốn giảm dần: df.sort_values('Sales', ascending=False).

📌 Kết quả: bảng được sắp từ giá trị Sales nhỏ nhất đến lớn nhất.

image 16 7.png

Sắp xếp theo nhiều cột

df.sort_values(['Newspaper', 'Sales'])
  • Danh sách cột: Pandas sẽ sắp xếp theo thứ tự ưu tiên trong list.
  • Bước 1: sắp theo Newspaper tăng dần.
  • Bước 2: nếu giá trị Newspaper bằng nhau → sắp tiếp theo Sales. 📌 Kết quả: ưu tiên Newspaper, nếu trùng thì xét Sales. Note: image 17 7.png
  • Không thay đổi dữ liệu gốc trừ khi dùng inplace=True.
  • Có thể kết hợp ascending=[True, False] để mỗi cột có thứ tự riêng.

Add a column

Thêm một cột mới vào DataFrame

import pandas as pd
df = pd.read_csv('advertising_simple.csv')
df['ID'] = list(range(2, 10))
  • **df['ID']**: tạo cột mới tên là ID.
  • **list(range(2, 10))**: sinh dãy số từ 2 → 9 để gán vào cột ID.
  • Lúc này df.columns sẽ có thêm ID ở cuối. image 18 7.png Đặt một cột làm index
df = df.set_index('ID')
  • **set_index('ID')**: đặt cột ID làm chỉ số dòng (index) mới.
  • Nếu không gán lại hoặc dùng inplace=True thì DataFrame gốc không thay đổi.
  • Index mới thay thế df.index, và cột ID biến mất khỏi df.columns. image 19 7.png 📌 Kết quả:
  • Index hiển thị các giá trị từ cột ID.
  • Cột ID không còn nằm trong phần dữ liệu chính nữa.

Get values

  • df.columns → Lấy danh sách tên cột.
  • df.index → Lấy danh sách index (nhãn hàng).
  • df['Newspaper'] → Lấy dữ liệu của cột Newspaper. Truy cập dữ liệu theo cột:
df.Radio
df['Radio']

→ Trả về Series của cột Radio. image 20 6.png

Tuy nhiên nên dùng

df[’Radio’]: _như là chỉ số (dictionary-style indexing)_→ vì tránh được việc tên cột có ký tự đặc biệt hoặc khoảng trắng.
Ngược lại: df.Radio như là thuộc tính (attribute-style access).

Duyệt các dòng của dataframe

df = pd.read_excel(folder + '/Data/Data.xls', sheet_name = 'Insurance')
df = df.head()
for idx, row in df.iterrows():
    print(f'* Dòng {idx}:')
    print(row, '\n')

==Quy tắc: Dòng trước cột sau==

Bởi vì df của chúng ta có cấu trúc là:

* Dòng 0:
age                19
sex            female
bmi              27.9
children            0
smoker            yes
region      southwest
charges     16884.924
Name: 0, dtype: object 
* Dòng 1:
age                18
sex              male
bmi             33.77
children            1
smoker             no
region      southeast
charges     1725.5523
Name: 1, dtype: object 
* Dòng 2:
age                28
sex              male
bmi              33.0
children            3
...
region      northwest
charges     3866.8552
Name: 4, dtype: object 

2. Example 1: Weather dataset

Quay lại với dữ liệu nhiệt độ ở phần 1 đã giới thiệu.

  • Dữ liệu thời gian (datetime) được giữ nguyên dạng chuỗi ‘2006-12-01 00’

    → Mô hình Machine Learning không thể hiểu ý nghĩa trực tiếp của chuỗi thời gian này (chuỗi ký tự không có quan hệ số học rõ ràng).

  • datetime được tách thành nhiều feature số học:

    • year = 2006
    • month = 12
    • day = 1
    • hour = 0

    → Mô hình dễ học hơn, vì các giá trị này là dữ liệu dạng số và thể hiện trực tiếp các đặc trưng thời gian.

Datatime

Cấu trúc datetime

year-month-day hour:minute:second.millisecond

Trong Pandas, có thể truy cập từng thành phần qua:

datetime = pd.to_datetime('2006-12-01 00:00:00.000')
print(datetime)        \#2006-12-01 00:00:00
print(datetime.year)   #2006
print(datetime.month)  #12
print(datetime.day)    #1
print(datetime.hour)   #0

Chuyển đổi cột ngày giờ sang kiểu datetime

  • Cột 'Formatted Date' được chuyển sang kiểu datetime64[ns, UTC] để dễ thao tác với thời gian.
  • utc=True đảm bảo dữ liệu được chuẩn hóa theo múi giờ UTC. Tách các thành phần thời gian:
  • .dt.year → Lấy năm.
  • .dt.month → Lấy tháng.
  • .dt.day → Lấy ngày.
  • .dt.hour → Lấy giờ.
  • Giúp phân tích dữ liệu theo từng thành phần thời gian hoặc xây dựng mô hình dự báo theo các yếu tố này. Sau đó xóa cột gốc Formatted Date
df = pd.read_csv('weatherHistory2D.csv')
df['Formatted Date'] = pd.to_datetime(df['Formatted Date'], 
                                      utc=True)
df['year'] = df['Formatted Date'].dt.year
df['month'] = df['Formatted Date'].dt.month
df['day'] = df['Formatted Date'].dt.day
df['hour'] = df['Formatted Date'].dt.hour
df = df.drop('Formatted Date', axis=1)
df
Temperature (C)yearmonthdayhour
00.5777782005123123
11.1611112006110
21.6666672006111
31.7111112006112
41.1833332006113
964480.4888892016123118
964490.0722222016123119
96450-0.2333332016123120
96451-0.4722222016123121
96452-0.6777782016123122
96453 rows × 5 columns

3. Example 2: Tweets dataset

Mô tả dữ liệu

Dataset Tweets dùng để phân loại tweet thành disaster hoặc non-disaster.

df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 7613 entries, 0 to 7612
Data columns (total 5 columns):

Column Non-Null Count Dtype

0 id 7613 non-null int64
1 keyword 7552 non-null object
2 location 5080 non-null object
3 text 7613 non-null object
4 target 7613 non-null int64
dtypes: int64(2), object(3)
memory usage: 297.5+ KB

  • Số lượng mẫu huấn luyện (Training samples): 7613
  • Số tweet disaster: 4342 (target = 1)
  • Số tweet non-disaster: 3271 (target = 0) image 21 6.png Các trường dữ liệu: |Cột|Ý nghĩa| |---|---| |id|Mã định danh duy nhất của tweet| |keyword|Từ khóa liên quan (nếu có)| |location|Địa điểm được nhắc đến trong tweet| |text|Nội dung tweet| |target|Nhãn phân loại: 1 = disaster tweet, 0 = non-disaster tweet|

Delete a row

df.drop(label, axis)
  • **axis=0** → xóa dòng (row) theo index
  • **axis=1** → xóa cột (column) theo tên cột Xóa 1 dòng
df.drop(1, axis=0)  

→ Xóa dòng có index = 1.

Xóa 2 dòng

df.drop([1, 2, 3], axis=0)

→ Xóa các dòng có index = 1, 2, 3.

Delete a column

Xóa 1 cột

df.drop('Radio', axis=1)

→ Xóa cột Radio. Xóa nhiều cột

df.drop(['Radio', 'Sales'], axis=1)

→ Xóa cột RadioSales. Ví dụ: Trong xử lý dữ liệu NLP, thường id, keyword, và location không cần thiết cho bước tiền xử lý văn bản, nên ta sẽ xóa chúng.

import pandas as pd
# Đọc dữ liệu từ file CSV
df = pd.read_csv("path_to_cvs_file")
# Xóa 3 cột: id, keyword, location
df.drop(["id", "keyword", "location"], axis=1, inplace=True)

4. Example 3: Credit Card Fraud Detection

III. Visualization