一、回顾与本篇目标
上一篇我们学了爬虫,你的 Python 程序已经能从网页上自动抓取数据了。但数据抓回来之后呢?看着一大坨 JSON 或者 CSV 文件,怎么从中找出有价值的信息?怎么筛选、排序、分组、统计?
如果你用 Excel 处理过数据,你一定熟悉这些操作:筛选出某个月份的销售记录、按产品类别分组求平均价格、对金额从高到低排序。Python 里有一个库,让你用代码的方式完成所有这些操作,而且能处理 Excel 处理不了的数据量——几十万行、几百万行的表格。这个库就是 Pandas。
Pandas 是 Python 在数据科学领域最核心的工具。如果你以后想往数据分析、数据可视化、机器学习方向发展,Pandas 是绕不过去的基本功。即使你只是偶尔需要处理表格数据,Pandas 也能让你效率倍增。
本篇的目标:
- 理解 Pandas 的两个核心数据结构:Series 和 DataFrame
- 学会读取 CSV 和 Excel 文件
- 掌握数据筛选、排序、分组统计
- 学会处理缺失值
- 理解数据合并的基本操作
- 做一个完整的表格数据分析示例
二、Pandas 是什么
Pandas 是 Python 中专门用来处理表格数据的库。表格数据就是那种有行有列、带表头的数据——Excel 表格、CSV 文件、数据库查询结果——都是表格数据。
在 Pandas 出现之前,用 Python 处理表格数据是很痛苦的——你需要用 csv 模块逐行读取、手动解析每一列、自己写循环做筛选和统计。Pandas 把这些操作都封装成了简洁的方法,一个 .groupby() 就能完成原本需要几十行代码的分组统计。
你可以把 Pandas 理解为:程序员的 Excel,而且能处理的数据量远超 Excel。
安装 Pandas
pip install pandas
通常还会一起安装 openpyxl(用于读写 Excel 文件):
pip install openpyxl
导入 Pandas
import pandas as pd
import pandas as pd 是数据科学领域的标准写法——大家都这么写。后面的文章我们都用 pd 来指代 Pandas。
三、Pandas 的两个核心数据结构
Pandas 建立在两个核心数据结构之上。理解它们,是理解 Pandas 的关键。
Series:一列数据
Series 相当于 Excel 中的一列。它由两个部分组成:索引(行的标签)和值(实际数据)。
import pandas as pd
# 从列表创建 Series
scores = pd.Series([85, 92, 78, 95])
print(scores)
# 0 85
# 1 92
# 2 78
# 3 95
# dtype: int64
# 自定义索引
scores_with_index = pd.Series([85, 92, 78, 95], index=['张三', '李四', '王五', '赵六'])
print(scores_with_index)
# 张三 85
# 李四 92
# 王五 78
# 赵六 95
# dtype: int64
左边是索引(行标签),右边是值。你可以通过索引来访问值:
print(scores_with_index['张三']) # 85
print(scores_with_index[0]) # 85 —— 也可以用位置索引
DataFrame:一张完整的表格
DataFrame 相当于 Excel 中的一整张工作表。它由多个 Series(列)组成,既有行索引,也有列名。
# 用字典创建 DataFrame
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [28, 22, 25, 30],
'成绩': [85, 92, 78, 95],
'城市': ['上海', '北京', '广州', '深圳']
}
df = pd.DataFrame(data)
print(df)
输出是一张整齐的表格:
姓名 年龄 成绩 城市
0 张三 28 85 上海
1 李四 22 92 北京
2 王五 25 78 广州
3 赵六 30 95 深圳
DataFrame 有行索引(最左边 0、1、2、3)和列名(姓名、年龄、成绩、城市)。你可以通过列名访问一整列(得到一个 Series),也可以定位到具体的某个单元格。
四、读取文件:CSV 和 Excel
实际工作中,数据通常存在文件里。Pandas 提供了极其简洁的读取函数。
读取 CSV 文件
假设你有一个 students.csv 文件:
姓名,年龄,成绩,城市
张三,28,85,上海
李四,22,92,北京
王五,25,78,广州
赵六,30,95,深圳
用 Pandas 读取只需要一行:
df = pd.read_csv('students.csv')
print(df)
如果 CSV 文件编码不是 utf-8(比如是 gbk),指定编码:
df = pd.read_csv('students.csv', encoding='gbk')
读取 Excel 文件
# 读取第一个工作表
df = pd.read_excel('students.xlsx')
# 读取指定工作表
df = pd.read_excel('students.xlsx', sheet_name='Sheet1')
查看数据的基本信息
拿到 DataFrame 后,通常先快速查看一下数据长什么样:
# 查看前几行(默认 5 行)
print(df.head())
# 查看后几行
print(df.tail())
# 查看数据的基本信息:行数、列数、每列的数据类型、是否有缺失值
print(df.info())
# 查看数值列的基本统计:计数、平均值、标准差、最小值、最大值
print(df.describe())
# 查看行数和列数
print(df.shape) # (4, 4) —— 4 行 4 列
# 查看列名
print(df.columns) # Index(['姓名', '年龄', '成绩', '城市'], dtype='object')
五、访问数据:选列、选行、选单元格
这是 Pandas 中最基础也最常用的操作。有多种方式,我们聚焦于最实用的三种。
选择列
# 选择单列——返回一个 Series
print(df['姓名'])
print(df.姓名) # 也可以这样写,但列名必须是合法的变量名
# 选择多列——返回一个 DataFrame
print(df[['姓名', '成绩']])
# 注意:多列要用两层方括号,内层是一个列表
选择行:用 .loc[] 和 .iloc[]
.loc[行标签]:基于索引值选择行。.iloc[行位置]:基于位置选择行(从 0 开始计数)。
# 用 .loc 按索引选行
df_with_name_index = df.set_index('姓名') # 把“姓名”列设为行索引
print(df_with_name_index.loc['张三']) # 选择姓名为张三的行
# 用 .iloc 按位置选行
print(df.iloc[0]) # 第一行
print(df.iloc[1:3]) # 第二行到第三行(不包括第四行)
print(df.iloc[-1]) # 最后一行
选择特定的行和列(单元格)
# .loc[行, 列]
print(df.loc[0, '姓名']) # 第一行,姓名列
print(df.loc[0:2, ['姓名', '成绩']]) # 第 0 到 2 行,姓名和成绩两列
# .iloc[行位置, 列位置]
print(df.iloc[0, 1]) # 第一行第二列(年龄)
print(df.iloc[0:2, 0:3]) # 第 0 到 1 行,第 0 到 2 列
记忆技巧:loc 是按名字(label)查找,iloc 是按数字位置(integer location)查找。
六、数据筛选:按条件过滤行
数据筛选就是“找出满足某个条件的行”。这是数据分析中最频繁的操作之一。
df = pd.DataFrame({
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [28, 22, 25, 30],
'成绩': [85, 92, 78, 95],
'城市': ['上海', '北京', '广州', '深圳']
})
# 1. 筛选成绩大于 80 的行
high_scores = df[df['成绩'] > 80]
print(high_scores)
# 2. 筛选城市是“上海”的行
shanghai = df[df['城市'] == '上海']
print(shanghai)
# 3. 多条件筛选:年龄大于 25 并且成绩大于 80
# 每个条件用括号包裹,用 &(与)、|(或)、~(非)连接
filtered = df[(df['年龄'] > 25) & (df['成绩'] > 80)]
print(filtered)
# 4. 用 isin() 筛选多个值
cities = df[df['城市'].isin(['上海', '深圳'])]
print(cities)
# 5. 筛选字符串包含某个子串
contains_hao = df[df['姓名'].str.contains('王')]
print(contains_hao)
操作符对照:
- 并且:
&(不能用and) - 或者:
|(不能用or) - 非:
~(不能用not)
每个条件表达式必须用括号包裹。这是新手最容易出错的地方。
七、数据排序
# 按成绩升序排列
sorted_df = df.sort_values('成绩')
print(sorted_df)
# 按成绩降序排列
sorted_df = df.sort_values('成绩', ascending=False)
print(sorted_df)
# 按多列排序:先按城市,再按年龄
sorted_df = df.sort_values(['城市', '年龄'])
print(sorted_df)
八、新增列和修改列
# 新增一列:计算成绩的等级
df['等级'] = df['成绩'].apply(lambda x: '优秀' if x >= 90 else '良好' if x >= 80 else '及格')
print(df)
# 用现有的列计算新列
df['年龄平方'] = df['年龄'] ** 2
df['成绩百分比'] = df['成绩'] / 100
# 修改某列的值
df['成绩'] = df['成绩'] + 5 # 每人加 5 分
apply() 是 Pandas 中非常有用的方法——它把一个函数应用到一列的每个值上,返回一个新 Series。这里用了一个 lambda 匿名函数来实现分段判断。
九、分组统计:groupby()
分组统计是数据分析的核心。它的逻辑是:先按某个列把数据分成若干组,然后对每组做统计。
比如“统计每个城市的平均成绩”——先按城市分组,再对每组求成绩的平均值。
# 创建一些示例数据
df = pd.DataFrame({
'城市': ['上海', '北京', '上海', '北京', '广州', '上海'],
'姓名': ['张三', '李四', '王五', '赵六', '孙七', '周八'],
'成绩': [85, 92, 78, 95, 88, 90],
'年龄': [28, 22, 25, 30, 27, 24]
})
# 1. 按城市分组,求每组的平均成绩
print(df.groupby('城市')['成绩'].mean())
# 城市
# 上海 84.333333
# 北京 93.500000
# 广州 88.000000
# 2. 按城市分组,求每组的成绩最高分和最低分
print(df.groupby('城市')['成绩'].agg(['max', 'min']))
# max min
# 城市
# 上海 90 78
# 北京 95 92
# 广州 88 88
# 3. 按城市分组,求成绩的平均值和人数
print(df.groupby('城市').agg(
平均成绩=('成绩', 'mean'),
人数=('成绩', 'count')
))
分组统计最常用的聚合函数:
| 函数 | 作用 |
|---|---|
mean() |
平均值 |
sum() |
求和 |
max() |
最大值 |
min() |
最小值 |
count() |
计数(非空值的个数) |
std() |
标准差 |
median() |
中位数 |
十、处理缺失值
实际数据中经常有缺失值——某个单元格为空、某一行缺了几个字段。Pandas 用 NaN(Not a Number)来表示缺失值。
import numpy as np
# 创建包含缺失值的 DataFrame
df = pd.DataFrame({
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [28, np.nan, 25, 30],
'成绩': [85, 92, np.nan, 95]
})
# 1. 检查缺失值
print(df.isnull()) # 返回布尔值 DataFrame,True 表示缺失
print(df.isnull().sum()) # 统计每列缺失值的个数
# 2. 删除包含缺失值的行
df_dropped = df.dropna() # 只要有缺失就删除该行
print(df_dropped)
# 3. 填充缺失值
df_filled = df.fillna(0) # 用 0 填充
df_filled = df.fillna({'年龄': 0, '成绩': 60}) # 不同列用不同值填充
df_filled = df.fillna(df['成绩'].mean()) # 用平均值填充
十一、数据合并
实际工作中,数据往往分散在多个文件里。比如用户信息在一个文件,订单信息在另一个文件。需要用共同的列把它们拼在一起。
# 用户表
users = pd.DataFrame({
'用户ID': [1, 2, 3],
'姓名': ['张三', '李四', '王五']
})
# 订单表
orders = pd.DataFrame({
'订单ID': [101, 102, 103, 104],
'用户ID': [1, 2, 1, 3],
'金额': [99, 150, 200, 75]
})
# 合并:按“用户ID”把两张表拼起来
merged = pd.merge(users, orders, on='用户ID', how='inner')
print(merged)
输出:
用户ID 姓名 订单ID 金额
0 1 张三 101 99
1 1 张三 103 200
2 2 李四 102 150
3 3 王五 104 75
合并类型(how 参数):
'inner':只保留两张表中都有的行(交集)。'left':保留左表的所有行,右表匹配不上的填 NaN。'right':保留右表的所有行。'outer':保留两表的所有行(并集)。
这和数据库的 JOIN 操作完全对应。如果你学过 MySQL,这里的 pd.merge() 和 SQL 的 JOIN 是同一个概念。
十二、导出数据
处理完数据后,通常需要导出成文件:
# 导出为 CSV
df.to_csv('result.csv', index=False, encoding='utf-8-sig')
# index=False 表示不导出行索引
# encoding='utf-8-sig' 在 Excel 中打开不会乱码
# 导出为 Excel
df.to_excel('result.xlsx', index=False, sheet_name='Sheet1')
十三、综合演示:销售数据分析
下面这个示例综合运用了本篇学到的知识——读取数据、筛选、分组统计、排序、导出结果。使用一个虚构的销售数据集:
import pandas as pd
# 1. 创建示例数据(实际工作中是从 CSV 文件读取)
data = {
'日期': ['2024-01-05', '2024-01-12', '2024-01-18', '2024-02-03',
'2024-02-15', '2024-02-22', '2024-03-08', '2024-03-20'],
'产品': ['手机', '电脑', '手机', '平板',
'电脑', '手机', '平板', '电脑'],
'地区': ['华东', '华北', '华东', '华南',
'华北', '华东', '华南', '华东'],
'销量': [120, 45, 150, 80, 55, 130, 70, 60],
'单价': [2999, 5999, 2999, 1999, 5999, 2999, 1999, 5999]
}
df = pd.DataFrame(data)
# 2. 新增计算列:销售额 = 销量 * 单价
df['销售额'] = df['销量'] * df['单价']
# 3. 查看基本信息
print('===== 数据概览 =====')
print(f'共 {len(df)} 条记录')
print(f'总销售额:{df["销售额"].sum():,} 元')
# 4. 各产品的销售汇总
print('\n===== 各产品销售汇总 =====')
product_summary = df.groupby('产品').agg(
总销量=('销量', 'sum'),
总销售额=('销售额', 'sum'),
平均单价=('单价', 'mean')
).sort_values('总销售额', ascending=False)
print(product_summary)
# 5. 各地区的销售情况
print('\n===== 各地区销售情况 =====')
region_summary = df.groupby('地区').agg(
总销量=('销量', 'sum'),
总销售额=('销售额', 'sum')
).sort_values('总销售额', ascending=False)
print(region_summary)
# 6. 筛选销量大于 100 的大单
print('\n===== 销量大于 100 的大单 =====')
big_orders = df[df['销量'] > 100].sort_values('销量', ascending=False)
print(big_orders[['日期', '产品', '地区', '销量', '销售额']])
# 7. 导出结果
product_summary.to_csv('产品汇总.csv', encoding='utf-8-sig')
region_summary.to_csv('地区汇总.csv', encoding='utf-8-sig')
print('\n分析结果已导出为 CSV 文件')
代码逻辑:
- 第一步:创建数据。实际项目中这里会替换为
pd.read_csv()。 - 第二步:计算派生字段。销售额不是原始数据,但可以通过销量和单价算出来。
- 第三到第六步:分组、排序、筛选——数据分析的三个最核心操作。
- 第七步:导出结果。处理完的数据存成 CSV,方便分享或进一步加工。
十四、本篇动手练习
练习 1:成绩分析
新建 practice9-1.py。创建一个包含 20 名学生的 DataFrame,字段包括:姓名、班级(一班/二班/三班)、语文成绩、数学成绩、英语成绩。完成以下分析:
- 计算每个学生的总分和平均分
- 按班级分组,统计每班的各科平均分
- 找出总分最高的 3 名学生
- 找出数学不及格(小于 60 分)的学生
练习 2:使用真实数据
新建 practice9-2.py。在网络上找一个公开的 CSV 数据集(推荐 Kaggle 或 GitHub 上的开放数据),用 Pandas 读取并做简单的分析。至少包括:查看基本信息、按某列筛选、按某列分组统计、排序。
练习 3:合并数据
新建 practice9-3.py。创建两个 DataFrame:students(学号、姓名、班级)和 scores(学号、科目、分数)。用 pd.merge() 合并两张表,然后统计每个学生的平均分。
十五、本篇小结
这一篇你进入了 Python 数据分析的世界:
- Pandas 是什么:Python 中处理表格数据的核心库。两个核心数据结构:Series(一列数据)和 DataFrame(一张表格)。
- 读取文件:
pd.read_csv()读取 CSV,pd.read_excel()读取 Excel。 - 查看数据:
head()看前几行,info()看概览,describe()看统计摘要,shape看行列数。 - 访问数据:
df['列名']选列,df.loc[]按索引选行,df.iloc[]按位置选行。 - 筛选数据:
df[条件],多条件用&(与)、|(或)。每个条件必须用括号包裹。 - 排序:
df.sort_values('列名', ascending=False)。 - 新增列:直接赋值
df['新列'] = ...,apply()逐元素处理。 - 分组统计:
df.groupby('列名')['统计列'].聚合函数(),agg()同时做多种统计。 - 缺失值:
dropna()删除缺失行,fillna()填充缺失值。 - 合并数据:
pd.merge(表1, 表2, on='共同列'),类似数据库 JOIN。 - 导出:
to_csv()、to_excel()。
Pandas 的内容非常丰富,这一篇覆盖了日常使用中最频繁的 80% 操作。把这些操作练熟,你就可以用 Python 处理绝大多数表格数据了。
下一篇预告
下一篇——《自动化脚本——用 Python 干杂活》:批量重命名文件、自动发送邮件、操作 Excel/Word、定时执行任务。这些是 Python 在日常办公和运维中最实用的自动化技能。我们不会引入新概念,而是用你已经学过的文件读写、函数、模块知识,写出真正能帮你省时间的实用工具脚本。
Python 零基础入门,每周更新。













暂无评论内容