Python 编程:从零基础到精通
第45课 - pandas 数据清洗与操作
模块十:数据处理与分析 | 难度:intermediate | 标签:pandas, data-manipulation, cleaning 上一课: 数据分析:pandas 入门与 DataFrame 下一课: 数据可视化:Matplotlib 基础
1. 学习目标
完成本课学习后,你将能够:
- 掌握使用 pandas 处理缺失值(NaN)的常用方法。
- 学会识别和处理重复数据。
- 熟练进行数据类型的转换和列的重命名。
- 运用字符串方法清洗和格式化文本数据。
- 能够根据条件筛选、替换和修改数据。
2. 核心概念
2.1 处理缺失值(Missing Values)
在真实世界的数据集中,经常会有数据缺失的情况,pandas 用 NaN (Not a Number) 来表示。处理缺失值是数据清洗的第一步,常见策略有删除、填充或插值。
通俗比喻:想象一盒拼图,其中几块缺失了。你可以选择:1)把缺失块周围的拼图都扔掉(删除行/列);2)找一块相似颜色的硬纸板补上(填充);3)根据周围的图案猜测缺失块的样子(插值)。
2.2 处理重复数据
数据中可能因为录入错误、系统合并等原因出现完全相同的行。duplicated() 方法可以找出重复行,而 drop_duplicates() 可以删除它们。
2.3 数据类型转换与重命名
数据类型(如整数、浮点数、字符串、日期时间)必须正确,才能进行正确的计算和分析。astype() 用于转换类型,rename() 用于更改列名或索引名,使其更清晰、规范。
2.4 字符串数据操作
当数据包含文本时,需要标准化处理。pandas 提供了 .str 访问器,可以像操作 Python 字符串一样,批量处理 DataFrame 中的文本列,如提取、替换、分割、大小写转换等。
2.5 条件数据替换与筛选
根据特定条件来修改或筛选数据,是数据清洗和准备的核心。例如,将异常值标记为缺失、将分类变量进行编码等。
3. 代码示例
以下是一个完整的、可运行的示例,演示了常见的数据清洗操作。
import pandas as pd
import numpy as np
# 创建一个包含常见"脏"数据的示例DataFrame
data = {
'姓名': ['张三', '李四', '王五', '赵六', '孙七', '张三'], # 注意:'张三'重复了
'年龄': [28, 35, np.nan, 42, 23, 28], # 缺失值 (NaN)
'城市': ['北京', '上海', '广州', '深圳', '杭州', '北京'],
'薪资': ['8000', '12000', '9500', 'N/A', '7000', '8000'], # 有非数字字符串 'N/A'
'入职日期': ['2020-01-15', '2019-05-20', '2021-08-01', '2018-11-30', '2022-03-10', '2020-01-15'],
'评价': ['优秀', '良好', '优秀', '待改进', '良好', '优秀']
}
df = pd.DataFrame(data)
print("=== 原始数据 ===")
print(df)
print("\n")
# 1. 处理缺失值
# 查看缺失值情况
print("=== 各列缺失值数量 ===")
print(df.isnull().sum())
print("\n")
# 填充缺失值:用年龄列的均值填充
mean_age = df['年龄'].mean()
df['年龄'].fillna(mean_age, inplace=True) # inplace=True 表示原地修改
# 或者使用 df['年龄'] = df['年龄'].fillna(mean_age)
# 2. 处理重复数据
# 查看是否有重复行
print("=== 标记重复行 (keep='first'保留第一处出现) ===")
print(df.duplicated())
print("\n")
# 删除完全重复的行(基于所有列)
df_cleaned = df.drop_duplicates()
print("=== 删除重复行后的数据 ===")
print(df_cleaned)
print("\n")
# 3. 数据类型转换与重命名
# 将'薪资'列转换为数值类型,忽略错误(将'N/A'等无效值转为NaN)
df_cleaned['薪资'] = pd.to_numeric(df_cleaned['薪资'], errors='coerce')
# 将'入职日期'列转换为datetime类型
df_cleaned['入职日期'] = pd.to_datetime(df_cleaned['入职日期'])
# 重命名列:将'姓名'改为'Name','年龄'改为'Age'
df_cleaned = df_cleaned.rename(columns={'姓名': 'Name', '年龄': 'Age'})
print("=== 类型转换与重命名后的数据信息 ===")
print(df_cleaned.dtypes)
print(df_cleaned)
print("\n")
# 4. 字符串操作
# 将'城市'列的所有值转换为小写
df_cleaned['城市小写'] = df_cleaned['城市'].str.lower()
# 检查'评价'列中是否包含'优'字
df_cleaned['是否优秀'] = df_cleaned['评价'].str.contains('优')
print("=== 字符串操作结果 ===")
print(df_cleaned[['Name', '城市', '城市小写', '评价', '是否优秀']])
print("\n")
# 5. 条件数据替换与筛选
# 将'评价'为'待改进'的员工,其'薪资'增加1000元作为激励
# 使用 .loc 进行条件赋值,避免链式索引警告
df_cleaned.loc[df_cleaned['评价'] == '待改进', '薪资'] = df_cleaned.loc[df_cleaned['评价'] == '待改进', '薪资'] + 1000
# 筛选出年龄大于30岁的员工
senior_employees = df_cleaned[df_cleaned['Age'] > 30]
print("=== 年龄大于30岁的员工 ===")
print(senior_employees[['Name', 'Age', '薪资']])
# 最终查看清洗后的完整数据
print("\n=== 最终清洗后的数据 ===")
print(df_cleaned)
运行结果预期:你将看到一个经过缺失值填充、去重、列重命名、类型转换、新增计算列,并根据条件修改了数据的清洁 DataFrame。
4. 实践练习
练习1:基础数据清洗 给定以下 DataFrame,请完成:
import pandas as pd
import numpy as np
exercise_data = {
'产品': ['A', 'B', 'C', 'A', 'D', 'E'],
'价格': [100, 200, np.nan, 100, 50, 150],
'销量': [50, 30, 45, 50, '无数据', 60],
'类别': ['电子', '家居', '电子', '电子', '食品', '家居']
}
df_ex = pd.DataFrame(exercise_data)
要求:
- 找出并删除完全重复的行。
- 将'销量'列转换为数值类型,无法转换的填充为
0。 - 计算每行的'总销售额'(价格 * 销量)。
练习2:综合清洗与分析 使用下面更复杂的 DataFrame:
messy_data = {
'员工ID': ['E001', 'E002', 'E003', 'E004', 'E001'],
'姓名': ['alice', 'Bob Smith', 'Charlie', 'David', 'alice'],
'部门': ['销售部', '市场部', '研发部', '销售部', '销售部'],
'邮箱': ['[email protected]', 'bob.smith@co', '[email protected]', '[email protected]', '[email protected]'],
'绩效分数': ['95', 'Good', '88', '91', '95']
}
df_messy = pd.DataFrame(messy_data)
要求:
- 删除重复的员工记录(基于'员工ID'和'姓名')。
- 将'姓名'列中的英文名转换为首字母大写(如 'alice' -> 'Alice', 'Bob Smith' -> 'Bob Smith')。
- 将'邮箱'列中不完整的邮箱(如不包含'@'或不以'.com'结尾)标记为'无效邮箱'。
- 将'绩效分数'列转换为数值,无法转换的(如'Good')用该列数值的均值填充。
5. 常见错误
- 直接删除缺失值而忽略业务逻辑:盲目使用
dropna()可能会删除大量有价值的数据。应先分析缺失原因和占比,再决定策略。 - 忽略数据类型:将本应为数值的字符串列(如 '12,000')直接进行数学运算会导致错误。必须先进行类型转换和清理(如去除逗号)。
- 链式索引警告:使用
df[条件][列] = 值这样的链式索引进行赋值可能会触发SettingWithCopyWarning,并可能无法修改原 DataFrame。应使用.loc或.iloc。 - 忘记使用
inplace=True或赋值:很多 pandas 方法(如fillna,rename)默认返回一个新对象,原地修改需要设置inplace=True或将结果赋值给原变量。 - 字符串方法误用:
.str.contains()等方法区分大小写,如需不敏感匹配,可使用case=False参数。同时,操作对象必须是字符串类型。
6. 小结
本节课我们学习了 pandas 数据清洗与操作的核心技能:
- 处理缺失值:使用
isnull(),fillna(),dropna()来检查、填充或删除缺失数据。 - 处理重复数据:使用
duplicated()和drop_duplicates()来识别和删除重复行。 - 数据类型与格式:使用
astype(),pd.to_numeric(),pd.to_datetime()转换类型;使用rename()修改列名。 - 文本清洗:利用
.str访问器进行批量字符串操作,如.lower(),.contains(),.replace()。 - 条件操作:熟练使用布尔索引和
.loc进行基于条件的筛选、赋值和修改。
掌握这些技能,你就能将杂乱的原始数据转变为结构清晰、可直接用于分析和建模的干净数据集,为后续的数据分析和可视化打下坚实基础。