Data Cleaning & Preprocessing
1. Tại sao Data Cleaning quan trọng?
"Garbage in, garbage out" - Dữ liệu bẩn → Model tệ!
Các vấn đề thường gặp:
- Missing values - Giá trị thiếu
- Duplicates - Dữ liệu trùng lặp
- Outliers - Giá trị ngoại lai
- Inconsistent data - Dữ liệu không nhất quán
- Wrong data types - Kiểu dữ liệu sai
Python
1import pandas as pd2import numpy as np34# Sample dirty data5df = pd.DataFrame({6 'name': ['Alice', 'BOB', 'alice', None, 'Charlie'],7 'age': [25, 300, 30, 35, -5],8 'salary': [50000, 60000, np.nan, 70000, 80000],9 'email': ['alice@gmail.com', 'bob@', 'ALICE@GMAIL.COM', 'charlie@yahoo.com', '']10})2. Missing Values
2.1 Phát hiện Missing Values
Python
1# Kiểm tra null2df.isnull() # Boolean DataFrame3df.isnull().sum() # Đếm null mỗi cột4df.isnull().sum().sum() # Tổng null56# Tỷ lệ missing7missing_pct = df.isnull().sum() / len(df) * 1008print(missing_pct)910# Visualize missing11import missingno as msno12msno.matrix(df)13msno.heatmap(df)2.2 Xử lý Missing Values
Python
1# 1. Drop rows với missing2df.dropna() # Drop nếu có bất kỳ NaN3df.dropna(subset=['name']) # Drop nếu 'name' là NaN4df.dropna(thresh=3) # Giữ dòng có ≥3 non-null56# 2. Drop columns với quá nhiều missing7df.dropna(axis=1, thresh=len(df)*0.5) # Drop cột có >50% missing89# 3. Fill missing - Numeric10df['age'].fillna(df['age'].mean()) # Mean11df['age'].fillna(df['age'].median()) # Median12df['age'].fillna(df['age'].mode()[0]) # Mode13df['age'].fillna(0) # Constant1415# 4. Fill missing - Categorical16df['category'].fillna('Unknown')17df['category'].fillna(df['category'].mode()[0])1819# 5. Forward/Backward Fill (Time series)20df['value'].fillna(method='ffill') # Forward fill21df['value'].fillna(method='bfill') # Backward fill2223# 6. Interpolation24df['value'].interpolate(method='linear')25df['value'].interpolate(method='polynomial', order=2)2627# 7. Group-wise fill28df['salary'] = df.groupby('department')['salary'].transform(29 lambda x: x.fillna(x.median())30)2.3 Advanced: KNN Imputation
Python
1from sklearn.impute import KNNImputer23imputer = KNNImputer(n_neighbors=5)4df_numeric = df.select_dtypes(include=[np.number])5df_imputed = pd.DataFrame(6 imputer.fit_transform(df_numeric),7 columns=df_numeric.columns8)3. Duplicate Data
3.1 Phát hiện Duplicates
Python
1# Kiểm tra duplicates2df.duplicated() # Boolean Series3df.duplicated().sum() # Đếm duplicates45# Duplicates theo specific columns6df.duplicated(subset=['name', 'email'])78# Xem các dòng duplicate9df[df.duplicated(keep=False)] # Tất cả duplicates10df[df.duplicated(keep='first')] # Trừ dòng đầu3.2 Xử lý Duplicates
Python
1# Remove duplicates2df.drop_duplicates() # Giữ dòng đầu3df.drop_duplicates(keep='last') # Giữ dòng cuối4df.drop_duplicates(subset=['email']) # Theo cột cụ thể5df.drop_duplicates(subset=['name'], keep=False) # Remove all4. Outliers
4.1 Phát hiện Outliers
Python
1import matplotlib.pyplot as plt2import seaborn as sns34# Visualize với Boxplot5plt.figure(figsize=(10, 6))6sns.boxplot(data=df[['age', 'salary', 'income']])7plt.show()89# Z-Score method10from scipy import stats1112z_scores = np.abs(stats.zscore(df['salary'].dropna()))13outliers_z = df[z_scores > 3] # Z-score > 31415# IQR method16Q1 = df['salary'].quantile(0.25)17Q3 = df['salary'].quantile(0.75)18IQR = Q3 - Q11920lower_bound = Q1 - 1.5 * IQR21upper_bound = Q3 + 1.5 * IQR2223outliers_iqr = df[(df['salary'] < lower_bound) | (df['salary'] > upper_bound)]24print(f"Outliers: {len(outliers_iqr)}")4.2 Xử lý Outliers
Python
1# 1. Remove outliers2df_clean = df[(df['salary'] >= lower_bound) & (df['salary'] <= upper_bound)]34# 2. Cap outliers (Winsorization)5df['salary_capped'] = df['salary'].clip(lower=lower_bound, upper=upper_bound)67# 3. Log transform (giảm skewness)8df['salary_log'] = np.log1p(df['salary'])910# 4. Robust scaling11from sklearn.preprocessing import RobustScaler1213scaler = RobustScaler()14df['salary_scaled'] = scaler.fit_transform(df[['salary']])5. Data Type Conversion
Python
1# Kiểm tra data types2df.dtypes34# Convert to numeric5df['price'] = pd.to_numeric(df['price'], errors='coerce') # NaN if invalid67# Convert to datetime8df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')9df['date'] = pd.to_datetime(df['date'], errors='coerce')1011# Convert to category (memory efficient)12df['status'] = df['status'].astype('category')1314# Convert to string15df['id'] = df['id'].astype(str)1617# Convert boolean18df['is_active'] = df['is_active'].map({'yes': True, 'no': False})6. String Cleaning
Python
1# Strip whitespace2df['name'] = df['name'].str.strip()34# Standardize case5df['name'] = df['name'].str.lower()6df['name'] = df['name'].str.title() # Title Case78# Remove special characters9df['phone'] = df['phone'].str.replace(r'[^0-9]', '', regex=True)1011# Fix inconsistent values12df['country'] = df['country'].replace({13 'vn': 'Vietnam',14 'VN': 'Vietnam',15 'vietnam': 'Vietnam',16 'Viet Nam': 'Vietnam'17})1819# Extract information20df['domain'] = df['email'].str.extract(r'@(\w+\.\w+)')21df['area_code'] = df['phone'].str[:3]7. Feature Encoding
7.1 Label Encoding
Python
1from sklearn.preprocessing import LabelEncoder23le = LabelEncoder()4df['status_encoded'] = le.fit_transform(df['status'])56# Mapping7mapping = dict(zip(le.classes_, le.transform(le.classes_)))8print(mapping) # {'active': 0, 'inactive': 1}7.2 One-Hot Encoding
Python
1# Pandas get_dummies2df_encoded = pd.get_dummies(df, columns=['city', 'status'], drop_first=True)34# Sklearn OneHotEncoder5from sklearn.preprocessing import OneHotEncoder67ohe = OneHotEncoder(sparse=False, drop='first')8encoded = ohe.fit_transform(df[['city', 'status']])7.3 Ordinal Encoding
Python
1from sklearn.preprocessing import OrdinalEncoder23# Với thứ tự cụ thể4education_order = ['High School', 'Bachelor', 'Master', 'PhD']5oe = OrdinalEncoder(categories=[education_order])6df['education_encoded'] = oe.fit_transform(df[['education']])8. Feature Scaling
8.1 StandardScaler (Z-score)
Python
1from sklearn.preprocessing import StandardScaler23scaler = StandardScaler()4df[['age_scaled', 'salary_scaled']] = scaler.fit_transform(df[['age', 'salary']])56# Mean = 0, Std = 18.2 MinMaxScaler
Python
1from sklearn.preprocessing import MinMaxScaler23scaler = MinMaxScaler(feature_range=(0, 1))4df[['age_scaled', 'salary_scaled']] = scaler.fit_transform(df[['age', 'salary']])56# Range [0, 1]8.3 RobustScaler (cho data có outliers)
Python
1from sklearn.preprocessing import RobustScaler23scaler = RobustScaler()4df['salary_scaled'] = scaler.fit_transform(df[['salary']])56# Robust với outliers (dùng median và IQR)9. Complete Pipeline
Python
1import pandas as pd2import numpy as np3from sklearn.preprocessing import StandardScaler, LabelEncoder45def clean_data(df):6 """Pipeline làm sạch dữ liệu hoàn chỉnh"""7 8 df = df.copy()9 10 # 1. Remove duplicates11 df = df.drop_duplicates()12 print(f"After removing duplicates: {len(df)} rows")13 14 # 2. Handle missing values15 # Numeric: fill with median16 numeric_cols = df.select_dtypes(include=[np.number]).columns17 for col in numeric_cols:18 df[col] = df[col].fillna(df[col].median())19 20 # Categorical: fill with mode21 cat_cols = df.select_dtypes(include=['object']).columns22 for col in cat_cols:23 df[col] = df[col].fillna(df[col].mode()[0])24 25 # 3. Handle outliers (IQR method)26 for col in numeric_cols:27 Q1 = df[col].quantile(0.25)28 Q3 = df[col].quantile(0.75)29 IQR = Q3 - Q130 df[col] = df[col].clip(Q1 - 1.5*IQR, Q3 + 1.5*IQR)31 32 # 4. Clean strings33 for col in cat_cols:34 df[col] = df[col].str.strip().str.lower()35 36 # 5. Encode categoricals37 le = LabelEncoder()38 for col in cat_cols:39 df[f'{col}_encoded'] = le.fit_transform(df[col])40 41 # 6. Scale numerics42 scaler = StandardScaler()43 df[numeric_cols] = scaler.fit_transform(df[numeric_cols])44 45 return df4647# Sử dụng48df_clean = clean_data(df)10. Data Quality Report
Python
1def data_quality_report(df):2 """Tạo báo cáo chất lượng dữ liệu"""3 4 report = pd.DataFrame({5 'Column': df.columns,6 'Data Type': df.dtypes.values,7 'Non-Null Count': df.count().values,8 'Null Count': df.isnull().sum().values,9 'Null %': (df.isnull().sum() / len(df) * 100).round(2).values,10 'Unique Values': df.nunique().values,11 'Sample Values': [df[col].dropna().head(3).tolist() for col in df.columns]12 })13 14 return report1516# Sử dụng17report = data_quality_report(df)18print(report.to_string())Tổng Kết
Trong bài này, bạn đã học:
- ✅ Phát hiện và xử lý Missing Values
- ✅ Xử lý Duplicate data
- ✅ Phát hiện và xử lý Outliers
- ✅ Data type conversion
- ✅ String cleaning
- ✅ Feature Encoding (Label, One-Hot, Ordinal)
- ✅ Feature Scaling (Standard, MinMax, Robust)
- ✅ Building data cleaning pipeline
Bài tiếp theo: Data Visualization với Seaborn!
