简介:本文面向 Python 数据分析初学者,旨在通过 30 分钟的系统学习,帮助读者快速掌握 Pandas 库中最核心、最高频的数据操作技能。文章从数据导入导出、数据查看、数据选择与过滤、数据清洗、数据重塑、分组聚合、数据合并、时间序列处理到综合实战,层层递进,结合大量可直接运行的代码示例,构建完整的数据分析知识框架。读完本文,您将能够独立完成从数据加载到结果输出的全流程操作,为后续进阶学习打下坚实基础。
在数据驱动的时代,高效处理和分析数据已成为开发者与数据工作者的必备技能。Pandas 作为 Python 生态中用于数据分析和清洗的核心库,凭借其强大的 Series 与 DataFrame 数据结构,以及对表格数据的灵活操作能力,成为数据科学领域的事实标准。无论是数据挖掘、机器学习预处理,还是商业智能报表,Pandas 都扮演着至关重要的角色。
然而,Pandas 功能庞大,初学者往往面对海量 API 感到无从下手。本文提炼出实际项目中最常用的操作场景,以 30 分钟为限,构建从数据导入到结果导出的完整闭环,帮助读者建立清晰的操作脉络。
数据分析的第一步是获取数据。Pandas 支持多种数据源格式,以下展示最常见的几种导入方式。
import pandas as pdimport numpy as np# 从 CSV 文件读取数据df_csv = pd.read_csv('data.csv')# 从 Excel 文件读取指定工作表df_excel = pd.read_excel('data.xlsx', sheet_name='Sheet1')# 从 SQL 数据库读取(以 SQLite 为例)from sqlalchemy import create_engineengine = create_engine('sqlite:///mydatabase.db')df_sql = pd.read_sql('SELECT * FROM orders', engine)# 从字典创建 DataFramedata = {'姓名': ['张三', '李四'], '年龄': [28, 32], '城市': ['北京', '上海']}df_dict = pd.DataFrame(data)
# 导出为 CSV,index=False 去除索引列,utf-8-sig 保证 Excel 中文兼容df.to_csv('output.csv', index=False, encoding='utf-8-sig')# 导出到 Excel 文件df.to_excel('output.xlsx', sheet_name='report', index=False)# 导出到 SQL 数据库,if_exists='replace' 表示覆盖原表df.to_sql('table_name', engine, if_exists='replace', index=False)
要点提示:在读取大文件时,可指定 nrows 参数预览前 N 行,或使用 chunksize 分块读取,以缓解内存压力。导出时注意编码与索引处理,避免数据错位。
拿到数据后,首要任务是了解数据结构、类型与质量状况。Pandas 提供了简洁的探测方法。
# 生成示例数据data = {'姓名': ['张三', '李四', '王五', '赵六', '钱七'],'年龄': [25, 30, None, 40, 45],'城市': ['北京', '上海', '广州', '深圳', '杭州'],'工资': [10000, 15000, 12000, 20000, 25000],'入职日期': ['2020-01-15', '2019-05-20', '2021-03-10', '2018-07-05', '2022-02-28']}df = pd.DataFrame(data)df['入职日期'] = pd.to_datetime(df['入职日期'])# 查看前 3 行与后 2 行print(df.head(3))print(df.tail(2))# 查看整体结构信息:索引范围、列名、非空值数量、数据类型、内存占用df.info()# 数值列统计摘要:均值、标准差、分位数、极值df.describe()# 查看形状(行数、列数)print(df.shape) # 输出 (5, 5)# 查看列名与索引对象print(df.columns)print(df.index)# 检查每列缺失值数量print(df.isnull().sum())
扩展解读:df.info() 在数据清洗前非常有价值,可以直观看到每一列的数据类型与缺失情况,辅助决定后续处理策略。describe() 默认只统计数值列,如需包含分类列,可设置 include='all'。
数据选择是 DataFrame 操作中最频繁的动作,需熟练掌握位置索引、标签索引与条件过滤。
# 选择单列,返回 Seriess_name = df['姓名']# 选择多列,返回 DataFramedf_subset = df[['姓名', '年龄']]# 使用点号操作符(列名需为合法标识符)s_age = df.年龄# 通过布尔条件过滤行df_high_salary = df[df['工资'] > 15000]# 多条件组合:& 表示与,| 表示或,~ 表示非df_condition = df[(df['年龄'] < 40) & (df['城市'].isin(['北京', '上海'])]# 使用 loc 与 iloc 进行标签/位置切片df.loc[1:3, ['姓名', '工资']] # 行标签 1 到 3,闭区间df.iloc[0:2, 0:2] # 前两行前两列,开区间# 按条件筛选指定列df.filter(items=['姓名', '年龄'], axis=1)
细节提示:布尔索引是 Pandas 最强大特性之一。注意逻辑运算符必须使用 &、|,且每个条件需加括号。loc 切片包含末端标签,而 iloc 则遵循 Python 左闭右开原则,两者极易混淆,应重点区分。
真实数据往往包含缺失值、重复值、异常值。清洗环节决定后续分析的可靠性。
# 检测缺失值df.isnull() # 逐元素布尔表df.isnull().sum() # 每列缺失总数# 删除含缺失值的行(axis=0)或列(axis=1)df_dropna = df.dropna(axis=0, how='any') # how='all' 仅删除全为缺失值的行# 填充缺失值:常数、前向填充、后向填充、均值/中位数df_fill = df.fillna(value={'年龄': df['年龄'].mean()}) # 用均值填充df_fill_ffill = df.fillna(method='ffill') # 用上一行值填充# 插值法填充df_interpolate = df.interpolate() # 线性插值,适合时间序列
# 检测重复行duplicated_mask = df.duplicated(subset=['姓名'], keep='first')df_unique = df.drop_duplicates(subset=['姓名'], keep='first')# 异常值识别(以年龄为例,基于标准差)mean_age = df['年龄'].mean()std_age = df['年龄'].std()df_outlier = df[(df['年龄'] > mean_age - 3 * std_age) & (df['年龄'] < mean_age + 3 * std_age)]
# 强制类型转换df['年龄'] = df['年龄'].astype('float64')# 自定义转换函数df['工资'] = df['工资'].apply(lambda x: x / 10000) # 转换为万元
实用建议:清洗策略需结合业务场景。若缺失比例低于 5%,可考虑直接删除;若为关键字段,优先采用中位数或众数填充。处理时间序列数据时,前向/后向填充往往比均值填充更合理。
数据透视与行列转换在报表聚合中极为常见,Pandas 提供了 melt、pivot 等方法实现结构变换。
# 从宽表转为长表(melt)df_melted = pd.melt(df, id_vars=['姓名'], value_vars=['工资', '年龄'],var_name='指标', value_name='数值')# 从长表转为宽表(pivot)df_pivot = df_melted.pivot(index='姓名', columns='指标', values='数值')# stack / unstack:作用于多层索引df_stack = df.set_index(['姓名', '城市']).stack()df_unstack = df_stack.unstack(level=0)
# 按单列/多列排序df_sorted = df.sort_values(by=['年龄', '工资'], ascending=[True, False])# 添加排名df['工资排名'] = df['工资'].rank(method='dense', ascending=False)
场景举例:当多个特征以列存在而分析需要以行排列时,melt 可快速将宽表展开;pivot 能实现类似 Excel 透视表的功能,对分组数据重建交叉表。
分组聚合是数据分析中价值密度最高的操作。groupby 配合多种聚合函数可实现高效统计。
# 按城市分组,计算工资均值group_mean = df.groupby('城市')['工资'].mean()# 按多列分组,多个聚合函数group_agg = df.groupby(['城市', '入职日期']).agg({'工资': ['sum', 'mean', 'count'],'年龄': 'median'})# 使用 named aggregationgroup_named = df.groupby('城市').agg(平均工资=('工资', 'mean'),最高工资=('工资', 'max'),人数=('姓名', 'count'))# 分组后遍历,适用于复杂逻辑for city, group in df.groupby('城市'):print(f"城市: {city}, 平均年龄: {group['年龄'].mean()}")
# 自定义函数:计算极差def range_func(series):return series.max() - series.min()df_apply = df.groupby('城市')['工资'].apply(range_func)
进阶技巧:groupby 后可以配合 transform 保留原始行数,如计算每位员工工资与城市均值的差值。filter 方法可根据分组统计结果过滤原始行,如保留人数大于 2 的城市。
在真实项目中,数据往往分散于多个表或文件,合并操作是数据整合的基础。
# 创建两组数据df1 = pd.DataFrame({'ID': [1, 2, 3], '工资': [10000, 15000, 12000]})df2 = pd.DataFrame({'ID': [4, 5], '工资': [20000, 25000]})df3 = pd.DataFrame({'ID': [1, 2], '绩效': ['A', 'B']})# 纵向拼接(行合并)df_concat = pd.concat([df1, df2], axis=0, ignore_index=True)# 横向拼接(列合并)df_concat_col = pd.concat([df1.set_index('ID'), df3.set_index('ID')], axis=1, join='inner')
# 内连接:仅保留匹配的行df_inner = pd.merge(df1, df3, on='ID', how='inner')# 左连接:保留左表所有行df_left = pd.merge(df1, df3, on='ID', how='left')# 右连接与全外连接df_right = pd.merge(df1, df3, on='ID', how='right')df_outer = pd.merge(df1, df3, on='ID', how='outer')# 当键列名称不同时,指定 left_on 与 right_ondf_custom = pd.merge(df1, df3, left_on='ID', right_on='ID', how='left')
注意事项:合并前务必确认关联键的唯一性(或明确可容忍的笛卡尔积)。merge 默认做内连接,且会对重名列自动追加后缀,可通过 suffixes 参数自定义。
时间序列是金融、物联网、运营分析中最常见的数据类型。Pandas 提供了丰富的时间处理工具。
# 将字符串列转为时间类型,并设置为索引df_time = df.copy()df_time['入职日期'] = pd.to_datetime(df_time['入职日期'])df_time.set_index('入职日期', inplace=True)# 按月份重采样,计算月度平均工资df_monthly = df_time.resample('M')['工资'].mean()# 按季度聚合df_quarterly = df_time.resample('Q')['工资'].agg(['sum', 'count', 'mean'])# 时间差计算df_time['工龄天数'] = (pd.Timestamp.now() - df_time.index).days
# 计算环比变化(本月与上月差额)df_time['工资环比'] = df_time['工资'].diff(periods=1)# 计算增长率df_time['工资增长率'] = df_time['工资'].pct_change() * 100# 移动平均平滑df_time['移动平均3月'] = df_time['工资'].rolling(window=3).mean()
实战要点:重采样前必须保证索引为 DatetimeIndex。resample 支持频率参数 ‘M’ 月度末、’MS’ 月度初、’Q’ 季度末、’H’ 小时等。滚动窗口的 min_periods 参数可控制窗口内最少有效值数,避免前几行产生 NaN。
将上述所有知识点串联,构建一个完整的实战示例,题目为:员工工资分析报告。
import pandas as pdimport numpy as np# 1. 数据读取df = pd.read_csv('employees.csv', encoding='utf-8-sig')# 2. 数据审阅print("数据形状:", df.shape)print("缺失值统计:\n", df.isnull().sum())# 3. 数据清洗df = df.drop_duplicates(subset='员工ID')df['年龄'].fillna(df['年龄'].median(), inplace=True)df['入职日期'] = pd.to_datetime(df['入职日期'])# 4. 特征衍生df['入职年份'] = df['入职日期'].dt.yeardf['工龄'] = (pd.Timestamp.now() - df['入职日期']).dt.days // 365# 5. 分组聚合分析# 各部门平均工资与人数dept_stats = df.groupby('部门').agg(平均工资=('工资', 'mean'),人数=('员工ID', 'count'),平均工龄=('工龄', 'mean')).reset_index()# 高薪员工筛选(工资高于部门平均水平 1.2 倍)df['部门平均工资'] = df.groupby('部门')['工资'].transform('mean')df['高薪标记'] = np.where(df['工资'] > 1.2 * df['部门平均工资'], '是', '否')# 6. 结果导出dept_stats.to_excel('部门薪资统计.xlsx', index=False)df[df['高薪标记'] == '是'].to_csv('高薪员工名单.csv', index=False, encoding='utf-8-sig')print("分析完成,结果已输出。")
该案例涵盖了数据导入、探索、清洗、聚合、条件标记与导出的一整套流程,是日常分析工作的标准范式。
本文系统梳理了 Pandas 入门所需的六大核心能力:数据读写、数据探查、数据筛选、数据清洗、数据聚合与数据合并,并辅以时间序列处理和完整实战。30 分钟的学习虽然只能覆盖高频操作,但已经足以构建起独立解决数据问题的能力框架。
numba 加速与 eval/query 方法。Pandas 的学习曲线虽然陡峭,但只要有清晰的操作地图与实战锻造,很快便能从生疏走向自如。建议读者将本文作为速查手册,在真实项目中有针对性地查询与巩固。