Pandas 数据处理详解
引言
Pandas 是 Python 中最强大的数据处理和分析库之一,它提供了高效、灵活的数据结构,让数据分析变得简单直观。无论是处理 Excel 表格、CSV 文件,还是进行复杂的数据分析,Pandas 都是不可或缺的工具。
本教程特点:
- 每个概念都配有可直接运行的代码示例
- 代码可以直接复制到 Python 解释器中执行
- 循序渐进,从基础到高级
- 包含实际应用场景和最佳实践
学习建议:
- 阅读每个示例代码
- 复制代码到 Python 解释器或 Jupyter Notebook 中运行
- 尝试修改代码,观察结果变化
- 完成每个部分的练习
安装 Pandas:
pip install pandas
第一部分:Pandas 基础
1. 什么是 Pandas?
Pandas 提供了两个核心数据结构:
- Series:一维数据,类似带标签的数组
- DataFrame:二维数据,类似 Excel 表格
2. 导入 Pandas
# 示例 1:导入 Pandas
import pandas as pd
import numpy as np
# 查看 Pandas 版本
print(f"Pandas 版本:{pd.__version__}")
运行结果:
Pandas 版本:2.0.0
第二部分:Series(序列)
1. 创建 Series
# 示例 2:创建 Series
import pandas as pd
# 方法1:从列表创建
s1 = pd.Series([1, 3, 5, 7, 9])
print("从列表创建:")
print(s1)
print()
# 方法2:指定索引
s2 = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])
print("指定索引:")
print(s2)
print()
# 方法3:从字典创建
s3 = pd.Series({'苹果': 5, '香蕉': 3, '橙子': 8})
print("从字典创建:")
print(s3)
print()
# 方法4:指定数据类型
s4 = pd.Series([1.5, 2.5, 3.5], dtype='float32')
print("指定数据类型:")
print(s4)
print(f"数据类型:{s4.dtype}")
运行结果:
从列表创建:
0 1
1 3
2 5
3 7
4 9
dtype: int64
指定索引:
a 10
b 20
c 30
d 40
dtype: int64
从字典创建:
苹果 5
香蕉 3
橙子 8
dtype: int64
指定数据类型:
0 1.5
1 2.5
2 3.5
dtype: float32
数据类型:float32
2. Series 的基本操作
# 示例 3:Series 基本操作
import pandas as pd
s = pd.Series([10, 20, 30, 40, 50], index=['a', 'b', 'c', 'd', 'e'])
# 访问元素
print(f"第一个元素:{s[0]}")
print(f"通过索引访问:{s['a']}")
print(f"前三个元素:\n{s[:3]}")
print()
# 基本属性
print(f"索引:{s.index}")
print(f"值:{s.values}")
print(f"长度:{len(s)}")
print(f"大小:{s.size}")
print(f"形状:{s.shape}")
print()
# 统计信息
print("统计信息:")
print(f"平均值:{s.mean()}")
print(f"总和:{s.sum()}")
print(f"最大值:{s.max()}")
print(f"最小值:{s.min()}")
print(f"标准差:{s.std()}")
print()
# 布尔索引
print("大于30的元素:")
print(s[s > 30])
运行结果:
第一个元素:10
通过索引访问:10
前三个元素:
a 10
b 20
c 30
dtype: int64
索引:Index(['a', 'b', 'c', 'd', 'e'], dtype='object')
值:[10 20 30 40 50]
长度:5
大小:5
形状:(5,)
统计信息:
平均值:30.0
总和:150
最大值:50
最小值:10
标准差:15.811388300841896
大于30的元素:
d 40
e 50
dtype: int64
第三部分:DataFrame(数据框)
1. 创建 DataFrame
# 示例 4:创建 DataFrame
import pandas as pd
# 方法1:从字典创建
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [25, 30, 28, 35],
'城市': ['北京', '上海', '广州', '深圳'],
'工资': [8000, 12000, 10000, 15000]
}
df1 = pd.DataFrame(data)
print("从字典创建:")
print(df1)
print()
# 方法2:从列表的列表创建
data2 = [
['张三', 25, '北京', 8000],
['李四', 30, '上海', 12000],
['王五', 28, '广州', 10000]
]
df2 = pd.DataFrame(data2, columns=['姓名', '年龄', '城市', '工资'])
print("从列表创建:")
print(df2)
print()
# 方法3:从 NumPy 数组创建
import numpy as np
arr = np.random.randn(3, 4)
df3 = pd.DataFrame(arr, columns=['A', 'B', 'C', 'D'])
print("从 NumPy 数组创建:")
print(df3)
print()
# 方法4:创建空 DataFrame
df4 = pd.DataFrame(columns=['姓名', '年龄'])
print("空 DataFrame:")
print(df4)
运行结果:
从字典创建:
姓名 年龄 城市 工资
0 张三 25 北京 8000
1 李四 30 上海 12000
2 王五 28 广州 10000
3 赵六 35 深圳 15000
从列表创建:
姓名 年龄 城市 工资
0 张三 25 北京 8000
1 李四 30 上海 12000
2 王五 28 广州 10000
从 NumPy 数组创建:
A B C D
0 0.374540 1.950714 0.731994 0.598658
1 0.156019 0.155995 0.058084 0.866176
2 0.601115 0.708073 0.020584 0.969910
空 DataFrame:
Empty DataFrame
Columns: [姓名, 年龄]
Index: [0, 1, 2]
2. DataFrame 的基本属性
# 示例 5:DataFrame 基本属性
import pandas as pd
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [25, 30, 28, 35],
'城市': ['北京', '上海', '广州', '深圳'],
'工资': [8000, 12000, 10000, 15000]
}
df = pd.DataFrame(data)
# 基本信息
print("DataFrame 形状:")
print(df.shape) # (行数, 列数)
print()
print("列名:")
print(df.columns)
print()
print("索引:")
print(df.index)
print()
print("数据类型:")
print(df.dtypes)
print()
print("基本信息:")
print(df.info())
print()
print("统计摘要:")
print(df.describe())
print()
print("前几行:")
print(df.head(2))
print()
print("后几行:")
print(df.tail(2))
运行结果:
DataFrame 形状:
(4, 4)
列名:
Index(['姓名', '年龄', '城市', '工资'], dtype='object')
索引:
RangeIndex(start=0, stop=4, step=1)
数据类型:
姓名 object
年龄 int64
城市 object
工资 int64
dtype: object
基本信息:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 姓名 4 non-null object
1 年龄 4 non-null int64
2 城市 4 non-null object
3 工资 4 non-null int64
dtypes: int64(2), object(2)
memory usage: 256.0+ bytes
None
统计摘要:
年龄 工资
count 4.000000 4.000000
mean 29.500000 11250.000000
std 4.201190 3041.381265
min 25.000000 8000.000000
25% 27.250000 9500.000000
50% 29.000000 11000.000000
75% 31.750000 12750.000000
max 35.000000 15000.000000
前几行:
姓名 年龄 城市 工资
0 张三 25 北京 8000
1 李四 30 上海 12000
后几行:
姓名 年龄 城市 工资
2 王五 28 广州 10000
3 赵六 35 深圳 15000
第四部分:数据读取和写入
1. 读取 CSV 文件
# 示例 6:读取和写入 CSV 文件
import pandas as pd
# 首先创建一个示例 CSV 文件
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [25, 30, 28, 35],
'城市': ['北京', '上海', '广州', '深圳'],
'工资': [8000, 12000, 10000, 15000]
}
df = pd.DataFrame(data)
# 保存为 CSV
df.to_csv('employees.csv', index=False, encoding='utf-8-sig')
print("已创建 employees.csv 文件")
print()
# 读取 CSV 文件
df_read = pd.read_csv('employees.csv', encoding='utf-8-sig')
print("读取的 CSV 文件:")
print(df_read)
print()
# 读取时指定参数
df_read2 = pd.read_csv('employees.csv',
encoding='utf-8-sig',
usecols=['姓名', '年龄'], # 只读取指定列
nrows=2) # 只读取前2行
print("读取指定列和前2行:")
print(df_read2)
运行结果:
已创建 employees.csv 文件
读取的 CSV 文件:
姓名 年龄 城市 工资
0 张三 25 北京 8000
1 李四 30 上海 12000
2 王五 28 广州 10000
3 赵六 35 深圳 15000
读取指定列和前2行:
姓名 年龄
0 张三 25
1 李四 30
2. 读取 Excel 文件
# 示例 7:读取和写入 Excel 文件
import pandas as pd
# 创建数据
data = {
'姓名': ['张三', '李四', '王五'],
'年龄': [25, 30, 28],
'工资': [8000, 12000, 10000]
}
df = pd.DataFrame(data)
# 保存为 Excel
df.to_excel('employees.xlsx', index=False, sheet_name='员工信息')
print("已创建 employees.xlsx 文件")
print()
# 读取 Excel 文件
df_excel = pd.read_excel('employees.xlsx', sheet_name='员工信息')
print("读取的 Excel 文件:")
print(df_excel)
print()
# 读取多个工作表
# 假设有多个工作表
with pd.ExcelWriter('multi_sheet.xlsx') as writer:
df.to_excel(writer, sheet_name='Sheet1', index=False)
df.to_excel(writer, sheet_name='Sheet2', index=False)
# 读取所有工作表
excel_file = pd.ExcelFile('multi_sheet.xlsx')
print("工作表名称:")
print(excel_file.sheet_names)
注意:读取 Excel 文件需要安装 openpyxl 或 xlrd:
pip install openpyxl
3. 读取 JSON 文件
# 示例 8:读取和写入 JSON 文件
import pandas as pd
# 创建数据
data = {
'姓名': ['张三', '李四', '王五'],
'年龄': [25, 30, 28],
'工资': [8000, 12000, 10000]
}
df = pd.DataFrame(data)
# 保存为 JSON
df.to_json('employees.json', orient='records', force_ascii=False)
print("已创建 employees.json 文件")
print()
# 读取 JSON 文件
df_json = pd.read_json('employees.json')
print("读取的 JSON 文件:")
print(df_json)
第五部分:数据选择和索引
1. 选择列
# 示例 9:选择列
import pandas as pd
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [25, 30, 28, 35],
'城市': ['北京', '上海', '广州', '深圳'],
'工资': [8000, 12000, 10000, 15000]
}
df = pd.DataFrame(data)
# 方法1:使用列名(返回 Series)
print("选择单列(返回 Series):")
print(df['姓名'])
print()
# 方法2:使用点号(仅当列名是有效的 Python 标识符时)
print("使用点号选择列:")
print(df.姓名)
print()
# 方法3:选择多列(返回 DataFrame)
print("选择多列:")
print(df[['姓名', '年龄']])
print()
# 方法4:使用 loc 选择列
print("使用 loc 选择列:")
print(df.loc[:, '姓名':'城市']) # 选择从'姓名'到'城市'的所有列
运行结果:
选择单列(返回 Series):
0 张三
1 李四
2 王五
3 赵六
Name: 姓名, dtype: object
使用点号选择列:
0 张三
1 李四
2 王五
3 赵六
Name: 姓名, dtype: object
选择多列:
姓名 年龄
0 张三 25
1 李四 30
2 王五 28
3 赵六 35
使用 loc 选择列:
姓名 年龄 城市
0 张三 25 北京
1 李四 30 上海
2 王五 28 广州
3 赵六 35 深圳
2. 选择行
# 示例 10:选择行
import pandas as pd
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [25, 30, 28, 35],
'城市': ['北京', '上海', '广州', '深圳'],
'工资': [8000, 12000, 10000, 15000]
}
df = pd.DataFrame(data)
# 方法1:使用索引位置(iloc)
print("选择第一行:")
print(df.iloc[0])
print()
print("选择前两行:")
print(df.iloc[0:2])
print()
print("选择最后一行:")
print(df.iloc[-1])
print()
# 方法2:使用标签索引(loc)
print("使用 loc 选择行:")
print(df.loc[0:2]) # 注意:loc 包含结束位置
print()
# 方法3:使用布尔索引
print("选择年龄大于28的行:")
print(df[df['年龄'] > 28])
print()
print("选择工资大于10000的行:")
print(df[df['工资'] > 10000])
print()
# 方法4:多条件筛选
print("多条件筛选(年龄>25 且 工资>9000):")
print(df[(df['年龄'] > 25) & (df['工资'] > 9000)])
运行结果:
选择第一行:
姓名 张三
年龄 25
城市 北京
工资 8000
Name: 0, dtype: object
选择前两行:
姓名 年龄 城市 工资
0 张三 25 北京 8000
1 李四 30 上海 12000
选择最后一行:
姓名 赵六
年龄 35
城市 深圳
工资 15000
Name: 3, dtype: object
使用 loc 选择行:
姓名 年龄 城市 工资
0 张三 25 北京 8000
1 李四 30 上海 12000
2 王五 28 广州 10000
选择年龄大于28的行:
姓名 年龄 城市 工资
1 李四 30 上海 12000
3 赵六 35 深圳 15000
选择工资大于10000的行:
姓名 年龄 城市 工资
1 李四 30 上海 12000
3 赵六 35 深圳 15000
多条件筛选(年龄>25 且 工资>9000):
姓名 年龄 城市 工资
1 李四 30 上海 12000
2 王五 28 广州 10000
3 赵六 35 深圳 15000
3. 选择行和列(loc 和 iloc)
# 示例 11:使用 loc 和 iloc 选择数据
import pandas as pd
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [25, 30, 28, 35],
'城市': ['北京', '上海', '广州', '深圳'],
'工资': [8000, 12000, 10000, 15000]
}
df = pd.DataFrame(data)
# loc:基于标签的选择
print("loc - 选择特定行和列:")
print(df.loc[0, '姓名']) # 单个值
print()
print(df.loc[0:2, ['姓名', '年龄']]) # 多行多列
print()
# iloc:基于位置的选择
print("iloc - 基于位置选择:")
print(df.iloc[0, 0]) # 第一个元素
print()
print(df.iloc[0:2, 0:2]) # 前两行前两列
print()
# 使用条件选择
print("条件选择:")
print(df.loc[df['年龄'] > 28, ['姓名', '工资']])
运行结果:
loc - 选择特定行和列:
张三
姓名 年龄
0 张三 25
1 李四 30
2 王五 28
iloc - 基于位置选择:
张三
姓名 年龄
0 张三 25
1 李四 30
条件选择:
姓名 工资
1 李四 12000
3 赵六 15000
第六部分:数据清洗
1. 处理缺失值
# 示例 12:处理缺失值
import pandas as pd
import numpy as np
# 创建包含缺失值的数据
data = {
'姓名': ['张三', '李四', '王五', '赵六', '钱七'],
'年龄': [25, 30, None, 35, 28],
'城市': ['北京', '上海', None, '深圳', '杭州'],
'工资': [8000, 12000, 10000, None, 9000]
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)
print()
# 检查缺失值
print("检查缺失值:")
print(df.isnull())
print()
print("每列缺失值数量:")
print(df.isnull().sum())
print()
# 删除包含缺失值的行
print("删除包含缺失值的行:")
df_dropna = df.dropna()
print(df_dropna)
print()
# 填充缺失值
print("填充缺失值:")
df_filled = df.fillna({
'年龄': df['年龄'].mean(),
'城市': '未知',
'工资': df['工资'].median()
})
print(df_filled)
print()
# 前向填充
print("前向填充:")
df_ffill = df.fillna(method='ffill')
print(df_ffill)
运行结果:
原始数据:
姓名 年龄 城市 工资
0 张三 25.0 北京 8000.0
1 李四 30.0 上海 12000.0
2 王五 NaN None 10000.0
3 赵六 35.0 深圳 NaN
4 钱七 28.0 杭州 9000.0
检查缺失值:
姓名 年龄 城市 工资
0 False False False False
1 False False False False
2 False True True False
3 False False False True
4 False False False False
每列缺失值数量:
姓名 0
年龄 1
城市 1
工资 1
dtype: int64
删除包含缺失值的行:
姓名 年龄 城市 工资
0 张三 25.0 北京 8000.0
1 李四 30.0 上海 12000.0
4 钱七 28.0 杭州 9000.0
填充缺失值:
姓名 年龄 城市 工资
0 张三 25.0 北京 8000.0
1 李四 30.0 上海 12000.0
2 王五 29.5 未知 10000.0
3 赵六 35.0 深圳 10000.0
4 钱七 28.0 杭州 9000.0
前向填充:
姓名 年龄 城市 工资
0 张三 25.0 北京 8000.0
1 李四 30.0 上海 12000.0
2 王五 30.0 上海 10000.0
3 赵六 35.0 深圳 10000.0
4 钱七 28.0 杭州 9000.0
2. 处理重复值
# 示例 13:处理重复值
import pandas as pd
# 创建包含重复值的数据
data = {
'姓名': ['张三', '李四', '王五', '张三', '李四'],
'年龄': [25, 30, 28, 25, 30],
'工资': [8000, 12000, 10000, 8000, 12000]
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)
print()
# 检查重复值
print("检查重复行:")
print(df.duplicated())
print()
print("重复行数量:")
print(df.duplicated().sum())
print()
# 删除重复值
print("删除重复行:")
df_unique = df.drop_duplicates()
print(df_unique)
print()
# 基于特定列删除重复值
print("基于'姓名'列删除重复:")
df_unique_name = df.drop_duplicates(subset=['姓名'])
print(df_unique_name)
运行结果:
原始数据:
姓名 年龄 工资
0 张三 25 8000
1 李四 30 12000
2 王五 28 10000
3 张三 25 8000
4 李四 30 12000
检查重复行:
0 False
1 False
2 False
3 True
4 True
dtype: bool
重复行数量:
2
删除重复行:
姓名 年龄 工资
0 张三 25 8000
1 李四 30 12000
2 王五 28 10000
基于'姓名'列删除重复:
姓名 年龄 工资
0 张三 25 8000
1 李四 30 12000
2 王五 28 10000
3. 数据类型转换
# 示例 14:数据类型转换
import pandas as pd
data = {
'姓名': ['张三', '李四', '王五'],
'年龄': ['25', '30', '28'], # 字符串类型
'工资': [8000.5, 12000.3, 10000.7]
}
df = pd.DataFrame(data)
print("原始数据类型:")
print(df.dtypes)
print()
# 转换数据类型
df['年龄'] = df['年龄'].astype(int)
df['工资'] = df['工资'].astype(int)
print("转换后的数据类型:")
print(df.dtypes)
print()
print("转换后的数据:")
print(df)
第七部分:数据操作
1. 添加和删除列
# 示例 15:添加和删除列
import pandas as pd
data = {
'姓名': ['张三', '李四', '王五'],
'年龄': [25, 30, 28],
'工资': [8000, 12000, 10000]
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)
print()
# 添加新列
df['城市'] = ['北京', '上海', '广州']
print("添加'城市'列:")
print(df)
print()
# 使用计算添加列
df['年薪'] = df['工资'] * 12
print("添加'年薪'列(计算列):")
print(df)
print()
# 删除列
df_dropped = df.drop('年薪', axis=1)
print("删除'年薪'列:")
print(df_dropped)
print()
# 删除多列
df_dropped2 = df.drop(['城市', '年薪'], axis=1)
print("删除多列:")
print(df_dropped2)
运行结果:
原始数据:
姓名 年龄 工资
0 张三 25 8000
1 李四 30 12000
2 王五 28 10000
添加'城市'列:
姓名 年龄 工资 城市
0 张三 25 8000 北京
1 李四 30 12000 上海
2 王五 28 10000 广州
添加'年薪'列(计算列):
姓名 年龄 工资 城市 年薪
0 张三 25 8000 北京 96000
1 李四 30 12000 上海 144000
2 王五 28 10000 广州 120000
删除'年薪'列:
姓名 年龄 工资 城市
0 张三 25 8000 北京
1 李四 30 12000 上海
2 王五 28 10000 广州
删除多列:
姓名 年龄 工资
0 张三 25 8000
1 李四 30 12000
2 王五 28 10000
2. 添加和删除行
# 示例 16:添加和删除行
import pandas as pd
data = {
'姓名': ['张三', '李四', '王五'],
'年龄': [25, 30, 28],
'工资': [8000, 12000, 10000]
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)
print()
# 添加新行(使用 append,已弃用,推荐使用 concat)
new_row = pd.DataFrame({'姓名': ['赵六'], '年龄': [35], '工资': [15000]})
df = pd.concat([df, new_row], ignore_index=True)
print("添加新行:")
print(df)
print()
# 删除行
df_dropped = df.drop(0) # 删除第一行
print("删除第一行:")
print(df_dropped)
print()
# 删除多行
df_dropped2 = df.drop([0, 2])
print("删除多行:")
print(df_dropped2)
3. 排序
# 示例 17:数据排序
import pandas as pd
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [25, 30, 28, 35],
'工资': [8000, 12000, 10000, 15000]
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)
print()
# 按单列排序
print("按年龄升序排序:")
print(df.sort_values('年龄'))
print()
print("按工资降序排序:")
print(df.sort_values('工资', ascending=False))
print()
# 按多列排序
print("按年龄和工资排序:")
print(df.sort_values(['年龄', '工资'], ascending=[True, False]))
print()
# 重置索引
df_sorted = df.sort_values('年龄')
df_sorted = df_sorted.reset_index(drop=True)
print("排序后重置索引:")
print(df_sorted)
运行结果:
原始数据:
姓名 年龄 工资
0 张三 25 8000
1 李四 30 12000
2 王五 28 10000
3 赵六 35 15000
按年龄升序排序:
姓名 年龄 工资
0 张三 25 8000
2 王五 28 10000
1 李四 30 12000
3 赵六 35 15000
按工资降序排序:
姓名 年龄 工资
3 赵六 35 15000
1 李四 30 12000
2 王五 28 10000
0 张三 25 8000
按年龄和工资排序:
姓名 年龄 工资
0 张三 25 8000
2 王五 28 10000
1 李四 30 12000
3 赵六 35 15000
排序后重置索引:
姓名 年龄 工资
0 张三 25 8000
1 王五 28 10000
2 李四 30 12000
3 赵六 35 15000
第八部分:数据分组和聚合
1. 分组操作(groupby)
# 示例 18:分组操作
import pandas as pd
data = {
'部门': ['销售', '销售', '技术', '技术', '销售', '技术'],
'姓名': ['张三', '李四', '王五', '赵六', '钱七', '孙八'],
'工资': [8000, 10000, 12000, 15000, 9000, 13000]
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)
print()
# 按部门分组
grouped = df.groupby('部门')
print("分组后的组:")
for name, group in grouped:
print(f"\n{name} 部门:")
print(group)
print()
# 分组聚合
print("各部门平均工资:")
print(grouped['工资'].mean())
print()
print("各部门工资总和:")
print(grouped['工资'].sum())
print()
print("各部门员工数量:")
print(grouped.size())
print()
# 多列聚合
print("多列聚合:")
print(grouped.agg({
'工资': ['mean', 'sum', 'max', 'min']
}))
运行结果:
原始数据:
部门 姓名 工资
0 销售 张三 8000
1 销售 李四 10000
2 技术 王五 12000
3 技术 赵六 15000
4 销售 钱七 9000
5 技术 孙八 13000
分组后的组:
销售 部门:
部门 姓名 工资
0 销售 张三 8000
1 销售 李四 10000
4 销售 钱七 9000
技术 部门:
部门 姓名 工资
2 技术 王五 12000
3 技术 赵六 15000
5 技术 孙八 13000
各部门平均工资:
部门
技术 13333.333333
销售 9000.000000
Name: 工资, dtype: float64
各部门工资总和:
部门
技术 40000
销售 27000
Name: 工资, dtype: int64
各部门员工数量:
部门
技术 3
销售 3
dtype: int64
多列聚合:
工资
mean sum max min
部门
技术 13333.333333 40000 15000 12000
销售 9000.000000 27000 10000 8000
2. 透视表(pivot_table)
# 示例 19:透视表
import pandas as pd
data = {
'日期': ['2024-01-01', '2024-01-01', '2024-01-02', '2024-01-02', '2024-01-03', '2024-01-03'],
'产品': ['A', 'B', 'A', 'B', 'A', 'B'],
'销售额': [1000, 1500, 1200, 1800, 1100, 1600]
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)
print()
# 创建透视表
pivot = pd.pivot_table(df,
values='销售额',
index='日期',
columns='产品',
aggfunc='sum')
print("透视表:")
print(pivot)
print()
# 多值透视表
data2 = {
'日期': ['2024-01-01', '2024-01-01', '2024-01-02', '2024-01-02'],
'产品': ['A', 'B', 'A', 'B'],
'销售额': [1000, 1500, 1200, 1800],
'数量': [10, 15, 12, 18]
}
df2 = pd.DataFrame(data2)
pivot2 = pd.pivot_table(df2,
values=['销售额', '数量'],
index='日期',
columns='产品',
aggfunc='sum')
print("多值透视表:")
print(pivot2)
运行结果:
原始数据:
日期 产品 销售额
0 2024-01-01 A 1000
1 2024-01-01 B 1500
2 2024-01-02 A 1200
3 2024-01-02 B 1800
4 2024-01-03 A 1100
5 2024-01-03 B 1600
透视表:
产品 A B
日期
2024-01-01 1000 1500
2024-01-02 1200 1800
2024-01-03 1100 1600
多值透视表:
销售额 数量
产品 A B A B
日期
2024-01-01 1000 1500 10 15
2024-01-02 1200 1800 12 18
第九部分:数据合并
1. 合并(merge)
# 示例 20:数据合并
import pandas as pd
# 创建两个 DataFrame
df1 = pd.DataFrame({
'员工ID': [1, 2, 3, 4],
'姓名': ['张三', '李四', '王五', '赵六'],
'部门ID': [101, 102, 101, 103]
})
df2 = pd.DataFrame({
'部门ID': [101, 102, 103, 104],
'部门名称': ['销售部', '技术部', '财务部', '人事部']
})
print("DataFrame 1:")
print(df1)
print()
print("DataFrame 2:")
print(df2)
print()
# 内连接(inner join)
print("内连接:")
df_inner = pd.merge(df1, df2, on='部门ID', how='inner')
print(df_inner)
print()
# 左连接(left join)
print("左连接:")
df_left = pd.merge(df1, df2, on='部门ID', how='left')
print(df_left)
print()
# 外连接(outer join)
print("外连接:")
df_outer = pd.merge(df1, df2, on='部门ID', how='outer')
print(df_outer)
运行结果:
DataFrame 1:
员工ID 姓名 部门ID
0 1 张三 101
1 2 李四 102
2 3 王五 101
3 4 赵六 103
DataFrame 2:
部门ID 部门名称
0 101 销售部
1 102 技术部
2 103 财务部
3 104 人事部
内连接:
员工ID 姓名 部门ID 部门名称
0 1 张三 101 销售部
1 2 李四 102 技术部
2 3 王五 101 销售部
3 4 赵六 103 财务部
左连接:
员工ID 姓名 部门ID 部门名称
0 1 张三 101 销售部
1 2 李四 102 技术部
2 3 王五 101 销售部
3 4 赵六 103 财务部
外连接:
员工ID 姓名 部门ID 部门名称
0 1.0 张三 101.0 销售部
1 2.0 李四 102.0 技术部
2 3.0 王五 101.0 销售部
3 4.0 赵六 103.0 财务部
4 NaN NaN 104.0 人事部
2. 连接(concat)
# 示例 21:连接操作
import pandas as pd
# 创建两个 DataFrame
df1 = pd.DataFrame({
'A': [1, 2, 3],
'B': [4, 5, 6]
})
df2 = pd.DataFrame({
'A': [7, 8, 9],
'B': [10, 11, 12]
})
print("DataFrame 1:")
print(df1)
print()
print("DataFrame 2:")
print(df2)
print()
# 垂直连接(沿行方向)
print("垂直连接:")
df_concat = pd.concat([df1, df2], ignore_index=True)
print(df_concat)
print()
# 水平连接(沿列方向)
print("水平连接:")
df_concat_h = pd.concat([df1, df2], axis=1)
print(df_concat_h)
第十部分:时间序列处理
1. 创建时间序列
# 示例 22:时间序列处理
import pandas as pd
# 创建日期范围
dates = pd.date_range('2024-01-01', periods=7, freq='D')
print("日期范围:")
print(dates)
print()
# 创建时间序列数据
ts = pd.Series([100, 105, 110, 108, 112, 115, 120], index=dates)
print("时间序列:")
print(ts)
print()
# 创建带日期的 DataFrame
df = pd.DataFrame({
'日期': pd.date_range('2024-01-01', periods=5, freq='D'),
'销售额': [1000, 1200, 1100, 1300, 1250]
})
print("带日期的 DataFrame:")
print(df)
print()
# 将日期列设置为索引
df['日期'] = pd.to_datetime(df['日期'])
df.set_index('日期', inplace=True)
print("日期作为索引:")
print(df)
运行结果:
日期范围:
DatetimeIndex(['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04',
'2024-01-05', '2024-01-06', '2024-01-07'],
dtype='datetime64[ns]', freq='D')
时间序列:
2024-01-01 100
2024-01-02 105
2024-01-03 110
2024-01-04 108
2024-01-05 112
2024-01-06 115
2024-01-07 120
Freq: D, dtype: int64
带日期的 DataFrame:
日期 销售额
0 2024-01-01 1000
1 2024-01-02 1200
2 2024-01-03 1100
3 2024-01-04 1300
4 2024-01-05 1250
日期作为索引:
销售额
日期
2024-01-01 1000
2024-01-02 1200
2024-01-03 1100
2024-01-04 1300
2024-01-05 1250
2. 时间序列操作
# 示例 23:时间序列操作
import pandas as pd
# 创建时间序列数据
dates = pd.date_range('2024-01-01', periods=30, freq='D')
df = pd.DataFrame({
'日期': dates,
'销售额': range(1000, 1030)
})
df.set_index('日期', inplace=True)
print("原始数据(前5行):")
print(df.head())
print()
# 按周重采样
print("按周求和:")
weekly = df.resample('W').sum()
print(weekly)
print()
# 按月重采样
print("按月求和:")
monthly = df.resample('M').sum()
print(monthly)
print()
# 移动平均
df['移动平均7天'] = df['销售额'].rolling(window=7).mean()
print("添加7天移动平均:")
print(df.head(10))
第十一部分:实际应用示例
1. 学生成绩分析系统
# 示例 24:学生成绩分析系统
import pandas as pd
import numpy as np
# 创建学生成绩数据
np.random.seed(42)
data = {
'学号': [f'2024{i:04d}' for i in range(1, 21)],
'姓名': [f'学生{i}' for i in range(1, 21)],
'数学': np.random.randint(60, 101, 20),
'英语': np.random.randint(60, 101, 20),
'物理': np.random.randint(60, 101, 20),
'化学': np.random.randint(60, 101, 20)
}
df = pd.DataFrame(data)
# 计算总分和平均分
df['总分'] = df[['数学', '英语', '物理', '化学']].sum(axis=1)
df['平均分'] = df['总分'] / 4
# 添加等级
def get_grade(avg):
if avg >= 90:
return '优秀'
elif avg >= 80:
return '良好'
elif avg >= 70:
return '中等'
elif avg >= 60:
return '及格'
else:
return '不及格'
df['等级'] = df['平均分'].apply(get_grade)
print("学生成绩表:")
print(df)
print()
# 统计分析
print("=" * 50)
print("统计分析")
print("=" * 50)
print("\n各科平均分:")
print(df[['数学', '英语', '物理', '化学']].mean())
print()
print("\n各科最高分:")
print(df[['数学', '英语', '物理', '化学']].max())
print()
print("\n各等级人数:")
print(df['等级'].value_counts())
print()
print("\n平均分排名前5:")
print(df.nlargest(5, '平均分')[['姓名', '平均分', '等级']])
运行结果:
学生成绩表:
学号 姓名 数学 英语 物理 化学 总分 平均分 等级
0 20240001 学生1 92 75 95 78 340 85.00 良好
1 20240002 学生2 64 88 70 75 297 74.25 中等
2 20240003 学生3 67 78 95 88 328 82.00 良好
...(省略部分输出)
统计分析
==================================================
各科平均分:
数学 77.85
英语 78.20
物理 78.10
化学 78.15
dtype: float64
各科最高分:
数学 100
英语 99
物理 99
化学 99
dtype: int64
各等级人数:
良好 8
中等 6
优秀 4
及格 2
dtype: int64
平均分排名前5:
姓名 平均分 等级
0 学生1 85.00 良好
3 学生4 84.50 良好
...(省略部分输出)
2. 销售数据分析
# 示例 25:销售数据分析
import pandas as pd
import numpy as np
# 创建销售数据
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=100, freq='D')
data = {
'日期': dates,
'产品': np.random.choice(['A', 'B', 'C'], 100),
'销售额': np.random.randint(1000, 5000, 100),
'数量': np.random.randint(10, 100, 100)
}
df = pd.DataFrame(data)
# 计算单价
df['单价'] = df['销售额'] / df['数量']
print("销售数据(前10行):")
print(df.head(10))
print()
# 按产品分组分析
print("=" * 50)
print("按产品分析")
print("=" * 50)
product_analysis = df.groupby('产品').agg({
'销售额': ['sum', 'mean', 'count'],
'数量': 'sum',
'单价': 'mean'
}).round(2)
print(product_analysis)
print()
# 按日期分析
print("=" * 50)
print("按日期分析(按月)")
print("=" * 50)
df['月份'] = df['日期'].dt.month
monthly_analysis = df.groupby('月份').agg({
'销售额': 'sum',
'数量': 'sum'
}).round(2)
print(monthly_analysis)
第十二部分:高级功能
1. 应用函数(apply)
# 示例 26:使用 apply 应用函数
import pandas as pd
data = {
'姓名': ['张三', '李四', '王五'],
'年龄': [25, 30, 28],
'工资': [8000, 12000, 10000]
}
df = pd.DataFrame(data)
# 应用函数到列
def calculate_tax(salary):
if salary > 10000:
return salary * 0.1
else:
return salary * 0.05
df['税费'] = df['工资'].apply(calculate_tax)
df['税后工资'] = df['工资'] - df['税费']
print("应用函数后的数据:")
print(df)
print()
# 应用函数到行
def get_info(row):
return f"{row['姓名']},{row['年龄']}岁,工资{row['工资']}元"
df['信息'] = df.apply(get_info, axis=1)
print("添加信息列:")
print(df[['姓名', '信息']])
运行结果:
应用函数后的数据:
姓名 年龄 工资 税费 税后工资
0 张三 25 8000 400.0 7600.0
1 李四 30 12000 1200.0 10800.0
2 王五 28 10000 500.0 9500.0
添加信息列:
姓名 信息
0 张三 张三,25岁,工资8000元
1 李四 李四,30岁,工资12000元
2 王五 王五,28岁,工资10000元
2. 条件操作
# 示例 27:条件操作
import pandas as pd
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [25, 30, 28, 35],
'工资': [8000, 12000, 10000, 15000]
}
df = pd.DataFrame(data)
# 使用 where
df['高薪'] = df['工资'].where(df['工资'] > 10000, '否')
print("使用 where:")
print(df)
print()
# 使用 np.where
import numpy as np
df['等级'] = np.where(df['工资'] > 10000, '高', '低')
print("使用 np.where:")
print(df[['姓名', '工资', '等级']])
3. 数据透视和重塑
# 示例 28:数据重塑
import pandas as pd
# 创建数据
data = {
'日期': ['2024-01-01', '2024-01-01', '2024-01-02', '2024-01-02'],
'产品': ['A', 'B', 'A', 'B'],
'销售额': [1000, 1500, 1200, 1800]
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)
print()
# 透视
pivot = df.pivot(index='日期', columns='产品', values='销售额')
print("透视后:")
print(pivot)
print()
# 堆叠和取消堆叠
stacked = pivot.stack()
print("堆叠:")
print(stacked)
print()
unstacked = stacked.unstack()
print("取消堆叠:")
print(unstacked)
第十三部分:性能优化和最佳实践
1. 使用向量化操作
# 示例 29:向量化操作 vs 循环
import pandas as pd
import numpy as np
import time
# 创建大数据集
df = pd.DataFrame({
'A': np.random.randn(100000),
'B': np.random.randn(100000)
})
# 方法1:使用循环(慢)
start = time.time()
result1 = []
for i in range(len(df)):
result1.append(df.iloc[i]['A'] * df.iloc[i]['B'])
time1 = time.time() - start
# 方法2:使用向量化操作(快)
start = time.time()
result2 = df['A'] * df['B']
time2 = time.time() - start
print(f"循环方法耗时:{time1:.4f} 秒")
print(f"向量化方法耗时:{time2:.4f} 秒")
print(f"速度提升:{time1/time2:.2f} 倍")
2. 最佳实践
# 示例 30:最佳实践总结
import pandas as pd
# 1. 使用 copy() 避免意外修改原始数据
df1 = pd.DataFrame({'A': [1, 2, 3]})
df2 = df1.copy() # 推荐
df2['A'] = [4, 5, 6]
print("原始数据未被修改:")
print(df1)
print()
# 2. 使用 inplace 参数
df = pd.DataFrame({'A': [1, 2, 3, 4, 5]})
df.drop([0, 1], inplace=True) # 直接修改,不返回新对象
print("使用 inplace:")
print(df)
print()
# 3. 链式操作
data = {
'姓名': ['张三', '李四', '王五'],
'年龄': [25, 30, 28],
'工资': [8000, 12000, 10000]
}
df = pd.DataFrame(data)
result = (df
.query('年龄 > 25') # 筛选
.sort_values('工资', ascending=False) # 排序
.reset_index(drop=True)) # 重置索引
print("链式操作结果:")
print(result)
第十四部分:练习和总结
练习1:数据分析任务
# 练习1:完成以下任务
# 1. 创建一个包含学生信息的 DataFrame
# 2. 计算每个学生的平均分
# 3. 找出平均分最高的学生
# 4. 按班级分组,计算每班的平均分
# 在这里编写你的代码
练习2:数据清洗任务
# 练习2:完成以下任务
# 1. 创建一个包含缺失值的数据集
# 2. 处理缺失值(填充或删除)
# 3. 处理重复值
# 4. 数据类型转换
# 在这里编写你的代码
总结
核心概念:
- Series:一维数据结构
- DataFrame:二维数据结构
- 索引和选择:loc、iloc、布尔索引
- 数据清洗:处理缺失值、重复值
- 数据操作:添加、删除、排序
- 分组和聚合:groupby、透视表
- 数据合并:merge、concat
- 时间序列:日期处理、重采样
常用方法:
read_csv()/to_csv():CSV 文件读写read_excel()/to_excel():Excel 文件读写head()/tail():查看前后几行describe():统计摘要groupby():分组操作merge()/concat():数据合并apply():应用函数pivot_table():创建透视表
最佳实践:
- 使用向量化操作而不是循环
- 使用
copy()避免意外修改 - 合理使用
inplace参数 - 利用链式操作提高代码可读性
- 处理大数据时注意内存使用
下一步学习建议:
- 学习更多 Pandas 高级功能
- 结合 Matplotlib 进行数据可视化
- 学习数据分析和统计方法
- 实践真实项目,处理实际数据
- 阅读 Pandas 官方文档