1. 数据探索分析(EDA)与pandas基础
在数据分析的初始阶段,探索性数据分析(Exploratory Data Analysis,简称EDA)是每位数据工作者必须掌握的核心技能。作为Python生态中最强大的数据处理工具,pandas库提供了丰富而高效的函数集,能够帮助我们快速理解数据特征、发现潜在规律并识别异常值。
我从事数据分析工作多年,pandas始终是我日常工作中使用频率最高的工具。与其他工具相比,pandas最大的优势在于其DataFrame数据结构的设计——这种二维表格形式与我们日常处理的数据形态高度契合,同时提供了SQL-like的操作接口,使得数据操作变得直观而高效。
提示:对于刚接触pandas的新手,建议先理解两个核心数据结构:Series(一维带标签数组)和DataFrame(二维表格结构)。这是掌握所有高级操作的基础。
在实际EDA过程中,我们通常会按照"数据加载→初步观察→数据清洗→特征分析→可视化洞察"的工作流推进。下面我将按照这个流程,分类介绍每个阶段最实用的pandas函数及其典型应用场景。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据加载与初步观察
2.1 数据读取函数
数据加载是EDA的第一步,pandas支持从各种数据源读取数据:
python复制# 从CSV文件读取
df = pd.read_csv('data.csv', encoding='utf-8', parse_dates=['date_column'])
# 从Excel读取
df = pd.read_excel('data.xlsx', sheet_name='Sheet1')
# 从SQL数据库读取
import sqlite3
conn = sqlite3.connect('database.db')
df = pd.read_sql('SELECT * FROM table_name', conn)
关键参数说明:
encoding:指定文件编码(中文常用utf-8或gbk)parse_dates:将指定列自动解析为日期类型dtype:强制指定列数据类型na_values:定义哪些值应被视为缺失值
2.2 数据概览函数
加载数据后,我们需要快速了解数据的基本情况:
python复制# 查看前5行数据
df.head()
# 查看数据维度(行数,列数)
df.shape
# 查看列名列表
df.columns
# 查看每列数据类型和非空计数
df.info()
# 显示数值列的统计摘要
df.describe(include='all') # include='all'包含非数值列
注意:df.describe()默认只显示数值列的统计信息。添加include='all'参数可以显示所有列的统计,但对于非数值列仅显示计数、唯一值数等基本信息。
3. 数据清洗与预处理
3.1 缺失值处理
真实数据中缺失值非常常见,pandas提供了多种处理方式:
python复制# 检查每列缺失值数量
df.isnull().sum()
# 删除包含缺失值的行
df.dropna(how='any', subset=['important_column'])
# 填充缺失值
df.fillna({
'numeric_column': df['numeric_column'].median(),
'categorical_column': 'Unknown'
})
# 向前填充(用前一个有效值填充)
df.ffill()
经验分享:
- 对于缺失率超过30%的列,通常考虑直接删除该列
- 数值型缺失值常用均值/中位数填充
- 分类变量常用众数或"Unknown"等特殊标记填充
- 时间序列数据常用前后值填充(ffill/bfill)
3.2 数据类型转换
正确的数据类型能显著提高分析效率和准确性:
python复制# 转换为日期类型
df['date_column'] = pd.to_datetime(df['date_string'])
# 转换为分类类型(节省内存,提高性能)
df['category_column'] = df['category_column'].astype('category')
# 数值类型转换
df['float_column'] = pd.to_numeric(df['string_number'], errors='coerce')
3.3 重复值处理
python复制# 检查重复行
df.duplicated().sum()
# 删除完全重复的行
df.drop_duplicates(inplace=True)
# 基于关键列去重
df.drop_duplicates(subset=['id_column'], keep='last')
4. 数据筛选与排序
4.1 数据筛选
python复制# 单条件筛选
df[df['age'] > 30]
# 多条件组合
df[(df['age'] > 30) & (df['city'] == '北京')]
# 使用query方法(语法更简洁)
df.query("age > 30 and city == '北京'")
# 使用isin筛选多个值
df[df['department'].isin(['销售', '市场'])]
# 字符串包含筛选
df[df['address'].str.contains('朝阳区', na=False)]
4.2 数据排序
python复制# 单列排序
df.sort_values('salary', ascending=False)
# 多列排序
df.sort_values(['department', 'salary'], ascending=[True, False])
# 按索引排序
df.sort_index()
5. 数据分组与聚合
分组聚合是EDA中最强大的分析手段之一:
5.1 基本分组操作
python复制# 单列分组
grouped = df.groupby('department')
# 多列分组
grouped = df.groupby(['year', 'month'])
# 查看分组结果
grouped.size() # 每组记录数
grouped.groups # 查看分组详情
5.2 聚合计算
python复制# 单聚合函数
df.groupby('department')['salary'].mean()
# 多聚合函数
df.groupby('department').agg({
'salary': ['mean', 'max', 'min'],
'age': 'median'
})
# 自定义聚合函数
def top_3_salaries(series):
return list(series.sort_values(ascending=False)[:3])
df.groupby('department')['salary'].apply(top_3_salaries)
5.3 透视表与交叉表
python复制# 透视表
pd.pivot_table(df,
index='department',
columns='gender',
values='salary',
aggfunc='mean')
# 交叉表(用于频数统计)
pd.crosstab(df['department'], df['education'])
6. 特征工程与转换
6.1 特征创建
python复制# 从日期提取特征
df['year'] = df['date_column'].dt.year
df['day_of_week'] = df['date_column'].dt.dayofweek
# 分箱(离散化连续变量)
df['age_group'] = pd.cut(df['age'],
bins=[0, 18, 35, 50, 100],
labels=['少年', '青年', '中年', '老年'])
# 虚拟变量(One-Hot编码)
pd.get_dummies(df['department'], prefix='dept')
6.2 数据标准化
python复制# Min-Max标准化
df['normalized'] = (df['value'] - df['value'].min()) / (df['value'].max() - df['value'].min())
# Z-score标准化
df['standardized'] = (df['value'] - df['value'].mean()) / df['value'].std()
7. 数据合并与连接
7.1 纵向合并
python复制# 简单堆叠(要求列名相同)
pd.concat([df1, df2], axis=0)
# 忽略索引
pd.concat([df1, df2], ignore_index=True)
7.2 横向连接
python复制# 类似SQL的JOIN操作
pd.merge(left_df, right_df,
how='inner', # 也可以是'left','right','outer'
on='key_column')
# 按索引连接
df1.join(df2, how='left')
8. 时间序列处理
pandas为时间序列分析提供了强大支持:
8.1 时间索引操作
python复制# 设置时间索引
df.set_index('timestamp', inplace=True)
# 按时间筛选
df.loc['2023-01':'2023-03'] # 筛选2023年第一季度数据
# 重采样(降采样/升采样)
df.resample('W').mean() # 按周重采样
8.2 滚动窗口计算
python复制# 7天滚动平均
df['rolling_7d'] = df['value'].rolling(window=7).mean()
# 扩展窗口计算
df['expanding_mean'] = df['value'].expanding().mean()
9. 性能优化技巧
处理大数据集时,这些技巧可以显著提高性能:
9.1 高效数据类型
python复制# 使用category类型节省内存
df['category_column'] = df['category_column'].astype('category')
# 使用整数类型替代浮点
df['int_column'] = pd.to_numeric(df['int_column'], downcast='integer')
9.2 避免链式赋值
python复制# 不推荐(可能产生SettingWithCopyWarning)
df[df['age'] > 30]['salary'] = 5000
# 推荐方式
df.loc[df['age'] > 30, 'salary'] = 5000
9.3 使用eval提升性能
python复制# 对于复杂表达式
df.eval('result = (col1 + col2) / col3', inplace=True)
10. 常见问题与解决方案
10.1 内存不足问题
当处理大型数据集时,可以尝试以下方法:
- 使用
dtype参数指定合适的数据类型 - 分块读取数据(
chunksize参数) - 使用
pd.read_csv(..., usecols=['col1','col2'])只加载必要列
10.2 SettingWithCopyWarning
这个常见警告通常是由于链式索引引起的。解决方案:
- 使用
.loc[row_indexer,col_indexer]进行明确索引 - 如果需要副本,显式调用
.copy()
10.3 性能瓶颈
如果操作执行缓慢:
- 避免在循环中操作DataFrame
- 考虑使用向量化操作替代apply
- 对于超大数据集,考虑使用Dask或Modin等替代库
11. 实战案例:销售数据分析
让我们通过一个实际案例综合运用这些函数:
python复制# 加载数据
sales = pd.read_csv('sales_data.csv', parse_dates=['order_date'])
# 数据清洗
sales = sales.dropna(subset=['customer_id', 'amount'])
sales['amount'] = pd.to_numeric(sales['amount'], errors='coerce')
# 添加特征
sales['month'] = sales['order_date'].dt.to_period('M')
sales['weekday'] = sales['order_date'].dt.day_name()
# 分析月销售额趋势
monthly_sales = sales.groupby('month')['amount'].sum().reset_index()
# 产品类别分析
category_analysis = pd.pivot_table(sales,
index='category',
columns='region',
values='amount',
aggfunc='sum')
# 客户RFM分析
from datetime import datetime
snapshot_date = sales['order_date'].max() + pd.Timedelta(days=1)
rfm = sales.groupby('customer_id').agg({
'order_date': lambda x: (snapshot_date - x.max()).days,
'order_id': 'count',
'amount': 'sum'
}).rename(columns={
'order_date': 'recency',
'order_id': 'frequency',
'amount': 'monetary'
})
在这个案例中,我们综合运用了数据加载、清洗、特征工程、分组聚合和透视表等多种技术,完成了从原始数据到业务洞察的全过程分析。
