Pandas数据清洗常用技巧包括处理缺失值、重复值、异常值、文本数据、日期时间及数据标准化。具体为:用dropna()或fillna()处理缺失值;drop_duplicates()去除重复数据;通过IQR或标准差识别异常值并合理处理;利用str方法清洗文本,如去空格、大小写转换;用to_datetime统一日期格式;结合业务需求进行数据归一化。同时需注意链式赋值警告、性能优化和内存管理等最佳实践。

Pandas是Python数据科学领域的一把瑞士军刀,它提供了一系列高效的数据结构和数据分析工具,让你能轻松处理和分析表格型数据,就像在用一个超级强大的Excel。无论是数据清洗、转换、聚合还是探索性分析,Pandas都能提供直观且高性能的解决方案。
要开始使用Pandas,第一步通常是导入它,约定俗成地使用
pd
import pandas as pd import numpy as np # 经常和Pandas一起使用
1. 创建数据结构:DataFrame和Series
Pandas最核心的两个数据结构是DataFrame和Series。Series可以看作带标签的一维数组,而DataFrame则是一个二维的、表格型数据结构,每列可以有不同的数据类型。
立即学习“Python免费学习笔记(深入)”;
创建Series:
s = pd.Series([1, 3, 5, np.nan, 6, 8]) print(s) # 输出: # 0 1.0 # 1 3.0 # 2 5.0 # 3 NaN # 4 6.0 # 5 8.0 # dtype: float64
创建DataFrame,这通常是我们日常工作中打交道最多的。可以从字典、列表的列表,或者直接从CSV、Excel文件加载。
# 从字典创建DataFrame
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [25, 30, 28, 35],
'城市': ['北京', '上海', '广州', '深圳'],
'薪资': [8000, 12000, 9000, 15000]
}
df = pd.DataFrame(data)
print(df)
# 输出:
# 姓名 年龄 城市 薪资
# 0 张三 25 北京 8000
# 1 李四 30 上海 12000
# 2 王五 28 广州 9000
# 3 赵六 35 深圳 150002. 从文件加载数据
真实世界的数据很少是手动输入的,更多是从文件读取。Pandas对多种文件格式提供了强大的支持。
# 读取CSV文件
# df_csv = pd.read_csv('your_data.csv')
# 读取Excel文件
# df_excel = pd.read_excel('your_data.xlsx', sheet_name='Sheet1')
# 读取JSON文件
# df_json = pd.read_json('your_data.json')通常,
pd.read_csv()
3. 数据查看与初步探索
拿到数据后,第一件事是看看它长什么样。
print(df.head()) # 查看前5行 print(df.tail(3)) # 查看后3行 print(df.info()) # 查看数据概览,包括列名、非空值数量、数据类型 print(df.describe()) # 对数值列进行统计描述,如均值、标准差、最大最小值等 print(df.shape) # 查看行数和列数 (rows, columns) print(df.columns) # 查看所有列名
4. 数据选择与过滤
这是数据分析的基础操作,如何精准地取出你想要的数据。
选择单列或多列:
print(df['姓名']) # 选择单列,返回Series print(df[['姓名', '薪资']]) # 选择多列,返回DataFrame
使用
loc
iloc
loc
iloc
print(df.loc[0]) # 选择第一行 print(df.loc[0, '姓名']) # 选择第一行'姓名'列的值 print(df.loc[0:2, ['姓名', '年龄']]) # 选择0到2行(包含2),'姓名'和'年龄'列 print(df.iloc[0:3, 0:2]) # 选择前3行,前2列(基于位置)
条件过滤:
# 筛选年龄大于30的员工 older_employees = df[df['年龄'] > 30] print(older_employees) # 筛选城市是上海且薪资高于10000的员工 filtered_df = df[(df['城市'] == '上海') & (df['薪资'] > 10000)] print(filtered_df)
5. 数据清洗与处理
这是数据分析中最耗时也最关键的一步。
缺失值处理:
# 检查缺失值 print(df.isnull().sum()) # 删除含有缺失值的行 # df_cleaned = df.dropna() # 填充缺失值 # df_filled = df.fillna(value=0) # 用0填充所有缺失值 # df['年龄'].fillna(df['年龄'].mean(), inplace=True) # 用年龄均值填充年龄列的缺失值
数据类型转换:
# 将某一列转换为特定类型 # df['年龄'] = df['年龄'].astype(int)
重复值处理:
# 检查重复行 # print(df.duplicated().sum()) # 删除重复行 # df_no_duplicates = df.drop_duplicates()
6. 数据聚合与分组
groupby()
# 按照城市分组,计算每个城市的平均薪资
avg_salary_by_city = df.groupby('城市')['薪资'].mean()
print(avg_salary_by_city)
# 按照城市和年龄分组,计算每个组的薪资总和
grouped_data = df.groupby(['城市', '年龄'])['薪资'].sum()
print(grouped_data)
# 可以同时应用多个聚合函数
agg_data = df.groupby('城市')['薪资'].agg(['mean', 'max', 'min', 'count'])
print(agg_data)7. 数据合并与连接
当数据分散在多个DataFrame中时,你需要将它们合并起来。
df1 = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'value': np.random.randn(4)})
df2 = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'value2': np.random.randn(4)})
# 内连接:只保留两个DataFrame中key都存在的行
merged_df = pd.merge(df1, df2, on='key', how='inner')
print(merged_df)
# 左连接:保留左边DataFrame的所有行,匹配右边DataFrame的行
left_merged_df = pd.merge(df1, df2, on='key', how='left')
print(left_merged_df)
# 拼接(Stacking):将多个DataFrame按行或列堆叠起来
df3 = pd.DataFrame({'key': ['G', 'H'], 'value': np.random.randn(2)})
concatenated_df = pd.concat([df1, df3], ignore_index=True)
print(concatenated_df)数据清洗,这活儿说起来简单,做起来往往是整个项目最磨人的部分。我的经验是,没有哪个数据集是“干净”的,总有些奇奇怪怪的脏数据等着你去处理。Pandas在这方面提供了很多趁手的工具。
除了前面提到的缺失值、重复值处理,还有几个点我觉得特别重要:
异常值检测与处理: 异常值可能是数据录入错误,也可能代表了真实的特殊情况。识别它们是第一步。常用的方法有基于统计(如3倍标准差、IQR范围)或可视化(箱线图、散点图)。Pandas本身没有直接的异常值检测函数,但你可以结合其统计功能轻松实现。
# 假设我们想找出薪资的异常值
Q1 = df['薪资'].quantile(0.25)
Q3 = df['薪资'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = df[(df['薪资'] < lower_bound) | (df['薪资'] > upper_bound)]
print("薪资异常值:\n", outliers)
# 处理方式可以是删除、替换为均值/中位数,或者上限/下限值
# df['薪资'] = np.where(df['薪资'] > upper_bound, upper_bound, df['薪资'])处理异常值需要谨慎,有时它们是宝贵的信息,比如高价值客户或系统故障。
文本数据清洗: 字符串列往往是最混乱的。大小写不一致、多余空格、特殊字符、错别字……这些都得处理。Pandas的
str
df['城市'] = df['城市'].str.strip() # 移除前后空格
df['城市'] = df['城市'].str.lower() # 转换为小写
df['姓名'] = df['姓名'].str.replace('张', 'ZHANG') # 替换字符
# 使用正则表达式进行更复杂的匹配和替换
# df['描述'] = df['描述'].str.replace(r'[^\w\s]', '', regex=True) # 移除所有非字母数字和空格的字符这里面有个小坑,如果你的字符串列里有
NaN
str
日期时间数据处理: 日期时间格式不统一是常态。Pandas的
to_datetime
# df['日期'] = pd.to_datetime(df['日期'], errors='coerce') # errors='coerce'会将无法解析的日期转换为NaT(Not a Time) # 提取年份、月份、星期几等 # df['年份'] = df['日期'].dt.year # df['月份'] = df['日期'].dt.month
处理日期时间时,时区问题也常常让人头疼,特别是在处理跨国数据时。Pandas提供了
tz_localize
tz_convert
数据标准化/归一化: 在进行机器学习前,往往需要将不同量纲的数值特征进行缩放。虽然这通常在Pandas之外(如scikit-learn)完成,但Pandas是数据准备的平台。
# 简单的Min-Max标准化示例 # df['薪资_normalized'] = (df['薪资'] - df['薪资'].min()) / (df['薪资'].max() - df['薪资'].min())
这些技巧,用得多了自然熟练,但每次遇到新数据,我还是会先花大量时间在清洗上,毕竟“垃圾进,垃圾出”是数据分析的铁律。
数据聚合和分组分析是Pandas的灵魂所在,它允许我们从宏观角度理解数据,而不是纠结于每一行。
groupby()
想象一下,你有一堆销售数据,你可能想知道每个产品类别的总销售额,或者每个地区的平均订单价值。这就是
groupby()
基本流程是:Split-Apply-Combine。
最常见的应用是聚合函数:
# 假设我们有一个更复杂的销售数据
sales_data = {
'产品类别': ['电子', '服装', '电子', '食品', '服装', '电子', '食品'],
'地区': ['华东', '华南', '华东', '华北', '华南', '华东', '华北'],
'销售额': [1200, 500, 1500, 300, 800, 1000, 450],
'订单数量': [10, 5, 12, 3, 8, 9, 4]
}
sales_df = pd.DataFrame(sales_data)
print("原始销售数据:\n", sales_df)
# 按产品类别计算总销售额
total_sales_by_category = sales_df.groupby('产品类别')['销售额'].sum()
print("\n按产品类别总销售额:\n", total_sales_by_category)
# 按地区计算平均订单数量
avg_orders_by_region = sales_df.groupby('地区')['订单数量'].mean()
print("\n按地区平均订单数量:\n", avg_orders_by_region)更进一步,你可以同时对多个列应用不同的聚合函数,使用
agg()
# 按产品类别和地区分组,同时计算销售额的总和、平均值和订单数量的总和
multi_agg = sales_df.groupby(['产品类别', '地区']).agg(
总销售额=('销售额', 'sum'),
平均销售额=('销售额', 'mean'),
总订单数量=('订单数量', 'sum')
)
print("\n多重聚合结果:\n", multi_agg)这里我用了Python 3.6+的f-string风格的
agg
除了聚合,
groupby()
# 计算每个产品类别销售额占该类别总销售额的比例
sales_df['类别销售额占比'] = sales_df.groupby('产品类别')['销售额'].transform(lambda x: x / x.sum())
print("\n带类别销售额占比的数据:\n", sales_df)# 筛选出总销售额超过2000的产品类别
filtered_categories = sales_df.groupby('产品类别').filter(lambda x: x['销售额'].sum() > 2000)
print("\n总销售额超过2000的产品类别数据:\n", filtered_categories)这些高级用法让
groupby()
groupby()
在实际项目中使用Pandas,我遇到过不少坑,也总结了一些经验。它确实强大,但用不好也容易“翻车”。
常见陷阱:
链式赋值警告(SettingWithCopyWarning): 这是新手最常遇到的问题之一。当你对一个DataFrame的“视图”进行修改时,Pandas会发出警告。
# 错误示例:可能引发SettingWithCopyWarning # df_subset = df[df['年龄'] > 30] # df_subset['薪资'] = df_subset['薪资'] * 1.1 # 这里的修改可能不会反映到原始df,也可能报错
最佳实践: 明确地使用
.loc
.copy()
.copy()
.loc
df_subset = df[df['年龄'] > 30].copy() # 明确复制一份 df_subset['薪资'] = df_subset['薪资'] * 1.1 # 在原始DataFrame上修改,使用.loc df.loc[df['年龄'] > 30, '薪资'] = df.loc[df['年龄'] > 30, '薪资'] * 1.1
这个坑我踩过好几次,导致数据修改没生效,或者莫名其妙的错误。
性能问题: 对大型数据集使用循环(
for
apply
# 性能差的示例:逐行处理 # for index, row in df.iterrows(): # df.loc[index, '新列'] = row['列A'] + row['列B']
最佳实践: 尽可能使用Pandas的向量化操作。Pandas底层是C语言实现的,向量化操作能充分利用CPU的并行计算能力。
df['新列'] = df['列A'] + df['列B'] # 向量化操作
如果必须使用
apply
df.apply(..., axis=1)
numba
modin
内存占用: 大数据集可能导致内存不足。特别是字符串和日期时间列,它们在Pandas中可能比你想象的更占用内存。 最佳实践:
int8
int16
float32
df.info(memory_usage='deep')
category
df['城市'] = df['城市'].astype('category')pd.read_csv(..., chunksize=...)
索引管理不当: 索引是Pandas的强大之处,但如果处理不当,也可能导致问题,比如合并时索引不匹配。 最佳实践:
on
reset_index()
这些陷阱,说到底都是对Pandas底层机制理解不够深入造成的。多实践,多看官方文档,你会发现Pandas的设计哲学非常精妙。它不是一个简单的工具库,而是一个强大的数据处理框架,值得我们花时间去深入学习。
以上就是Python怎么使用Pandas库_Pandas数据处理入门指南的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号