使用 pandas 进行数据清洗和转换 从缺失值处理到类型转换的实用指南

数据清洗和转换是数据分析流程中至关重要的一环。无论数据来源多么可靠,原始数据往往包含缺失值、错误格式、不一致的类型或异常值。Pandas 是 Python 中最流行的数据处理库,提供了强大且灵活的工具来应对这些挑战。本文将详细介绍如何使用 Pandas 进行数据清洗和转换,涵盖从缺失值处理到类型转换的全过程,并通过完整的代码示例进行说明。
1. 环境准备与数据加载
在开始数据清洗之前,我们需要确保环境中已安装 Pandas,并加载示例数据。我们将创建一个包含各种数据问题的 DataFrame 来模拟真实场景。
import pandas as pd
import numpy as np

# 创建示例数据
data = {
‘Name’: [‘Alice’, ‘Bob’, ‘Charlie’, ‘David’, ‘Eve’, ‘Frank’],
‘Age’: [25, 30, np.nan, 35, 28, 40],
‘Salary’: [‘50000’, ‘60000’, ‘70000’, ‘80000’, ‘90000’, ‘100000’],
‘Department’: [‘HR’, ‘IT’, ‘IT’, ‘Finance’, ‘HR’, ‘Finance’],
‘JoinDate’: [‘2020-01-15’, ‘2019-03-20’, ‘2021-06-10’, ‘2018-11-05’, ‘2020-09-12’, ‘2017-04-18’],
‘Email’: [‘alice@example.com’, ‘bob@example.com’, ‘charlie@example.com’, ‘david@example.com’, ‘eve@example.com’, ‘frank@example.com’],
‘PerformanceScore’: [‘A’, ‘B’, ‘C’, ‘A’, ‘B’, ‘A’]
}

df = pd.DataFrame(data)
print(“原始数据:”)
print(df)
print(“\n数据信息:”)
df.info()
输出说明:
我们创建了一个包含6行7列的DataFrame。
Age
列包含一个缺失值(NaN)。
Salary
列是字符串类型,需要转换为数值类型。
JoinDate
是字符串,需要转换为日期类型。
PerformanceScore
是分类数据,但目前是字符串。
2. 数据概览与初步检查
在深入清洗之前,先对数据进行概览,了解数据的基本情况和潜在问题。
2.1 查看数据基本信息
使用
info()
方法可以快速查看每列的数据类型和非空值数量。
df.info()
2.2 查看数值型数据的统计摘要
使用
describe()
方法可以获取数值列的统计信息(如均值、标准差、最小值、最大值等)。
print(df.describe())
2.3 查看前几行数据
使用
head()
方法快速预览数据。
print(df.head())
2.4 检查缺失值
使用
isnull()
和
sum()
组合可以统计每列的缺失值数量。
print(df.isnull().sum())
3. 缺失值处理
缺失值是数据清洗中最常见的问题之一。Pandas 使用
NaN
(Not a Number)来表示缺失值。处理缺失值的方法主要有删除、填充或插值。
3.1 删除缺失值
如果缺失值的比例很小,或者某些行/列的缺失值无法有效填充,可以考虑删除。
# 删除包含任何缺失值的行
df_dropped_rows = df.dropna()
print(“删除缺失值行后的数据:”)
print(df_dropped_rows)

# 删除包含任何缺失值的列
df_dropped_cols = df.dropna(axis=1)
print(“\n删除缺失值列后的数据:”)
print(df_dropped_cols)

# 仅删除那些全部为缺失值的行
df_dropped_all_na = df.dropna(how=’all’)
print(“\n删除全部为缺失值的行后的数据:”)
print(df_dropped_all_na)

# 删除至少有3个非缺失值的行
df_dropped_thresh = df.dropna(thresh=3)
print(“\n删除非缺失值少于3个的行后的数据:”)
print(df_dropped_thresh)
3.2 填充缺失值
使用
fillna()
方法可以填充缺失值。填充策略取决于数据类型和业务逻辑。
# 用0填充所有缺失值
df_filled_zero = df.fillna(0)
print(“用0填充缺失值:”)
print(df_filled_zero)

