如何使用 Pandas 進(jìn)行數(shù)據(jù)清洗?如何保證數(shù)據(jù)清洗的效果?
前言
數(shù)據(jù)清洗是數(shù)據(jù)分析和機(jī)器學(xué)習(xí)項(xiàng)目中的關(guān)鍵步驟,它涉及處理缺失值、異常值、重復(fù)記錄、不一致的數(shù)據(jù)等。Pandas 提供了豐富的功能來幫助你進(jìn)行數(shù)據(jù)清洗。
如何使用 Pandas 進(jìn)行數(shù)據(jù)清洗
1. 導(dǎo)入必要的庫(kù)
import pandas as pd
import numpy as np
2. 讀取數(shù)據(jù)
假設(shè)你有一個(gè) CSV 文件 data.csv,其中包含一些特征和目標(biāo)變量。
# 讀取數(shù)據(jù)
df = pd.read_csv('data.csv')
print(df.head())
3. 數(shù)據(jù)探索
了解數(shù)據(jù)的基本信息,包括缺失值、數(shù)據(jù)類型等。
# 查看基本信息
print(df.info())
# 查看描述性統(tǒng)計(jì)信息
print(df.describe())
# 檢查缺失值
print(df.isnull().sum())
4. 處理缺失值
刪除含有缺失值的行或列
# 刪除含有缺失值的行
df = df.dropna()
# 刪除含有缺失值的列
df = df.dropna(axis=1)
填充缺失值
# 用均值填充數(shù)值列的缺失值
df['Age'] = df['Age'].fillna(df['Age'].mean())
# 用眾數(shù)填充分類列的缺失值
df['Gender'] = df['Gender'].fillna(df['Gender'].mode()[0])
# 用特定值填充
df['Income'] = df['Income'].fillna(0)
# 使用前一個(gè)值填充
df['Salary'] = df['Salary'].fillna(method='ffill')
# 使用后一個(gè)值填充
df['Salary'] = df['Salary'].fillna(method='bfill')
# 使用插值方法填充
df['Temperature'] = df['Temperature'].interpolate()
5. 處理異常值
條件篩選
# 移除年齡大于100歲的記錄
df = df[df['Age'] <= 100]
使用 Z-score 方法
from scipy import stats
# 計(jì)算 Z-score
z_scores = np.abs(stats.zscore(df.select_dtypes(include=[np.number])))
# 移除 Z-score 大于 3 的記錄
df = df[(z_scores < 3).all(axis=1)]
使用 IQR 方法
Q1 = df.quantile(0.25)
Q3 = df.quantile(0.75)
IQR = Q3 - Q1
# 移除 IQR 范圍外的記錄
df = df[~((df < (Q1 - 1.5 * IQR)) | (df > (Q3 + 1.5 * IQR))).any(axis=1)]
6. 處理重復(fù)記錄
# 檢查并刪除重復(fù)記錄
df = df.drop_duplicates()
7. 數(shù)據(jù)類型轉(zhuǎn)換
確保每個(gè)列的數(shù)據(jù)類型正確。
# 將字符串轉(zhuǎn)換為日期
df['Date'] = pd.to_datetime(df['Date'])
# 將對(duì)象類型轉(zhuǎn)換為數(shù)值類型
df['Age'] = pd.to_numeric(df['Age'], errors='coerce')
# 將數(shù)值類型轉(zhuǎn)換為類別類型
df['Category'] = df['Category'].astype('category')
8. 處理不一致的數(shù)據(jù)
確保數(shù)據(jù)的一致性,例如統(tǒng)一文本格式。
統(tǒng)一文本格式
# 將所有文本轉(zhuǎn)換為小寫
df['Name'] = df['Name'].str.lower()
# 去除空格
df['Name'] = df['Name'].str.strip()
替換特定值
# 替換特定值
df['City'] = df['City'].replace({'New York City': 'New York', 'LA': 'Los Angeles'})
9. 處理特殊字符
去除不必要的特殊字符。
# 去除特殊字符
df['Comment'] = df['Comment'].str.replace('[^\w\s]', '', regex=True)
10. 處理時(shí)間序列數(shù)據(jù)
處理時(shí)間序列數(shù)據(jù),如提取年份、月份、日等。
# 提取年份、月份、日
df['Year'] = df['Date'].dt.year
df['Month'] = df['Date'].dt.month
df['Day'] = df['Date'].dt.day
11. 保存清洗后的數(shù)據(jù)
將清洗后的數(shù)據(jù)保存到新的文件中。
# 保存清洗后的數(shù)據(jù)
df.to_csv('cleaned_data.csv', index=False)
如何保證數(shù)據(jù)清洗的效果?
1. 定義清晰的數(shù)據(jù)質(zhì)量標(biāo)準(zhǔn)
在開始數(shù)據(jù)清洗之前,明確你的數(shù)據(jù)質(zhì)量標(biāo)準(zhǔn)。這包括:
數(shù)據(jù)的完整性:確保所有必要的字段都已填寫。
數(shù)據(jù)的一致性:確保數(shù)據(jù)在不同記錄之間是一致的。
數(shù)據(jù)的準(zhǔn)確性:確保數(shù)據(jù)反映了真實(shí)情況。
數(shù)據(jù)的有效性:確保數(shù)據(jù)符合預(yù)期的格式和范圍。
2. 進(jìn)行徹底的數(shù)據(jù)探索
在清洗數(shù)據(jù)之前,進(jìn)行徹底的數(shù)據(jù)探索以了解數(shù)據(jù)的基本情況。使用 Pandas 和其他可視化工具來檢查數(shù)據(jù)的分布、缺失值、異常值等。
# 查看基本信息
print(df.info())
# 查看描述性統(tǒng)計(jì)信息
print(df.describe())
# 檢查缺失值
print(df.isnull().sum())
# 可視化數(shù)據(jù)分布
import matplotlib.pyplot as plt
df['Age'].hist(bins=20)
plt.show()
3. 記錄每一步操作
記錄你在數(shù)據(jù)清洗過程中所做的每一步操作。這有助于你跟蹤和驗(yàn)證每個(gè)步驟的效果,并在需要時(shí)回溯或調(diào)整。
# 記錄每一步操作
with open('data_cleaning_log.txt', 'w') as f:
f.write("Data Cleaning Log:\n")
f.write(f"Initial shape: {df.shape}\n")
# 示例:處理缺失值
df = df.dropna()
f.write(f"After dropping missing values: {df.shape}\n")
# 示例:處理異常值
df = df[df['Age'] <= 100]
f.write(f"After removing outliers: {df.shape}\n")
# 其他步驟...
4. 分階段進(jìn)行數(shù)據(jù)清洗
將數(shù)據(jù)清洗過程分為多個(gè)階段,逐步進(jìn)行并驗(yàn)證每個(gè)階段的效果。這樣可以更容易地發(fā)現(xiàn)和解決問題。
# 第一階段:處理缺失值
df = df.dropna()
# 驗(yàn)證結(jié)果
print(df.isnull().sum())
# 第二階段:處理異常值
df = df[df['Age'] <= 100]
# 驗(yàn)證結(jié)果
print(df['Age'].describe())
5. 使用斷言和測(cè)試
編寫斷言和測(cè)試來驗(yàn)證數(shù)據(jù)清洗的結(jié)果是否符合預(yù)期。這可以通過簡(jiǎn)單的條件語句或更復(fù)雜的單元測(cè)試來實(shí)現(xiàn)。
# 斷言
assert df.isnull().sum().sum() == 0, "There are still missing values in the dataset"
assert (df['Age'] > 100).sum() == 0, "There are still age values greater than 100"
# 單元測(cè)試
import unittest
class TestDataCleaning(unittest.TestCase):
def test_missing_values(self):
self.assertEqual(df.isnull().sum().sum(), 0)
def test_outliers(self):
self.assertEqual((df['Age'] > 100).sum(), 0)
if __name__ == '__main__':
unittest.main(argv=['first-arg-is-ignored'], exit=False)
6. 定期復(fù)查數(shù)據(jù)
即使數(shù)據(jù)清洗完成后,也要定期復(fù)查數(shù)據(jù),確保沒有新的問題出現(xiàn)。特別是在數(shù)據(jù)源發(fā)生變化或有新數(shù)據(jù)加入時(shí)。
# 定期復(fù)查數(shù)據(jù)
def check_data_quality(df):
print("Checking data quality...")
print("Missing values:", df.isnull().sum())
print("Outliers in Age:", (df['Age'] > 100).sum())
check_data_quality(df)
7. 使用版本控制
使用版本控制系統(tǒng)(如 Git)來管理數(shù)據(jù)和代碼。這樣可以在出現(xiàn)問題時(shí)輕松回滾到之前的版本。
# 初始化 Git 倉(cāng)庫(kù)
git init
# 添加文件
git add data_cleaning_script.py
git add data_cleaning_log.txt
# 提交更改
git commit -m "Initial data cleaning script and log"
8. 與團(tuán)隊(duì)成員溝通
如果你在一個(gè)團(tuán)隊(duì)中工作,確保與團(tuán)隊(duì)成員溝通數(shù)據(jù)清洗的過程和結(jié)果。共享文檔、日志和測(cè)試結(jié)果,以便其他人可以理解和驗(yàn)證你的工作。
9. 使用自動(dòng)化工具
考慮使用自動(dòng)化工具和框架來簡(jiǎn)化數(shù)據(jù)清洗過程。例如,使用 Apache Airflow 或 Prefect 來自動(dòng)化數(shù)據(jù)管道,確保數(shù)據(jù)清洗步驟的一致性和可重復(fù)性。
10. 監(jiān)控?cái)?shù)據(jù)質(zhì)量
建立數(shù)據(jù)質(zhì)量監(jiān)控系統(tǒng),定期檢查數(shù)據(jù)的質(zhì)量指標(biāo)。這可以通過設(shè)置報(bào)警或報(bào)告來實(shí)現(xiàn),以便及時(shí)發(fā)現(xiàn)和解決問題。