Pandas数据分析完整学习指南
Pandas数据分析完整指南摘要 Pandas是Python核心数据分析库,提供Series和DataFrame两种核心数据结构。本指南系统讲解: 基础数据结构:Series(一维带标签数组)和DataFrame(二维表格)的创建与操作 数据处理:包括字符串操作(strip/split/replace等)、索引访问、属性查询 高级特性:继承NumPy的向量化运算、统计函数应用 数据I/O:支持多种
📚 Pandas数据分析完整学习指南
💡 核心定位:Pandas是Python中最强大的数据分析库,专门用于处理结构化数据,基于NumPy构建
📑 目录结构
1. Pandas核心数据结构
1.1 Pandas简介
📌 核心概念
Pandas提供两种核心数据结构用于数据分析:
- Series:一维数组 + 标签(类似带索引的列表)
- DataFrame:二维数组 + 行标签 + 列名称(类似Excel表格)
💡 知识点:Pandas的四大功能
- 读取数据
- 数据处理
- 数据分析
- 数据可视化
📝 代码示例:导入Pandas
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore') # 忽略警告信息
⚠️ 注意事项
- Pandas基于NumPy构建,因此继承了NumPy的许多特性
- 通常使用
pd作为Pandas的别名(行业标准) - 建议同时导入NumPy,因为很多操作需要配合使用
2. Series详解
2.1 Series基础概念
📌 核心概念
Series是一维的数组加标签,可以理解为Excel表格中的一列数据,每个数据都有对应的行索引。
🔧 函数:pd.Series()
📊 参数说明
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| data | list/tuple/dict/ndarray | 数据源 | 必填 |
| index | list/array | 行索引标签 | 0开始的整数 |
| dtype | dtype | 数据类型 | 自动推断 |
| name | str | Series名称 | None |
📝 代码示例:创建Series
# 方法1:从列表创建
data = [1, 2, 3, 4]
s1 = pd.Series(data=data, index=list('abcd'))
print(s1)
# 输出:
# a 1
# b 2
# c 3
# d 4
# dtype: int64
# 方法2:从字典创建(推荐)
dic = {'lisa': 80, 'cc': 90, 'john': 100}
s2 = pd.Series(data=dic)
print(s2)
# 输出:
# lisa 80
# cc 90
# john 100
# dtype: int64
# 方法3:从NumPy数组创建
arr = np.array([1, 2, 3, 4])
s3 = pd.Series(data=arr, index=list('abcd'))
💎 最佳实践
✅ 推荐:使用字典创建Series,键自动成为索引
s = pd.Series({'name': 'Lisa', 'age': 18})
❌ 避免:索引长度与数据长度不匹配
s = pd.Series([1, 2, 3], index=['a', 'b']) # 会报错
2.2 Series数据访问
💡 知识点:Series的两种索引方式
- 位置索引:使用整数位置(从0开始)
- 标签索引:使用自定义的索引标签
📝 代码示例:数据访问
s2 = pd.Series({'lisa': 80, 'cc': 90, 'john': 100})
# 位置索引访问
print(s2[0]) # 输出:80(第一个元素)
# 标签索引访问
print(s2['lisa']) # 输出:80(通过标签访问)
# 多个元素访问
print(s2[['cc', 'john']])
# 输出:
# cc 90
# john 100
# dtype: int64
2.3 Series属性
📊 常用属性列表
| 属性 | 说明 | 示例 |
|---|---|---|
ndim |
维度(Series固定为1) | s.ndim |
shape |
形状(元素个数,) | s.shape |
size |
元素总数 | s.size |
dtype |
数据类型 | s.dtype |
index |
行索引对象 | s.index |
values |
值(返回NumPy数组) | s.values |
📝 代码示例:属性使用
s2 = pd.Series({'lisa': 80, 'cc': 90, 'john': 100})
print('维度:', s2.ndim) # 输出:1
print('形状:', s2.shape) # 输出:(3,)
print('元素个数:', s2.size) # 输出:3
print('数据类型:', s2.dtype) # 输出:int64
print('行索引:', s2.index) # 输出:Index(['lisa', 'cc', 'john'], dtype='object')
print('值:', s2.values) # 输出:[ 80 90 100]
2.4 Series继承NumPy的特性
💡 知识点:Series支持NumPy操作
📝 代码示例:NumPy风格操作
s2 = pd.Series({'lisa': 80, 'cc': 90, 'john': 100})
# 1. 掩码操作(布尔索引)
print('取出>=80的数据:\n', s2[s2 >= 80])
# 输出:
# lisa 80
# cc 90
# john 100
# 2. 切片操作
print('取出cc和john的成绩:\n', s2[['cc', 'john']])
# 3. 统计函数
print('计算成绩均值:', s2.mean()) # 输出:90.0
print('最大值:', s2.max()) # 输出:100
print('最小值:', s2.min()) # 输出:80
print('标准差:', s2.std()) # 输出:10.0
print('求和:', s2.sum()) # 输出:270
🔗 关联知识
→ 3. Series字符串操作
→ 4. Series其他常用方法
3. Series字符串操作
3.1 字符串操作基础
📌 核心概念
所有Series字符串操作都通过series.str.函数名()的形式调用,这是Pandas提供的向量化字符串操作接口。
⚠️ 注意事项
- 必须使用
.str访问器才能调用字符串方法 - 字符串操作返回新的Series,不修改原数据(除非赋值)
- 只能用于字符串类型的Series
3.2 常用字符串方法
📊 字符串方法速查表
| 方法 | 功能 | 返回值 | 示例 |
|---|---|---|---|
str.strip() |
去除首尾指定字符 | Series | s.str.strip('()+ ') |
str.split() |
按分隔符分割 | Series/DataFrame | s.str.split('-') |
str.replace() |
替换子串 | Series | s.str.replace('old', 'new') |
str.contains() |
检查是否包含 | 布尔Series | s.str.contains('关键词') |
str.count() |
统计子串出现次数 | Series | s.str.count('a') |
str.len() |
计算字符串长度 | Series | s.str.len() |
str.find() |
查找子串位置 | Series | s.str.find('x') |
3.3 strip() - 去除首尾字符
🔧 函数:series.str.strip()
📝 代码示例
data = ['Tom', ' Jerry)', '(Tyke+', 'Spark']
s1 = pd.Series(data)
# 去除首尾的括号、加号和空格
s1 = s1.str.strip('()+ ')
print(s1)
# 输出:
# 0 Tom
# 1 Jerry
# 2 Tyke
# 3 Spark
# 去除首尾等号
data2 = ['Tom-Zhang', '====Jerry-Li', '===Tyke-Xiong===', 'Spark-Zhao====']
s2 = pd.Series(data2)
s2 = s2.str.strip('=')
print(s2)
# 输出:
# 0 Tom-Zhang
# 1 Jerry-Li
# 2 Tyke-Xiong
# 3 Spark-Zhao
💎 最佳实践
✅ 推荐:链式调用多个字符串方法
s = s.str.strip().str.lower().str.replace(' ', '_')
❌ 避免:忘记使用.str访问器
s = s.strip() # 错误!会报错
3.4 split() - 字符串分割
🔧 函数:series.str.split()
📊 参数说明
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| pat | str | 分隔符 | 空格 |
| expand | bool | 是否展开为DataFrame | False |
| n | int | 最大分割次数 | -1(全部) |
📝 代码示例
s2 = pd.Series(['Tom-Zhang', 'Jerry-Li', 'Tyke-Xiong', 'Spark-Zhao'])
# 基础分割(返回列表)
result1 = s2.str.split('-')
print(result1)
# 输出:
# 0 [Tom, Zhang]
# 1 [Jerry, Li]
# 2 [Tyke, Xiong]
# 3 [Spark, Zhao]
# 展开为DataFrame(推荐)
result2 = s2.str.split('-', expand=True)
print(result2)
# 输出:
# 0 1
# 0 Tom Zhang
# 1 Jerry Li
# 2 Tyke Xiong
# 3 Spark Zhao
# 设置列名
df = s2.str.split('-', expand=True)
df.columns = ['姓', '名']
🎯 应用场景:地理位置分割
s3 = pd.Series(['北京市-昌平区', '北京市-海淀区', '北京市-东城区'])
df1 = s3.str.split('-', expand=True)
df1.columns = ['城市', '片区']
print(df1)
# 输出:
# 城市 片区
# 0 北京市 昌平区
# 1 北京市 海淀区
# 2 北京市 东城区
3.5 replace() - 字符串替换
🔧 函数:series.str.replace()
📝 代码示例
s4 = pd.Series(['cc', 'lisa', 'john'])
# 替换字符串
s4 = s4.str.replace('cc', 'ch')
print(s4)
# 输出:
# 0 ch
# 1 lisa
# 2 john
# 实际应用:清理地铁站名称
s5 = pd.Series(['望京地铁站', '平安里地铁站', '西直门地铁站', '望京'])
s5 = s5.str.replace('地铁站', '')
print(s5)
# 输出:
# 0 望京
# 1 平安里
# 2 西直门
# 3 望京
3.6 contains() - 包含检查
🔧 函数:series.str.contains()
📊 参数说明
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| pat | str | 搜索模式(支持正则) | 必填 |
| case | bool | 是否区分大小写 | True |
| regex | bool | 是否使用正则表达式 | True |
📝 代码示例
s4 = pd.Series(['ch', 'lisa', 'john'])
# 基础包含检查
result = s4[s4.str.contains('lisa')]
print(result)
# 输出:
# 1 lisa
# 不区分大小写
emails = pd.Series(['user@example.com', 'admin@test.org', 'Support@ai.com'])
result = emails[emails.str.contains('admin|support', case=False)]
print(result)
# 输出:
# 1 admin@test.org
# 2 Support@ai.com
# 实际应用:筛选地点
s6 = s5[s5.str.contains('望京')]
print(s6)
# 输出:
# 0 望京
# 3 望京
3.7 count() - 统计子串出现次数
🔧 函数:series.str.count()
📝 代码示例
s4 = pd.Series(['ch', 'lisa', 'john'])
# 统计字符'c'出现的次数
result = s4.str.count('c')
print(result)
# 输出:
# 0 1
# 1 0
# 2 0
# 实际应用:统计DNA序列
dna = pd.Series(['AGCTAG', 'TTAGAC', 'GGGAGG'])
ag_count = dna.str.count('AG')
print(ag_count)
# 输出:
# 0 2
# 1 1
# 2 1
3.8 len() - 计算字符串长度
🔧 函数:series.str.len()
📝 代码示例
s4 = pd.Series(['ch', 'lisa', 'john'])
# 计算每个字符串的长度
lengths = s4.str.len()
print(lengths)
# 输出:
# 0 2
# 1 4
# 2 4
# 实际应用:验证学号长度
s2 = pd.Series(['20130101', '201301', '20130104', '20130106'])
invalid = s2[s2.str.len() != 8]
print('不合规的学号:\n', invalid)
# 输出:
# 1 201301
3.9 find() - 查找子串位置
🔧 函数:series.str.find()
💡 知识点:返回值规则
- 找到:返回第一次出现的索引位置(从0开始)
- 未找到:返回-1
📝 代码示例
s4 = pd.Series(['ch', 'lisa', 'john'])
# 查找字符'c'的位置
positions = s4.str.find('c')
print(positions)
# 输出:
# 0 0 ('ch'中'c'在位置0)
# 1 -1 ('lisa'中没有'c')
# 2 -1 ('john'中没有'c')
# 实际应用:筛选以'A'开头的数据
codes = pd.Series(['A100', 'B000', 'C300', 'A250'])
a_codes = codes[codes.str.find('A') == 0]
print(a_codes)
# 输出:
# 0 A100
# 3 A250
3.10 字符串索引
💡 知识点:直接索引字符
📝 代码示例
s1 = pd.Series(['Tom', 'Jerry', 'Tyke', 'Spark'])
# 截取首字母
first_letters = s1.str[0]
print(first_letters)
# 输出:
# 0 T
# 1 J
# 2 T
# 3 S
# 截取前三个字符
first_three = s1.str[0:3]
print(first_three)
# 输出:
# 0 Tom
# 1 Jer
# 2 Tyk
# 3 Spa
3.11 综合案例
🎯 案例1:公司福利统计
# 统计每家公司福利的个数
s1 = pd.Series(
data=['五险一金,餐补,年终奖',
'五险一金,下午茶,全勤奖,带薪休假',
'五险一金,下午茶,全勤奖,带薪休假,定期体检,团建'],
index=list('ABC')
)
# 方法:统计逗号数量+1
welfare_count = s1.str.count(',') + 1
print(welfare_count)
# 输出:
# A 3
# B 4
# C 6
🎯 案例2:学号验证
# 找到学号不合规的数据
s2 = pd.Series(['20130101', '201301', '20130104', '20130106'])
invalid_ids = s2[s2.str.len() != 8]
print('不合规学号:\n', invalid_ids)
# 输出:
# 1 201301
🎯 案例3:邮箱筛选
# 检查是否包含"admin"或"support"(不区分大小写)
emails = pd.Series(['user@example.com', 'admin@test.org', 'Support@ai.com'])
admin_emails = emails[emails.str.contains('admin|support', case=False)]
print(admin_emails)
# 输出:
# 1 admin@test.org
# 2 Support@ai.com
🔗 关联知识
→ 4. Series其他常用方法
→ 5. DataFrame详解
4. Series其他常用方法
4.1 isin() - 成员检查
🔧 函数:series.isin()
📌 核心概念
检查Series中的每个元素是否在给定的列表中,返回布尔Series,常用于按条件筛选数据。
📝 代码示例
s1 = pd.Series(['北京', '上海', '北京', '天津', '北京', '重庆', '上海', '重庆'])
# 筛选开设产品线的城市
target_cities = ['北京', '上海', '重庆']
result = s1[s1.isin(target_cities)]
print(result)
# 输出:
# 0 北京
# 1 上海
# 2 北京
# 4 北京
# 5 重庆
# 6 上海
# 7 重庆
# 实际应用:筛选已知性别
gender = pd.Series(['男', '女', '未统计', '男', '男', '女', '未统计'])
known_gender = gender[gender.isin(['男', '女'])]
print(known_gender)
# 输出:
# 0 男
# 1 女
# 3 男
# 4 男
# 5 女
💎 最佳实践
✅ 推荐:使用isin()进行多值筛选
df = df[df['city'].isin(['北京', '上海', '深圳'])]
❌ 避免:使用多个or条件
df = df[(df['city']=='北京') | (df['city']=='上海') | (df['city']=='深圳')] # 冗长
4.2 unique() - 去重
🔧 函数:series.unique()
📌 核心概念
返回Series中所有唯一值组成的NumPy数组,用于查看数据中有哪些不同的类别。
📝 代码示例
gender = pd.Series(['男', '女', '未统计', '男', '男', '女', '未统计'])
# 查看有哪些类别
categories = gender.unique()
print('有哪些类别:', categories)
# 输出:['男' '女' '未统计']
# 数据清洗后再去重
data_info = pd.Series(
['经理', '本科', '经理 ', '初中', '博士', '专科',
'专科', '博士', '博士', '本科', '专科', '本科', '专科', '本科'],
name='学历'
)
# 去掉首尾空格
data_info = data_info.str.strip()
# 去掉非学历数据
data_info = data_info[data_info != '经理']
# 查看学历类别
print('学历类别:', data_info.unique())
# 输出:['本科' '初中' '博士' '专科']
4.3 nunique() - 唯一值计数
🔧 函数:series.nunique()
📌 核心概念
返回Series中唯一值的数量(去重后的计数),常用于统计类别数量。
📝 代码示例
gender = pd.Series(['男', '女', '男', '男', '女'])
# 统计类别数量
n_categories = gender.nunique()
print('一共有几个类别:', n_categories)
# 输出:2
4.4 value_counts() - 分类计数
🔧 函数:series.value_counts()
📊 参数说明
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| normalize | bool | 是否返回占比 | False |
| sort | bool | 是否排序 | True |
| ascending | bool | 升序还是降序 | False |
| dropna | bool | 是否排除缺失值 | True |
📝 代码示例
gender = pd.Series(['男', '女', '男', '男', '女'])
# 统计每个类别的数量
counts = gender.value_counts()
print('每个类别多少人:\n', counts)
# 输出:
# 男 3
# 女 2
# 计算占比
proportions = gender.value_counts(normalize=True)
print('男女占比:\n', proportions)
# 输出:
# 男 0.6
# 女 0.4
# 或者手动计算占比
proportions2 = gender.value_counts() / gender.size
print(proportions2)
# 输出:
# 男 0.6
# 女 0.4
🎯 应用场景:学历统计
data_info = pd.Series(
['本科', '初中', '博士', '专科', '专科', '博士', '博士', '本科', '专科', '本科', '专科', '本科'],
name='学历'
)
# 查看各学历人数
print('各学历人数:\n', data_info.value_counts())
# 输出:
# 本科 4
# 专科 4
# 博士 3
# 初中 1
# 查看各学历占比
print('各学历占比:\n', data_info.value_counts(normalize=True))
# 输出:
# 本科 0.333333
# 专科 0.333333
# 博士 0.250000
# 初中 0.083333
4.5 map() - 映射转换
🔧 函数:series.map()
📌 核心概念
根据字典或函数对Series中的每个值进行一对一映射转换,常用于数据编码和分类转换。
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| arg | dict/function | 映射规则(字典或函数) |
📝 代码示例:城市等级映射
s1 = pd.Series(['北京', '上海', '北京', '天津', '北京', '重庆', '上海', '重庆'])
# 定义映射关系
city_map = {
'北京': '一线城市',
'上海': '一线城市',
'天津': '二线城市',
'重庆': '二线城市',
}
# 应用映射
s1 = s1.map(city_map)
print(s1)
# 输出:
# 0 一线城市
# 1 一线城市
# 2 一线城市
# 3 二线城市
# 4 一线城市
# 5 二线城市
# 6 一线城市
# 7 二线城市
🎯 应用场景:用户行为编码
# 用户行为数据:1-浏览 2-加购 3-收藏 4-购买
user_actions = pd.Series([1, 1, 2, 3, 4, 2, 1])
# 定义映射关系
actions_map = {
1: 'pv', # page view 浏览
2: 'cart', # 加购物车
3: 'collect', # 收藏
4: 'buy' # 购买
}
# 应用映射
user_actions = user_actions.map(actions_map)
print(user_actions)
# 输出:
# 0 pv
# 1 pv
# 2 cart
# 3 collect
# 4 buy
# 5 cart
# 6 pv
💎 最佳实践
✅ 推荐:使用map()进行分类编码
df['level'] = df['score'].map({1: '低', 2: '中', 3: '高'})
❌ 避免:使用多个if-else
# 不推荐的写法
def classify(x):
if x == 1: return '低'
elif x == 2: return '中'
else: return '高'
4.6 shift() - 数据偏移
🔧 函数:series.shift()
📊 参数说明
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| periods | int | 偏移量(正数向下,负数向上) | 1 |
| fill_value | scalar | 填充值 | NaN |
📌 核心概念
将Series中的数据向上或向下移动指定位置,常用于计算环比、同比等时间序列分析。
📝 代码示例:基础偏移
s2 = pd.Series(
[11, 22, 33, 44, 55],
index=['一月', '二月', '三月', '四月', '五月']
)
# 向下偏移1位(正数)
shifted_down = s2.shift(1)
print(shifted_down)
# 输出:
# 一月 NaN
# 二月 11.0
# 三月 22.0
# 四月 33.0
# 五月 44.0
# 向上偏移1位(负数)
shifted_up = s2.shift(-1)
print(shifted_up)
# 输出:
# 一月 22.0
# 二月 33.0
# 三月 44.0
# 四月 55.0
# 五月 NaN
🎯 应用场景:计算月环比
s2 = pd.Series(
[11, 22, 33, 44, 55],
index=['一月', '二月', '三月', '四月', '五月']
)
# 月环比 = (本月 - 上月) / 上月
# 例如:二月环比 = (22 - 11) / 11 = 1.0 = 100%增长
mom_growth = (s2 - s2.shift(1)) / s2.shift(1)
print('月环比:\n', mom_growth)
# 输出:
# 一月 NaN
# 二月 1.000000 (增长100%)
# 三月 0.500000 (增长50%)
# 四月 0.333333 (增长33.3%)
# 五月 0.250000 (增长25%)
💡 知识点:环比计算公式
- 月环比 = (本月 - 上月) / 上月
- 正数表示增长,负数表示下降
- 例如:0.25 表示增长25%,-0.1 表示下降10%
🔗 关联知识
→ 5. DataFrame详解
→ 7. 数据读取与存储
5. DataFrame详解
5.1 DataFrame基础概念
📌 核心概念
DataFrame是二维的数组加行标签和列名称,可以理解为Excel表格或SQL数据表,是Pandas中最常用的数据结构。
💡 知识点:DataFrame的组成
- 行索引(index):每一行的标签
- 列名(columns):每一列的名称
- 数据(values):实际的数据内容(NumPy数组)
🔧 函数:pd.DataFrame()
📊 参数说明
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| data | dict/list/ndarray | 数据源 | 必填 |
| index | list/array | 行索引 | 0开始的整数 |
| columns | list | 列名 | 自动生成 |
| dtype | dtype | 数据类型 | 自动推断 |
5.2 创建DataFrame的三种方式
📝 方法1:从NumPy数组创建
import numpy as np
import pandas as pd
# 创建随机数据
np.random.seed(123)
data = np.random.randint(1, 100, 24).reshape(6, 4)
# 定义行索引和列名
row_index = np.arange(2001, 2007, 1).astype(str)
col_index = ['语文', '数学', '英语', '物理']
# 创建DataFrame
df1 = pd.DataFrame(
data=data,
index=row_index,
columns=col_index
)
print(df1)
# 输出:
# 语文 数学 英语 物理
# 2001 67 93 99 18
# 2002 84 58 87 98
# 2003 97 48 13 93
# 2004 89 84 28 10
# 2005 94 72 84 45
# 2006 39 60 75 39
📝 方法2:从字典创建(推荐)
# 字典的key是列名,value是列数据
dic = {
'姓名': ['lisa', 'cc', 'john', 'lili'],
'年龄': [18, 21, 20, 19],
'语文成绩': [98, 95, 59, 75]
}
df2 = pd.DataFrame(data=dic, index=[5, 6, 7, 8])
print(df2)
# 输出:
# 姓名 年龄 语文成绩
# 5 lisa 18 98
# 6 cc 21 95
# 7 john 20 59
# 8 lili 19 75
📝 方法3:从嵌套列表创建
# 每个子列表代表一行数据
data1 = [
['lisa', 18, 98],
['cc', 21, 95],
['john', 20, 59],
['lili', 19, 75]
]
df3 = pd.DataFrame(data=data1, columns=['姓名', '年龄', '语文成绩'])
print(df3)
# 输出:
# 姓名 年龄 语文成绩
# 0 lisa 18 98
# 1 cc 21 95
# 2 john 20 59
# 3 lili 19 75
💎 最佳实践
✅ 推荐:使用字典创建DataFrame(列名清晰)
df = pd.DataFrame({'name': ['A', 'B'], 'age': [20, 21]})
❌ 避免:使用嵌套列表但不指定列名
df = pd.DataFrame([['A', 20], ['B', 21]]) # 列名不清晰
5.3 DataFrame属性
📊 常用属性列表
| 属性 | 说明 | 示例 |
|---|---|---|
shape |
形状(行数, 列数) | df.shape |
ndim |
维度(固定为2) | df.ndim |
size |
元素总数 | df.size |
dtypes |
每列的数据类型 | df.dtypes |
index |
行索引对象 | df.index |
columns |
列名对象 | df.columns |
values |
值(NumPy数组) | df.values |
📝 代码示例
df1 = pd.DataFrame({
'语文': [67, 84, 97],
'数学': [93, 58, 48],
'英语': [99, 87, 13]
}, index=['2001', '2002', '2003'])
print('df1的形状:', df1.shape) # 输出:(3, 3)
print('df1的维度:', df1.ndim) # 输出:2
print('df1的元素个数:', df1.size) # 输出:9
print('df1的数据类型:\n', df1.dtypes)
# 输出:
# 语文 int64
# 数学 int64
# 英语 int64
print('df1的行索引:', df1.index) # 输出:Index(['2001', '2002', '2003'])
print('df1的列名:', df1.columns) # 输出:Index(['语文', '数学', '英语'])
print('df1的值:\n', df1.values)
# 输出:
# [[67 93 99]
# [84 58 87]
# [97 48 13]]
5.4 DataFrame数据查询
5.4.1 查询列数据
💡 知识点:两种列访问方式
- 方括号访问:
df['列名']或df[['列1', '列2']] - 属性访问:
df.列名(仅适用于列名是合法Python标识符的情况)
📝 代码示例
df1 = pd.DataFrame({
'语文': [67, 84, 97],
'数学': [93, 58, 48],
'英语': [99, 87, 13],
'物理': [18, 98, 93]
}, index=['2001', '2002', '2003'])
# 查询单列(返回Series)
print(df1['语文'])
# 或
print(df1.语文)
# 输出:
# 2001 67
# 2002 84
# 2003 97
# 查询多列(返回DataFrame)
print(df1[['语文', '英语']])
# 输出:
# 语文 英语
# 2001 67 99
# 2002 84 87
# 2003 97 13
⚠️ 注意事项
- 单列查询返回Series,多列查询返回DataFrame
- 属性访问方式不能用于列名包含空格或特殊字符的情况
- 多列查询必须使用双层方括号
[[]]
5.4.2 查询行数据
💡 知识点:行切片
使用切片语法df[start:end:step]可以按行索引位置查询数据。
📝 代码示例
# 查询前两行
print(df1[0:2])
# 输出:
# 语文 数学 英语 物理
# 2001 67 93 99 18
# 2002 84 58 87 98
# 查询奇数行(0, 2, 4...)
print(df1[0:5:2])
# 输出:
# 语文 数学 英语 物理
# 2001 67 93 99 18
# 2003 97 48 13 93
5.4.3 iloc和loc定位
📌 核心概念
- iloc:基于整数位置的索引(integer location),前闭后开
- loc:基于标签的索引(label location),前闭后闭
🔍 对比说明
| 方法 | 索引方式 | 区间规则 | 使用场景 |
|---|---|---|---|
iloc |
整数位置 | 前闭后开[) | 按位置查询 |
loc |
标签名称 | 前闭后闭[] | 按名称查询 |
📝 代码示例
df1 = pd.DataFrame({
'语文': [67, 84, 97, 89, 94, 39],
'数学': [93, 58, 48, 84, 72, 60],
'英语': [99, 87, 13, 28, 84, 75],
'物理': [18, 98, 93, 10, 45, 39]
}, index=['2001', '2002', '2003', '2004', '2005', '2006'])
# iloc:前两行,前两列
print(df1.iloc[0:2, 0:2])
# 输出:
# 语文 数学
# 2001 67 93
# 2002 84 58
# loc:前两行,前两列(都能取到)
print(df1.loc['2001':'2002', '语文':'英语'])
# 输出:
# 语文 数学 英语
# 2001 67 93 99
# 2002 84 58 87
# loc:使用列表指定具体的行和列
print(df1.loc[['2001', '2002'], ['语文', '英语']])
# 输出:
# 语文 英语
# 2001 67 99
# 2002 84 87
5.4.4 条件查询
💡 知识点:布尔索引
使用条件表达式创建布尔Series,然后用于筛选数据。
📝 代码示例
# 查询语文成绩大于60分的数据
print(df1[df1['语文'] > 60])
# 或
print(df1.loc[df1['语文'] > 60])
# 输出:
# 语文 数学 英语 物理
# 2001 67 93 99 18
# 2002 84 58 87 98
# 2003 97 48 13 93
# 2004 89 84 28 10
# 2005 94 72 84 45
# 查询Lisa的语文成绩
df2 = pd.DataFrame({
'姓名': ['lisa', 'cc', 'john', 'lili'],
'年龄': [18, 21, 20, 19],
'语文成绩': [98, 95, 59, 75]
}, index=[5, 6, 7, 8])
result = df2.loc[df2['姓名'] == 'lisa', '语文成绩']
print(result)
# 输出:
# 5 98
💎 最佳实践
✅ 推荐:使用loc进行条件查询
df.loc[df['age'] > 18, ['name', 'score']]
❌ 避免:链式索引(可能产生警告)
df[df['age'] > 18]['name'] # 不推荐
5.5 DataFrame数据修改
5.5.1 新增列
📝 代码示例
df1 = pd.DataFrame({
'语文': [67, 84, 97],
'数学': [93, 58, 48],
'英语': [99, 87, 13]
}, index=['2001', '2002', '2003'])
# 新增化学成绩列
np.random.seed(123)
df1['化学'] = np.random.randint(20, 100, 3)
print(df1)
# 输出:
# 语文 数学 英语 化学
# 2001 67 93 99 86
# 2002 84 58 87 98
# 2003 97 48 13 97
# 新增行总分列
df1['row_sum'] = df1.sum(axis=1)
print(df1)
# 输出:
# 语文 数学 英语 化学 row_sum
# 2001 67 93 99 86 345
# 2002 84 58 87 98 327
# 2003 97 48 13 97 255
5.5.2 新增行
📝 代码示例
# 新增一行数据
df1.loc['2004'] = [90, 60, 100, 50, 300]
print(df1)
# 输出:
# 语文 数学 英语 化学 row_sum
# 2001 67 93 99 86 345
# 2002 84 58 87 98 327
# 2003 97 48 13 97 255
# 2004 90 60 100 50 300
# 新增列总和行
df1.loc['col_sum'] = df1.sum(axis=0)
print(df1)
# 输出:
# 语文 数学 英语 化学 row_sum
# 2001 67 93 99 86 345
# 2002 84 58 87 98 327
# 2003 97 48 13 97 255
# 2004 90 60 100 50 300
# col_sum 338 259 299 331 1227
5.5.3 修改数据
📝 代码示例
df2 = pd.DataFrame({
'姓名': ['lisa', 'cc', 'john', 'lili'],
'年龄': [18, 21, 20, 19],
'语文成绩': [98, 95, 59, 75]
}, index=[5, 6, 7, 8])
# 修改单个值
df2.loc[df2['姓名'] == 'lisa', '年龄'] = 20
print(df2)
# 修改整列数据
df2['年龄'] = df2['年龄'] + 1
print(df2)
# 修改特定条件的数据
df2.loc[df2['姓名'] == 'cc', '年龄'] += 1
print(df2)
5.6 综合案例
🎯 案例:学生信息管理
df2 = pd.DataFrame({
'姓名': ['lisa', 'cc', 'john', 'lili'],
'年龄': [18, 21, 20, 19],
'语文成绩': [98, 95, 59, 75]
}, index=[5, 6, 7, 8])
# 1. 新增一行:id为9,lulu,20,98
df2.loc[9] = ['lulu', 20, 98]
# 2. 新增一列:性别
df2['性别'] = ['女', '男', '男', '女', '女']
# 3. 将年龄数据整体+1
df2['年龄'] = df2['年龄'] + 1
# 4. 打印列名
print('列名:', df2.columns)
# 5. 打印形状
print('形状:', df2.shape)
# 6. 找到cc的性别
cc_gender = df2.loc[df2['姓名'] == 'cc', '性别'].values
print('cc的性别:', cc_gender)
# 7. 找到所有女生的数据
female_students = df2[df2['性别'] == '女']
print('女生数据:\n', female_students)
# 8. 找到成绩大于80的学生姓名
high_score = df2.loc[df2['语文成绩'] > 80, '姓名'].values
print('成绩>80的学生:', high_score)
# 9. 找到第三行和第四行,以及第一列第三列数据
result = df2.iloc[2:4, 0:3:2]
# 或
result = df2.loc[[7, 8], ['姓名', '语文成绩']]
print(result)
# 10. 把cc的年龄加1
df2.loc[df2['姓名'] == 'cc', '年龄'] += 1
🔗 关联知识
→ 6. DataFrame高级操作
→ 7. 数据读取与存储
6. DataFrame高级操作
6.1 head()和tail() - 快速查看数据
🔧 函数:df.head() / df.tail()
📊 参数说明
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| n | int | 返回的行数 | 5 |
📝 代码示例
df2 = pd.DataFrame({
'姓名': ['lisa', 'cc', 'john', 'lili'],
'年龄': [18, 21, 20, 19],
'语文成绩': [98, 95, 59, 75]
}, index=[5, 6, 7, 8])
# 查看前2行
print(df2.head(2))
# 输出:
# 姓名 年龄 语文成绩
# 5 lisa 18 98
# 6 cc 21 95
# 查看后2行
print(df2.tail(2))
# 输出:
# 姓名 年龄 语文成绩
# 7 john 20 59
# 8 lili 19 75
💎 最佳实践
✅ 推荐:读取大文件后先用head()查看数据结构
df = pd.read_csv('large_file.csv')
print(df.head()) # 快速了解数据格式
❌ 避免:直接打印整个DataFrame
print(df) # 数据量大时会很慢
6.2 drop() - 删除数据
🔧 函数:df.drop()
📊 参数说明
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| labels | str/list | 要删除的行/列标签 | 必填 |
| axis | int | 0删除行,1删除列 | 0 |
| inplace | bool | 是否在原数据上修改 | False |
📝 代码示例
df2 = pd.DataFrame({
'姓名': ['lisa', 'cc', 'john', 'lili'],
'年龄': [18, 21, 20, 19],
'语文成绩': [98, 95, 59, 75]
}, index=[5, 6, 7, 8])
# 删除列(不修改原数据)
result = df2.drop(labels='姓名', axis=1)
print(result)
# 输出:
# 年龄 语文成绩
# 5 18 98
# 6 21 95
# 7 20 59
# 8 19 75
# 删除行(直接修改原数据)
df2.drop(labels=[7, 8], axis=0, inplace=True)
print(df2)
# 输出:
# 姓名 年龄 语文成绩
# 5 lisa 18 98
# 6 cc 21 95
⚠️ 注意事项
inplace=False(默认):返回新DataFrame,不修改原数据inplace=True:直接修改原数据,返回None- 删除多个行/列时,labels参数传入列表
6.3 sort_values() - 按值排序
🔧 函数:df.sort_values()
📊 参数说明
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| by | str/list | 排序依据的列名 | 必填 |
| ascending | bool | True升序,False降序 | True |
| inplace | bool | 是否在原数据上修改 | False |
📝 代码示例
df2 = pd.DataFrame({
'姓名': ['lisa', 'cc', 'john', 'lili'],
'年龄': [18, 21, 20, 19],
'语文成绩': [98, 95, 59, 75]
}, index=[5, 6, 7, 8])
# 按语文成绩降序排序
sorted_df = df2.sort_values(by='语文成绩', ascending=False)
print(sorted_df)
# 输出:
# 姓名 年龄 语文成绩
# 5 lisa 18 98
# 6 cc 21 95
# 8 lili 19 75
# 7 john 20 59
# 按多列排序
sorted_df = df2.sort_values(by=['年龄', '语文成绩'], ascending=[True, False])
6.4 sort_index() - 按索引排序
🔧 函数:df.sort_index()
📊 参数说明
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| axis | int | 0按行索引,1按列名 | 0 |
| ascending | bool | True升序,False降序 | True |
| inplace | bool | 是否在原数据上修改 | False |
📝 代码示例
df2 = pd.DataFrame({
'姓名': ['lisa', 'cc', 'john', 'lili'],
'年龄': [18, 21, 20, 19],
'语文成绩': [98, 95, 59, 75]
}, index=[5, 6, 7, 8])
# 按行索引降序排序
sorted_df = df2.sort_index(axis=0, ascending=False)
print(sorted_df)
# 输出:
# 姓名 年龄 语文成绩
# 8 lili 19 75
# 7 john 20 59
# 6 cc 21 95
# 5 lisa 18 98
# 按列名排序
sorted_df = df2.sort_index(axis=1, ascending=True)
6.5 综合案例:学生成绩管理系统
🎯 案例背景
np.random.seed(123)
Score = pd.DataFrame({
"Name": ["Nancy", "Jack", "Jim", "Lili", "Simon", "Tom", "Lilei", "Jerry"],
"Python": np.random.randint(40, 100, 8),
"Java": np.random.randint(40, 100, 8),
"UI": np.random.randint(40, 100, 8),
"Class": np.random.randint(1, 3, 8)
})
📝 任务1:班级映射
# 1. Class班级:1-A,2-B
dic_class = {1: 'A', 2: 'B'}
Score['Class'] = Score['Class'].map(dic_class)
print(Score)
📝 任务2:数据修改
# 2. Jack修改为John
Score.loc[Score['Name'] == 'Jack', 'Name'] = 'John'
# 3. Simon的Java分数修改为75
Score.loc[Score['Name'] == 'Simon', 'Java'] = 75
📝 任务3:数据分析
# 4. A班Python成绩均值
a_class_avg = Score.loc[Score['Class'] == 'A', 'Python'].mean()
print('A班Python均分:', a_class_avg)
# 5. 一共有几个班,每个班多少人
class_counts = Score['Class'].value_counts()
print('班级人数:\n', class_counts)
# 6. 得到UI大于80分的学生姓名
high_ui = Score.loc[Score['UI'] > 80, 'Name'].values
print('UI>80的学生:', high_ui)
📝 任务4:成绩处理
# 1. UI成绩全部加10分
Score['UI'] = Score['UI'] + 10
# 2. 新增四列:总分、均分、最大、最小
Score['总分'] = Score[['Python', 'Java', 'UI']].sum(axis=1)
Score['均分'] = Score[['Python', 'Java', 'UI']].mean(axis=1)
Score['最大'] = Score[['Python', 'Java', 'UI']].max(axis=1)
Score['最小'] = Score[['Python', 'Java', 'UI']].min(axis=1)
# 3. 得到3科都及格的学生信息
# 方法1:使用多个条件
passed = Score[(Score['Python'] >= 60) & (Score['Java'] >= 60) & (Score['UI'] >= 60)]
# 方法2:使用最小值
passed = Score[Score['最小'] >= 60]
# 方法3:使用all()函数(推荐)
mask = (Score.iloc[:, 1:4] > 60).all(axis=1)
passed = Score[mask]
print('三科都及格的学生:\n', passed)
# 4. Tom的Class改为A
Score.loc[Score['Name'] == 'Tom', 'Class'] = 'A'
# 5. 按照总分从大到小排序
Score = Score.sort_values(by='总分', ascending=False)
print(Score)
💡 知识点:all()函数
all(axis=1):对每一行进行逻辑与运算- 所有值都为True时,结果才为True
- 常用于检查多个条件是否同时满足
🔗 关联知识
→ 7. 数据读取与存储
→ 4. Series其他常用方法
7. 数据读取与存储
7.1 读取CSV文件
🔧 函数:pd.read_csv()
📊 常用参数说明
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| filepath_or_buffer | str | 文件路径 | 必填 |
| encoding | str | 文件编码(UTF-8/GBK/GB2312) | None |
| sep | str | 分隔符 | ‘,’ |
| header | int | 哪一行作为列名 | 0 |
| names | list | 自定义列名 | None |
| usecols | list | 只读取指定列 | None |
| index_col | int/str | 指定某列为行索引 | None |
| nrows | int | 读取前n行 | None |
| skiprows | int/list | 跳过前n行 | None |
📝 代码示例:基础读取
import pandas as pd
# 基础读取
df = pd.read_csv(
filepath_or_buffer='data/HR.csv',
encoding='GB2312'
)
print(df.head())
💡 知识点:CSV vs Excel
| 特性 | CSV | Excel |
|---|---|---|
| 文件类型 | 纯文本 | 二进制 |
| 分隔符 | 逗号 | - |
| 数据表 | 单个 | 多个sheet |
| 体积 | 小 | 大 |
| 功能 | 仅数据 | 图表/公式/格式 |
| 加载速度 | 快 | 慢 |
| 适用场景 | 日志/原始数据/备份 | 财务报表/商业分析 |
7.2 检测文件编码
🔧 工具:chardet库
📝 代码示例
import chardet
# 检测文件编码
with open('data/HR.csv', 'rb') as f:
result = chardet.detect(f.read(1000)) # 读取前1000字节判断
print('文件编码:', result['encoding'])
# 输出:GB2312
⚠️ 常见编码问题
- UTF-8:国际通用,支持所有字符
- GBK/GB2312:中文编码,Windows中文系统常用
- ISO-8859-1:西欧字符编码
💎 最佳实践
✅ 推荐:先检测编码再读取
import chardet
with open('file.csv', 'rb') as f:
encoding = chardet.detect(f.read(1000))['encoding']
df = pd.read_csv('file.csv', encoding=encoding)
❌ 避免:盲目尝试不同编码
df = pd.read_csv('file.csv', encoding='utf-8') # 可能报错
7.3 高级读取参数
📝 代码示例:指定列和行
# 只读取指定列
df = pd.read_csv(
'data/HR.csv',
encoding='GB2312',
usecols=['员工满意度', '项目数量', '部门']
)
# 指定某列为行索引
df = pd.read_csv(
'data/HR.csv',
encoding='GB2312',
index_col=0 # 第一列作为行索引
)
# 读取前100行
df = pd.read_csv(
'data/HR.csv',
encoding='GB2312',
nrows=100
)
# 跳过前5行
df = pd.read_csv(
'data/HR.csv',
encoding='GB2312',
skiprows=5
)
# 自定义列名
df = pd.read_csv(
'data/HR.csv',
encoding='GB2312',
header=None, # 不使用第一行作为列名
names=['col1', 'col2', 'col3'] # 自定义列名
)
7.4 HR数据分析案例
🎯 数据字段说明
- 员工满意度:员工打的分数
- 考核评分:领导给的分数
- 项目数量:负责几个项目
- 每月在公司工作时间:平均值
- 司龄:在公司第几年
- 工作事故:0没有,1有
- 是否离职:0没有,1离职
- 五年内是否升职:0没有,1有
- 部门:所在部门
- 薪水:低/中/高
📝 分析任务
df = pd.read_csv('data/HR.csv', encoding='GB2312')
# 1. 打印数据列名
print('列名:', df.columns)
# 2. 求公司员工满意度的均值
avg_satisfaction = df['员工满意度'].mean()
print('员工满意度均值:', avg_satisfaction)
# 3. 求公司的员工离职率
turnover_rate = df['是否离职'].value_counts() / df.shape[0]
print('离职率:\n', turnover_rate)
# 或
turnover_rate = df.loc[df['是否离职'] == 1, '是否离职'].count() / df['是否离职'].count()
# 4. 都有哪些部门,每个部门多少人
dept_counts = df['部门'].value_counts()
print('各部门人数:\n', dept_counts)
# 5. 工作时长的最大值、最小值、均值
print('工作时长最大值:', df['每月在公司工作时间'].max())
print('工作时长最小值:', df['每月在公司工作时间'].min())
print('工作时长均值:', df['每月在公司工作时间'].mean())
# 6. 薪水的占比情况
salary_ratio = df['薪水'].value_counts(normalize=True)
print('薪水占比:\n', salary_ratio)
# 7. 销售部门员工项目数量的均值
sales_avg = df.loc[df['部门'] == 'sales', '项目数量'].mean()
print('销售部门项目数量均值:', sales_avg)
# 8. 每月在公司工作时间>250,得到部门和项目数量两列数据
result = df.loc[df['每月在公司工作时间'] > 250, ['部门', '项目数量']]
print(result)
7.5 保存CSV文件
🔧 函数:df.to_csv()
📊 常用参数说明
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| path_or_buf | str | 保存路径 | 必填 |
| sep | str | 分隔符 | ‘,’ |
| index | bool | 是否保存行索引 | True |
| header | bool | 是否保存列名 | True |
| columns | list | 保存指定列 | None |
| encoding | str | 文件编码 | ‘utf-8’ |
📝 代码示例
stu = pd.DataFrame({
'姓名': ['张三', '李四', '王五'],
'年龄': [18, 19, 17],
'成绩': [80, 70, 99]
}, index=['No1', 'No3', 'No2'])
# 保存到CSV(包含行索引)
stu.to_csv(path_or_buf='data/stu.csv')
# 保存到CSV(不包含行索引)
stu.to_csv(path_or_buf='data/stu.csv', index=False)
# 保存指定列
stu.to_csv(
path_or_buf='data/stu.csv',
columns=['姓名', '成绩'],
index=False
)
7.6 读取Excel文件
🔧 函数:pd.read_excel()
⚠️ 注意事项
需要先安装openpyxl库:
pip install openpyxl -i https://repo.huaweicloud.com/repository/pypi/simple/
📝 代码示例
# 读取Excel文件
df2 = pd.read_excel('data/students.xlsx')
print(df2)
# 读取指定sheet
df2 = pd.read_excel('data/students.xlsx', sheet_name='Sheet1')
# 读取多个sheet
dfs = pd.read_excel('data/students.xlsx', sheet_name=None) # 返回字典
7.7 保存Excel文件
🔧 函数:df.to_excel()
📝 代码示例
df2 = pd.DataFrame({
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [18, 19, 17, 20],
'成绩': [80, 70, 99, 85],
'性别': ['男', '女', '男', '男']
})
# 修改数据
df2.loc[df2['姓名'] == '张三', '年龄'] = 20
df2.loc[df2['姓名'] == '赵六', '成绩'] = 98
df2.loc[df2['姓名'] == '李四', '性别'] = '男'
# 保存到Excel
df2.to_excel(excel_writer='data/new_stu.xlsx', index=False)
# 保存到指定sheet
df2.to_excel(
excel_writer='data/new_stu.xlsx',
sheet_name='学生信息',
index=False
)
🔗 关联知识
→ 8. 数据库连接
→ 5. DataFrame详解
8. 数据库连接
8.1 连接MySQL数据库
🔧 工具:pymysql库
⚠️ 注意事项
需要先安装pymysql库:
pip install pymysql
📝 代码示例:建立连接
import pymysql
import pandas as pd
import warnings
warnings.filterwarnings('ignore')
# 建立数据库连接
conn = pymysql.connect(
host='localhost', # 数据库IP地址
port=3306, # 端口号
user='root', # 用户名
password='123456', # 密码
charset='utf8', # 字符编码
database='games_db' # 数据库名
)
print('连接成功:', conn)
📊 连接参数说明
| 参数 | 说明 | 示例 |
|---|---|---|
| host | 数据库服务器地址 | ‘localhost’ / ‘192.168.1.100’ |
| port | 端口号 | 3306(MySQL默认) |
| user | 用户名 | ‘root’ |
| password | 密码 | ‘123456’ |
| charset | 字符编码 | ‘utf8’ / ‘utf8mb4’ |
| database | 数据库名 | ‘test_db’ |
8.2 读取数据库数据
🔧 函数:pd.read_sql()
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| sql | str | SQL查询语句 |
| con | connection | 数据库连接对象 |
| index_col | str | 指定某列为行索引 |
| parse_dates | list | 解析为日期的列 |
📝 代码示例
# 读取整张表
df = pd.read_sql('SELECT * FROM sanguo', conn)
print(df)
# 条件查询
df = pd.read_sql('SELECT name, country FROM sanguo WHERE country="蜀国"', conn)
print(df)
# 聚合查询
df = pd.read_sql('SELECT country, COUNT(*) as count FROM sanguo GROUP BY country', conn)
print(df)
# 关闭连接
conn.close()
💡 知识点:SQL基础语句
-- 查询所有数据
SELECT * FROM table_name;
-- 条件查询
SELECT column1, column2 FROM table_name WHERE condition;
-- 排序
SELECT * FROM table_name ORDER BY column_name DESC;
-- 分组统计
SELECT column_name, COUNT(*) FROM table_name GROUP BY column_name;
-- 限制返回行数
SELECT * FROM table_name LIMIT 10;
8.3 完整工作流程
📝 代码示例:完整流程
import pymysql
import pandas as pd
# 1. 建立连接
conn = pymysql.connect(
host='localhost',
port=3306,
user='root',
password='123456',
charset='utf8',
database='games_db'
)
# 2. 读取数据
df = pd.read_sql('SELECT * FROM sanguo', conn)
# 3. 数据分析
print('数据形状:', df.shape)
print('前5行:\n', df.head())
print('数据类型:\n', df.dtypes)
# 4. 数据处理
# ... 进行各种数据分析和处理 ...
# 5. 关闭连接
conn.close()
⚠️ 注意事项
- 使用完数据库后要记得关闭连接
- 敏感信息(密码)不要硬编码在代码中
- 大数据量查询时注意内存占用
- 使用参数化查询防止SQL注入
💎 最佳实践
✅ 推荐:使用上下文管理器自动关闭连接
with pymysql.connect(...) as conn:
df = pd.read_sql('SELECT * FROM table', conn)
# 连接自动关闭
❌ 避免:忘记关闭连接
conn = pymysql.connect(...)
df = pd.read_sql('SELECT * FROM table', conn)
# 忘记conn.close(),可能导致连接泄漏
📚 知识点速查表
📊 核心知识点思维导图
Pandas数据分析
├── 1. 核心数据结构 ⭐
│ ├── Series(一维)
│ │ ├── 创建:pd.Series(data, index, dtype, name)
│ │ ├── 属性:index, values, dtype, shape, size, ndim
│ │ ├── 访问:位置索引[0]、标签索引['label']
│ │ └── 统计:mean(), sum(), max(), min(), std()
│ │
│ └── DataFrame(二维)
│ ├── 创建:pd.DataFrame(data, index, columns)
│ ├── 属性:index, columns, values, shape, dtypes, ndim, size
│ ├── 查询:df['col'], df.loc[], df.iloc[], df[condition]
│ └── 修改:df['col']=value, df.loc[]=value
│
├── 2. Series字符串操作 ⭐⭐
│ ├── 基础方法
│ │ ├── str.strip() - 去除首尾字符
│ │ ├── str.split() - 字符串分割
│ │ ├── str.replace() - 字符串替换
│ │ └── str[0:3] - 字符串切片
│ │
│ └── 高级方法
│ ├── str.contains() - 包含检查(支持正则)
│ ├── str.count() - 统计出现次数
│ ├── str.len() - 计算字符串长度
│ └── str.find() - 查找子串位置
│
├── 3. Series数据处理 ⭐⭐
│ ├── 成员检查
│ │ ├── isin() - 检查是否在列表中
│ │ └── 布尔索引 - series[condition]
│ │
│ ├── 去重统计
│ │ ├── unique() - 返回唯一值数组
│ │ ├── nunique() - 返回唯一值数量
│ │ └── value_counts() - 分类计数(支持normalize)
│ │
│ └── 数据转换
│ ├── map() - 映射转换(字典/函数)
│ └── shift() - 数据偏移(计算环比)
│
├── 4. DataFrame查询 ⭐⭐⭐
│ ├── 列查询
│ │ ├── df['col'] - 单列(返回Series)
│ │ ├── df[['col1','col2']] - 多列(返回DataFrame)
│ │ └── df.col - 属性访问(仅合法标识符)
│ │
│ ├── 行查询
│ │ ├── df[0:2] - 切片查询
│ │ ├── df.iloc[0:2, 0:2] - 位置索引(前闭后开)
│ │ └── df.loc['a':'b', 'col1':'col2'] - 标签索引(前闭后闭)
│ │
│ └── 条件查询
│ ├── df[df['col'] > 60] - 单条件
│ ├── df[(df['col1']>60) & (df['col2']<90)] - 多条件
│ └── df.loc[condition, ['col1','col2']] - 指定列
│
├── 5. DataFrame修改 ⭐⭐⭐
│ ├── 新增数据
│ │ ├── df['new_col'] = values - 新增列
│ │ ├── df.loc['new_row'] = values - 新增行
│ │ └── df['sum'] = df.sum(axis=1) - 计算列
│ │
│ ├── 修改数据
│ │ ├── df['col'] = df['col'] + 1 - 整列修改
│ │ ├── df.loc[condition, 'col'] = value - 条件修改
│ │ └── df.loc[index, 'col'] = value - 单值修改
│ │
│ └── 删除数据
│ ├── df.drop(labels, axis=0) - 删除行
│ ├── df.drop(labels, axis=1) - 删除列
│ └── inplace=True - 直接修改原数据
│
├── 6. DataFrame高级操作 ⭐⭐
│ ├── 查看数据
│ │ ├── df.head(n) - 查看前n行
│ │ ├── df.tail(n) - 查看后n行
│ │ └── df.info() - 查看数据信息
│ │
│ ├── 排序操作
│ │ ├── df.sort_values(by='col') - 按值排序
│ │ ├── df.sort_index() - 按索引排序
│ │ └── ascending=False - 降序排列
│ │
│ └── 统计分析
│ ├── df.describe() - 描述性统计
│ ├── df.sum(axis=0/1) - 求和(按列/行)
│ ├── df.mean(axis=0/1) - 平均值
│ └── df.max()/min() - 最大/最小值
│
├── 7. 数据读取与存储 ⭐⭐⭐
│ ├── CSV文件
│ │ ├── pd.read_csv(path, encoding, sep, header)
│ │ ├── df.to_csv(path, index, encoding)
│ │ └── 编码检测:chardet.detect()
│ │
│ ├── Excel文件
│ │ ├── pd.read_excel(path, sheet_name)
│ │ ├── df.to_excel(path, sheet_name, index)
│ │ └── 需要:pip install openpyxl
│ │
│ └── 高级参数
│ ├── usecols - 指定读取列
│ ├── nrows - 读取前n行
│ ├── skiprows - 跳过前n行
│ └── index_col - 指定索引列
│
└── 8. 数据库连接 ⭐⭐
├── MySQL连接
│ ├── pymysql.connect() - 建立连接
│ ├── pd.read_sql(sql, conn) - 读取数据
│ └── conn.close() - 关闭连接
│
└── SQL查询
├── SELECT * FROM table - 查询所有
├── WHERE condition - 条件筛选
├── ORDER BY col DESC - 排序
└── GROUP BY col - 分组统计
📋 函数速查表
Series创建与属性
| 函数/属性 | 语法 | 说明 | 优先级 |
|---|---|---|---|
pd.Series() |
pd.Series(data, index, dtype, name) |
创建Series | ⭐ |
ndim |
s.ndim |
维度(固定为1) | ⭐ |
shape |
s.shape |
形状(元素个数,) | ⭐ |
size |
s.size |
元素总数 | ⭐ |
dtype |
s.dtype |
数据类型 | ⭐ |
index |
s.index |
行索引对象 | ⭐ |
values |
s.values |
值(NumPy数组) | ⭐ |
Series字符串方法
| 方法 | 语法 | 说明 | 优先级 |
|---|---|---|---|
str.strip() |
s.str.strip('chars') |
去除首尾指定字符 | ⭐⭐ |
str.split() |
s.str.split('-', expand=True) |
字符串分割(expand展开为DataFrame) | ⭐⭐⭐ |
str.replace() |
s.str.replace('old', 'new') |
字符串替换 | ⭐⭐⭐ |
str.contains() |
s.str.contains('pattern', case=False) |
包含检查(支持正则) | ⭐⭐⭐ |
str.count() |
s.str.count('substring') |
统计子串出现次数 | ⭐⭐ |
str.len() |
s.str.len() |
计算字符串长度 | ⭐⭐ |
str.find() |
s.str.find('substring') |
查找子串位置(-1表示未找到) | ⭐ |
str[start:end] |
s.str[0:3] |
字符串切片 | ⭐⭐ |
Series数据处理方法
| 方法 | 语法 | 说明 | 优先级 |
|---|---|---|---|
isin() |
s.isin(['value1', 'value2']) |
成员检查 | ⭐⭐⭐ |
unique() |
s.unique() |
返回唯一值数组 | ⭐⭐⭐ |
nunique() |
s.nunique() |
返回唯一值数量 | ⭐⭐ |
value_counts() |
s.value_counts(normalize=True) |
分类计数(normalize返回占比) | ⭐⭐⭐ |
map() |
s.map({1:'A', 2:'B'}) |
映射转换(字典或函数) | ⭐⭐⭐ |
shift() |
s.shift(1) |
数据偏移(正数向下,负数向上) | ⭐⭐ |
Series统计方法
| 方法 | 语法 | 说明 | 优先级 |
|---|---|---|---|
sum() |
s.sum() |
求和 | ⭐ |
mean() |
s.mean() |
平均值 | ⭐ |
std() |
s.std(ddof=1) |
标准差(ddof=1为样本标准差) | ⭐ |
min() |
s.min() |
最小值 | ⭐ |
max() |
s.max() |
最大值 | ⭐ |
DataFrame创建与属性
| 函数/属性 | 语法 | 说明 | 优先级 |
|---|---|---|---|
pd.DataFrame() |
pd.DataFrame(data, index, columns) |
创建DataFrame | ⭐ |
shape |
df.shape |
形状(行数, 列数) | ⭐ |
ndim |
df.ndim |
维度(固定为2) | ⭐ |
size |
df.size |
元素总数 | ⭐ |
dtypes |
df.dtypes |
每列的数据类型 | ⭐ |
index |
df.index |
行索引对象 | ⭐ |
columns |
df.columns |
列名对象 | ⭐ |
values |
df.values |
值(NumPy数组) | ⭐ |
DataFrame查询方法
| 方法 | 语法 | 说明 | 优先级 |
|---|---|---|---|
| 列查询 | df['col'] 或 df[['col1','col2']] |
单列返回Series,多列返回DataFrame | ⭐⭐⭐ |
| 行切片 | df[0:2] |
按位置切片查询行 | ⭐⭐ |
iloc |
df.iloc[0:2, 0:2] |
位置索引(前闭后开) | ⭐⭐⭐ |
loc |
df.loc['a':'b', 'col1':'col2'] |
标签索引(前闭后闭) | ⭐⭐⭐ |
| 条件查询 | df[df['col'] > 60] |
布尔索引筛选 | ⭐⭐⭐ |
head() |
df.head(n) |
查看前n行(默认5) | ⭐⭐⭐ |
tail() |
df.tail(n) |
查看后n行(默认5) | ⭐⭐⭐ |
DataFrame修改方法
| 方法 | 语法 | 说明 | 优先级 |
|---|---|---|---|
| 新增列 | df['new_col'] = values |
添加新列 | ⭐⭐⭐ |
| 新增行 | df.loc['new_row'] = values |
添加新行 | ⭐⭐⭐ |
| 修改数据 | df.loc[condition, 'col'] = value |
条件修改 | ⭐⭐⭐ |
drop() |
df.drop(labels, axis=0/1, inplace=True) |
删除行/列 | ⭐⭐ |
DataFrame排序方法
| 方法 | 语法 | 说明 | 优先级 |
|---|---|---|---|
sort_values() |
df.sort_values(by='col', ascending=False) |
按值排序 | ⭐⭐⭐ |
sort_index() |
df.sort_index(axis=0, ascending=True) |
按索引排序 | ⭐⭐ |
DataFrame统计方法
| 方法 | 语法 | 说明 | 支持axis | 优先级 |
|---|---|---|---|---|
sum() |
df.sum(axis=0/1) |
求和 | ✅ | ⭐ |
mean() |
df.mean(axis=0/1) |
平均值 | ✅ | ⭐ |
std() |
df.std(axis=0/1) |
标准差 | ✅ | ⭐⭐ |
min() |
df.min(axis=0/1) |
最小值 | ✅ | ⭐ |
max() |
df.max(axis=0/1) |
最大值 | ✅ | ⭐ |
describe() |
df.describe() |
描述性统计 | ❌ | ⭐⭐ |
数据读取函数
| 函数 | 语法 | 常用参数 | 优先级 |
|---|---|---|---|
pd.read_csv() |
pd.read_csv(path, encoding, sep, header, usecols, nrows) |
encoding, usecols, nrows | ⭐⭐⭐ |
pd.read_excel() |
pd.read_excel(path, sheet_name) |
sheet_name | ⭐⭐⭐ |
pd.read_sql() |
pd.read_sql(sql, conn) |
sql, conn | ⭐⭐ |
数据存储函数
| 函数 | 语法 | 常用参数 | 优先级 |
|---|---|---|---|
df.to_csv() |
df.to_csv(path, index=False, encoding='utf-8') |
index, encoding | ⭐⭐⭐ |
df.to_excel() |
df.to_excel(path, sheet_name, index=False) |
sheet_name, index | ⭐⭐⭐ |
df.to_sql() |
df.to_sql(table_name, conn) |
table_name, conn | ⭐⭐ |
⚠️ 常见错误与解决方案
| 错误类型 | 错误示例 | 正确写法 | 说明 |
|---|---|---|---|
| 字符串方法 | s.strip() |
s.str.strip() |
必须使用.str访问器 |
| 多列查询 | df['col1', 'col2'] |
df[['col1', 'col2']] |
多列需要双层方括号 |
| 逻辑运算 | df[df['a']>60 and df['b']<90] |
df[(df['a']>60) & (df['b']<90)] |
使用&且加括号 |
| loc vs iloc | df.loc[0:2, 0:2] |
df.iloc[0:2, 0:2] |
loc用标签,iloc用位置 |
| 链式索引 | df[df['a']>60]['b'] |
df.loc[df['a']>60, 'b'] |
避免链式索引警告 |
| inplace参数 | df = df.drop('col', axis=1) |
df.drop('col', axis=1, inplace=True) |
理解inplace含义 |
📖 参考资源
- 官方文档:https://pandas.pydata.org/docs/
- 中文教程:https://www.pypandas.cn/
- 在线练习:https://www.kaggle.com/learn/pandas
- 视频教程:https://www.bilibili.com/(搜索Pandas教程)
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)