# 用特定值填充特定列的缺失值
df_filled_specific = df.copy()
df_filled_specific[‘Age’] = df_filled_specific[‘Age’].fillna(df_filled_specific[‘Age’].mean())
print(“\n用年龄列的均值填充缺失值:”)
print(df_filled_specific)

# 用前一个值填充(向前填充)
df_filled_ffill = df.fillna(method=’ffill’)
print(“\n向前填充缺失值:”)
print(df_filled_ffill)

# 用后一个值填充(向后填充)
df_filled_bfill = df.fillna(method=’bfill’)
print(“\n向后填充缺失值:”)
print(df_filled_bfill)
3.3 插值法
对于时间序列数据,线性插值可能更合适。
# 线性插值
df_interpolated = df.interpolate()
print(“线性插值后的数据:”)
print(df_interpolated)
4. 数据类型转换
数据类型不正确会导致计算错误或分析困难。常见的转换包括字符串转数值、字符串转日期、以及分类数据的编码。
4.1 字符串转数值
Salary
列是字符串,需要转换为整数或浮点数。
# 方法1: 使用 astype
df[‘Salary’] = df[‘Salary’].astype(int)
print(“转换Salary为整数类型:”)
print(df[‘Salary’].dtype)

# 方法2: 使用 to_numeric (更健壮,可以处理错误)
df[‘Salary’] = pd.to_numeric(df[‘Salary’], errors=’coerce’)
print(“\n使用to_numeric转换Salary:”)
print(df[‘Salary’])
4.2 字符串转日期
JoinDate
列需要转换为 datetime 类型,以便进行日期计算。
# 转换为 datetime 类型
df[‘JoinDate’] = pd.to_datetime(df[‘JoinDate’])
print(“转换JoinDate为datetime类型:”)
print(df[‘JoinDate’].dtype)

# 提取年份、月份等信息
df[‘JoinYear’] = df[‘JoinDate’].dt.year
df[‘JoinMonth’] = df[‘JoinDate’].dt.month
print(“\n提取年份和月份:”)
print(df[[‘JoinDate’, ‘JoinYear’, ‘JoinMonth’]])
4.3 分类数据编码
PerformanceScore
是分类数据,可以转换为类别类型或数值编码。
# 转换为 category 类型
df[‘PerformanceScore’] = df[‘PerformanceScore’].astype(‘category’)
print(“转换为category类型:”)
print(df[‘PerformanceScore’].dtype)

# 为类别分配数值编码
df[‘PerformanceScore_Code’] = df[‘PerformanceScore’].cat.codes
print(“\n类别数值编码:”)
print(df[[‘PerformanceScore’, ‘PerformanceScore_Code’]])
5. 数据标准化与规范化
数据标准化和规范化可以将数据缩放到特定范围,便于比较和模型训练。
5.1 字符串清洗
去除字符串中的空格、转换大小写等。
# 去除前后空格
df[‘Name’] = df[‘Name’].str.strip()

# 转换为大写
df[‘Name’] = df[‘Name’].str.upper()

# 替换特定字符
df[‘Email’] = df[‘Email’].str.replace(‘@’, ‘ at ‘)

print(“字符串清洗后的数据:”)
print(df[[‘Name’, ‘Email’]])
5.2 数值标准化
使用 Min-Max 缩放或 Z-Score 标准化。
# Min-Max 缩放 (0-1范围)
df[‘Age_MinMax’] = (df[‘Age’] – df[‘Age’].min()) / (df[‘Age’].max() – df[‘Age’].min())

# Z-Score 标准化
df[‘Age_ZScore’] = (df[‘Age’] – df[‘Age’].mean()) / df[‘Age’].std()

