查看全课大纲(第 15 / 101 节)
- 1.数据分析基本概念
- 2.学习数据分析的一般路线
- 3.数据分析的流程
- 4.数据类型
- 5.环境部署(1)
- 6.环境部署(2)
- 7.课程介绍
- 8.TXT文件操作
- 9.JSON文件操作
- 10.CSV文件操作
- 11.Excel文件操作
- 12.数据库及SQL常用语法
- 13.数据库基本操作
- 14.数据库多表连接
- 15.实战:欧洲职业足球数据库分析
- 16.爬虫简介
- 17.URL管理模块
- 18.网页下载模块
- 19.网页解析模块(1)
- 20.网页解析模块(2)
- 21.Scrapy简介
- 22.Scrapy使用步骤(1)
- 23.Scrapy使用步骤(2)
- 24.Scrapy使用步骤(3)
- 25.Scrapy使用步骤(4)
- 26.实战:获取国内城市空气质量指数数据
- 27.NumPy和SciPy介绍
- 28.多维数组
- 29.多维数组操作
- 30.NumPy的常用方法
- 31.向量化介绍
- 32.向量化及通用函数
- 33.实战:2016美国大选分析
- 34.数据结构-Series
- 35.数据结构-DataFrame
- 36.数据结构-Index
- 37.Series的索引操作
- 38.DataFrame的索引操作
- 39.索引操作总结
- 40.运算与对齐
- 41.函数应用操作(1) -- map
- 42.函数应用操作 (2) -- apply applymap
- 43.文件读写操作
- 44.排序操作
- 45.数据清洗--处理缺失数据
- 46.数据清洗--处理重复数据
- 47.数据清洗--替换数据
- 48.常用统计方法(1) -- describe quantile
- 49.常用统计方法(2) -- sum mean median count
- 50.常用统计方法(3) -- max min idxmax idxmin
- 51.常用统计方法(4) -- mad var std cumsum
- 52.实战:全球食品数据分析
- 53.层级索引
- 54.分组与聚合介绍
- 55.分组操作(1) -- GroupBy对象及常用聚合操作
- 56.分组操作(2) -- 自定义分组及聚合操作
- 57.透视表介绍
- 58.透视表操作
- 59.数据规整(1) -- 数据合并concat
- 60.数据规整(2) -- 数据连接merge
- 61.数据重构(3) -- 数据重构stack unstack
- 62.实战:互联网电影资料库分析
- 63.探索性数据分析EDA介绍
- 64.EDA的目的
- 65.EDA常用工具
- 66.Matplotlib绘图基本介绍
- 67.Matplotlib画布
- 68.散点图和柱状图的绘制
- 69.直方图的绘制
- 70.矩阵绘图
- 71.子图的使用
- 72.Matplotlib颜色、标记、线型
- 73.Matplotlib坐标刻度、标签、图例、标题
- 74.Seaborn介绍
- 75.数据集分布可视化(1) -- 单变量分布、双变量分布
- 76.数据集分布可视化(2) -- 变量关系可视化
- 77.类别数据可视化 -- 类别散布图、类别内数据分布、类别内统计图
- 78.交互式数据可视化工具Bokeh介绍
- 79.Bokeh绘制散点图、柱状图、盒子图、弦图
- 80.Bokeh绘制常用图形元素
- 81.3D绘图 -- mplot3d
- 82.3D曲线可视化
- 83.3D散点图可视化
- 84.3D柱状图可视化
- 85.Pandas绘图
- 86.实战:Lending Club借贷数据探索性分析及可视化
- 87.机器学习介绍及应用场景
- 88.机器学习建模介绍 (1) -- 分类
- 89.机器学习建模介绍 (2) -- 回归
- 90.机器学习建模介绍 (3) -- 聚类
- 91.机器学习分类
- 92.机器学习工具scikit-learn
- 93.使用scikit-learn的流程
- 94.数据集准备及划分
- 95.模型选择
- 96.数据预处理及特征工程
- 97.过拟合与欠拟合
- 98.模型调参介绍
- 99.模型调参方法
- 100.模型测试及评价
- 101.实战:通过移动设备行为数据预测性别和年龄
实战:欧洲职业足球数据库分析
约 17 分钟
小象实战讲义 · Python数据分析实战
在学习了本地数据的各种采集与操作方法后,我们通过一个实战项目来巩固所学。本节我们将对一个欧洲职业足球数据库进行分析,目标是提取球员的基本信息,并整合其生涯平均评分,最终将处理好的数据保存为JSON格式,为后续的数据应用做好准备。
💡 核心导读
- 项目目标:从SQLite数据库中提取并整合球员信息,输出为结构化的JSON文件。
- 关键技术:使用Python标准库
sqlite3连接数据库,执行SQL查询,进行多表关联与数据计算。 - 代码组织:学习如何通过模块化设计(主程序+工具函数)使代码更清晰、易维护。
- 数据流转:体验从原始数据库(
.db)到中间处理(Python对象),再到最终数据文件(.json)的完整流程。
项目背景与数据
本次实战使用的数据来源于一个欧洲职业足球数据库soccer.db。该数据库使用SQLite创建,包含了国家、比赛、球员、球队等多个维度的信息。
我们主要关注其中两张表:
- Player表:存储球员的基本信息,如ID、姓名、生日、身高、体重等,约有1万多条记录。
- Player_Attributes表:存储球员在不同时间点的属性评分,如综合评分(
overall_rating)、潜力等,约有18万多条记录。
我们的核心任务是:为每位球员计算其整个职业生涯的平均综合评分,并将其与基本信息(姓名、年龄、身高、体重)一同保存到一个JSON文件中。
代码结构设计
为了保持代码的清晰和可维护性,我们将项目代码分为两个文件:
main.py:主程序文件,负责程序的主要流程控制,如连接数据库、调用处理函数、保存结果。utils.py:工具函数文件,存放可复用的辅助函数,如根据生日计算年龄、计算平均评分等。
这种模块化的设计避免了将所有代码堆砌在一个文件中,使得主程序逻辑清晰,工具函数也易于管理和测试。
核心代码实现
下面,我们通过一个简化的、可独立运行的示例来演示核心逻辑。请注意,为了演示的完整性,我们将工具函数直接内联在主代码块中。
# 示例:足球球员数据处理核心逻辑演示
import sqlite3
import json
import datetime
# 注意:此为演示逻辑的简化代码。
# 实际项目中,数据库文件路径应为 './database/soccer.db'
# 此处我们模拟数据并演示流程。
def calculate_age(birthday_str):
"""根据生日字符串计算年龄(粗略计算)"""
# 生日格式如 '1989-12-15 00:00:00'
born_year = int(birthday_str.split('-')[0]) # 提取出生年份
current_year = 2026 # 演示用固定年份(实际项目中应为 datetime.datetime.now().date().year)
return current_year - born_year
def calculate_average_rating(cur, player_api_id):
"""根据球员API ID查询其所有历史评分并计算平均值"""
# 构建查询语句,查找该球员的所有综合评分
sql = f"SELECT overall_rating FROM Player_Attributes WHERE player_api_id = {player_api_id};"
rows = cur.execute(sql).fetchall()
# 处理查询结果:过滤空值,并转换为浮点数列表
ratings = [float(row[0]) for row in rows if row[0] is not None]
# 计算平均分,避免除零错误
if ratings:
mean_rating = sum(ratings) / len(ratings)
else:
mean_rating = 0.0 # 若无评分数据,则记为0
return mean_rating
# 模拟从Player表查询到的数据行
# 真实库 Player 表的列顺序为: (id, player_api_id, player_name, player_fifa_api_id, birthday, height, weight)
# 此处模拟时省略了 player_fifa_api_id 字段(本例用不到它)
simulated_player_rows = [
(1, 12345, 'Lionel Messi', '1987-06-24 00:00:00', 170, 70),
(2, 67890, 'Cristiano Ronaldo', '1985-02-05 00:00:00', 187, 83)
]
player_list = []
for row in simulated_player_rows:
player = {}
player['name'] = row[2] # 姓名
player['age'] = calculate_age(row[3]) # 年龄
player['height'] = row[4] # 身高(真实库中 height 列在 weight 之前)
player['weight'] = row[5] # 体重
# 注意:此处无法真实连接数据库,因此模拟一个平均评分
player['average_rating'] = 93.5 if row[2] == 'Lionel Messi' else 92.0
player_list.append(player)
# 将处理结果转换为JSON格式字符串并打印,模拟保存到文件
result_json = json.dumps(player_list, indent=2)
print("处理后的球员数据(JSON格式):")
print(result_json)处理后的球员数据(JSON格式):
[
{
"name": "Lionel Messi",
"age": 39,
"height": 170,
"weight": 70,
"average_rating": 93.5
},
{
"name": "Cristiano Ronaldo",
"age": 41,
"height": 187,
"weight": 83,
"average_rating": 92.0
}
]主程序流程解析
结合原项目代码,主程序 main.py 的执行流程如下:
- 连接数据库:使用
sqlite3.connect()建立与soccer.db数据库的连接,并获取游标(cursor)用于执行SQL。 - 查询球员基本信息:在
get_players_info函数中,首先从Player表查询指定数量或全部球员的基本记录。 - 循环处理每条记录:对查询到的每一条球员记录:
- 提取姓名、体重、身高。
- 调用
utils.get_age()函数,根据生日字符串计算年龄。 - 提取
player_api_id,调用utils.get_overall_rating()函数,查询Player_Attributes表并计算该球员的平均综合评分。 - 将以上信息构造成一个字典,添加到球员列表中。
- 保存为JSON文件:使用
json.dump()将整个球员列表写入到player.json文件中。 - 关闭数据库连接:处理完成后,关闭数据库连接以释放资源。
关键SQL查询示例:
- 限制查询条数:
SELECT * FROM Player LIMIT 50; - 关联查询评分:
SELECT overall_rating FROM Player_Attributes WHERE player_api_id = ?;
查看与验证结果
运行项目后,会生成 player.json 文件。你可以用文本编辑器打开查看,也可以使用在线的JSON查看器(如 jsonviewer.stack.hu)来更清晰地浏览其树状结构。文件中每条记录都包含了我们处理后的球员信息。
[
{
"name": "Aaron Cresswell",
"age": 34,
"weight": 66,
"height": 170,
"average rating": 63.666666666666664
},
{
"name": "Aaron Doran",
"age": 33,
"weight": 68,
"height": 170,
"average rating": 58.75
}
]口径说明:上面这份是原项目
main.py的真实输出样例,其键名为average rating(含空格,沿用原项目的字典写法);而本节演示代码用的是蛇形命名的average_rating。两者都是合法的 JSON 键名——键名由写代码的人定义,Python 中带空格的键需要用字符串形式书写。学习时以「演示代码(average_rating)」为准即可,原样保留旧输出是为了忠实呈现原项目的产物。
📝 动手练一练
- 概念辨析:在本次实战的代码结构中,为什么要把
get_age和get_overall_rating函数单独放在utils.py文件中,而不是直接写在main.py里?这样做有什么好处?
👉 点击查看参考答案
模块化与代码复用:将通用功能抽取为独立的工具函数并放在单独模块中,是良好的编程实践。这样做的主要好处有:
- 提高可读性:使主程序
main.py的逻辑更加清晰,专注于业务流程控制。 - 便于维护:当需要修改年龄计算或评分查询逻辑时,只需在一个地方(
utils.py)修改,而不用改动主程序。 - 促进复用:这些工具函数可以在项目的其他部分或其他项目中轻松地被导入和使用。
- 利于测试:可以单独对工具函数进行单元测试,保证其正确性。
- 代码修改:在原项目的
get_overall_rating函数中,我们使用了列表推导式[float(row[0]) for row in rows if row[0] is not None]来过滤空值。如果要求不使用列表推导式,改用传统的for循环来实现相同的功能,代码应该怎么写?
👉 点击查看参考答案
def get_overall_rating(cur, player_api_id):
"""
获取球员平均评分 (使用for循环版本)
"""
sql = f"SELECT overall_rating FROM Player_Attributes WHERE player_api_id = {player_api_id};"
rows = cur.execute(sql).fetchall()
ratings = [] # 初始化一个空列表来存储有效的评分
for row in rows:
rating_value = row[0] # 取出评分
if rating_value is not None: # 检查评分是否不为空
ratings.append(float(rating_value)) # 转换为浮点数并加入列表
if ratings: # 检查列表是否非空,避免除以零
mean_rating = sum(ratings) / len(ratings)
else:
mean_rating = 0.0 # 如果没有有效评分,返回0.0
return mean_rating两种方式功能等价,列表推导式更为简洁,而 for 循环版本则更清晰地展示了每一步的处理过程。
本章小结
通过这个实战项目,我们完整地演练了从本地数据库获取数据、进行多表关联查询、数据计算与清洗,并最终将结果序列化为通用数据格式(JSON)的整个流程。这是数据分析工作中非常典型的一个环节。
📋 行动清单
- 运行项目代码:尝试在本地配置环境,运行提供的项目代码,亲自体验从数据库到JSON文件的完整生成过程。
- 尝试修改查询:修改
main.py中的n_players参数,分别获取前10名和全部球员的数据,观察生成文件的大小和内容差异。 - 思考扩展:如果还想在JSON中加入球员的“国籍”信息,你需要查看数据库中的哪些表?如何修改SQL查询和代码逻辑?
—— 小象教研组
配套资料 · 直接下载
课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。
- 下载本节课件:实战:欧洲职业足球数据库分析PDF · 185KB
- 下载全套课件打包(第1-5章)ZIP · 12.8MB
- 下载全套课件打包(第6-8章)ZIP · 15MB
- 下载实战数据集:AppleStore 应用商城分析ZIP · 329KB
- 下载实战数据集:女性服装电商分析ZIP · 2.8MB
- 下载Python 数据分析环境搭建指南PDF · 2MB
- 下载Scrapy 安装教程PDF · 12.7MB
- 下载附加实战项目:AppleStore 应用商城数据分析ZIP · 0.3MB · ipynb + CSV 数据
- 下载附加实战项目:银行电话营销数据分析ZIP · 0.4MB · ipynb + CSV 数据
- 下载附加实战项目:女性服装电商评论数据分析ZIP · 2.7MB · ipynb + CSV 数据
- 下载附加实战项目:美国化学学会杂志数据分析ZIP · 34.2MB · ipynb + SQLite 数据库