print(“\n标准化后的年龄数据:”)
print(df[[‘Age’, ‘Age_MinMax’, ‘Age_ZScore’]])
6. 异常值处理
异常值可能影响分析结果,需要识别和处理。
6.1 基于统计方法识别异常值
使用 IQR(四分位距)方法识别异常值。
# 计算 Q1, Q3 和 IQR
Q1 = df[‘Age’].quantile(0.25)
Q3 = df[‘Age’].quantile(0.75)
IQR = Q3 – Q1

# 定义异常值边界
lower_bound = Q1 – 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 识别异常值
outliers = df[(df[‘Age’] < lower_bound) | (df['Age'] > upper_bound)]
print(“识别出的异常值:”)
print(outliers)

# 处理异常值 (例如,用边界值替换)
df[‘Age’] = np.where(df[‘Age’] > upper_bound, upper_bound, df[‘Age’])
df[‘Age’] = np.where(df[‘Age’] < lower_bound, lower_bound, df['Age']) print("\n处理异常值后的年龄数据:") print(df['Age']) 7. 数据去重 重复数据会导致分析偏差,需要去重。 # 检查重复行数 print("重复行数:", df.duplicated().sum()) # 删除完全重复的行 df_unique = df.drop_duplicates() print("\n去重后的数据:") print(df_unique) # 根据特定列去重 df_unique_name = df.drop_duplicates(subset=['Name']) print("\n根据Name列去重:") print(df_unique_name) 8. 数据重塑与分组聚合 数据清洗后,可能需要进行重塑和聚合以满足分析需求。 8.1 数据重塑 使用 melt 和 pivot 进行数据重塑。 # Pivot 示例 pivot_df = df.pivot_table(index='Department', values='Salary', aggfunc='mean') print("按部门分组的平均薪资:") print(pivot_df) 8.2 分组聚合 使用 groupby 进行分组聚合。 # 按部门分组,计算平均年龄和薪资 grouped = df.groupby('Department').agg({ 'Age': 'mean', 'Salary': 'mean' }) print("\n按部门分组聚合:") print(grouped) 9. 完整的数据清洗流程示例 下面是一个完整的数据清洗流程,将上述步骤整合在一起。 def clean_data(df): """ 完整的数据清洗函数 """ # 1. 处理缺失值 df['Age'] = df['Age'].fillna(df['Age'].mean()) # 2. 数据类型转换 df['Salary'] = pd.to_numeric(df['Salary'], errors='coerce') df['JoinDate'] = pd.to_datetime(df['JoinDate']) # 3. 字符串清洗 df['Name'] = df['Name'].str.strip().str.upper() df['Department'] = df['Department'].str.strip() # 4. 异常值处理 Q1 = df['Age'].quantile(0.25) Q3 = df['Age'].quantile(0.75) IQR = Q3 - Q1 lower_bound = Q1 - 1.5 * IQR upper_bound = Q3 + 1.5 * IQR df['Age'] = np.where(df['Age'] > upper_bound, upper_bound, df[‘Age’])
df[‘Age’] = np.where(df[‘Age’] < lower_bound, lower_bound, df['Age']) # 5. 去重 df = df.drop_duplicates() # 6. 特征工程 df['JoinYear'] = df['JoinDate'].dt.year return df # 应用清洗函数 cleaned_df = clean_data(df.copy()) print("完整清洗后的数据:") print(cleaned_df) print("\n清洗后数据信息:") cleaned_df.info() 10. 总结 本文详细介绍了使用 Pandas 进行数据清洗和转换的全过程,包括: 数据概览与检查 缺失值处理(删除、填充、插值) 数据类型转换(字符串转数值、日期、分类编码) 数据标准化与规范化 异常值处理 数据去重 数据重塑与聚合 通过这些步骤,你可以将原始数据转换为高质量、可用于分析的数据。数据清洗是一个迭代的过程,需要根据具体数据和业务需求调整策略。希望这篇指南能帮助你更高效地使用 Pandas 进行数据清洗工作。