DLAI-Python-数据分析笔记-全-
DLAI Python 数据分析笔记(全)
001:Python数据分析入门 🐍📊
概述
在本课程中,我们将学习如何使用Python进行数据分析。Python是全球数据专业人士中使用最广泛的编程语言。你将学会如何将已有的数据分析技能(如假设检验、统计分析、数据模拟)从电子表格迁移到Python环境中,并利用其强大的功能处理更大规模的数据、实现任务自动化。
欢迎来到Python数据分析课程
欢迎学习Python数据分析课程,这是DeepLearning.AI数据科学专业系列的第三门课。
你已学习过假设检验、统计分析和数据模拟,并在电子表格中完成了相关操作。本课程将教你如何使用Python完成这些任务。
根据Kaggle平台的调查,超过88%的全球数据专业人士定期使用Python,使其成为使用率最高的编程语言。掌握Python能提升你作为数据分析师的技能,使你能够自动化重复性任务,并处理更大规模的数据任务。
你已熟悉的数据操作,如数据过滤、分组、汇总和绘图,在Python中都有直接对应的功能,并且比电子表格操作更加灵活。
很高兴再次欢迎Sean作为本课程的讲师。
Python在数据分析中的强大能力
上一节我们介绍了Python的普及性,本节中我们来看看它的实际应用能力。
对于分析工作,Python能将你从严谨但小规模的分析(例如分析1万条客户评论)提升到自动处理数百万条数据(例如Netflix的处理规模)。
我们在Netflix将Python用于众多应用,从决定哪些节目可以立项,到为超过2.5亿用户提供视频内容。Python帮助我们在这个巨大规模上捕获洞察,而不仅仅局限于对部分用户的样本分析。
本课程旨在教你Python编程的基础知识,从可能的第一行代码开始,到描述性统计、可视化、推断统计和时间序列分析。你已经具备了解决复杂问题的核心分析技能。本课程的重点是效率、可重复性,以及将这些技能应用于越来越大的数据集。
我很期待你学习这门课程,并将你的技能提升到新的水平。
人工智能时代,学习编程依然重要
人们常问,在像ChatGPT这样有时能编写代码的大型语言模型兴起后,学习编程是否仍然值得。答案是非常肯定的:值得。
编程这项技能因为大型语言模型的兴起而变得更容易学习,也更有用。
- 更容易学习:因为现在你可以拥有一位AI助手,它可以回答你关于代码的问题并提供反馈。
- 更有用:对于数据分析师这样的角色,在AI助手的帮助下,你可以更快地编写代码。以前,程序员如果犯错,可能需要花半小时进行大量网络搜索来寻找解决方案。但现在,AI助手可以帮助你更快地修复错误,其速度甚至可能超过以前非常优秀的程序员。
事实上,Sean,你是否也看到你圈子里的朋友使用聊天机器人来辅助编程?
是的,这绝对是数据分析领域的一个大趋势。你会经常听到人们谈论聊天机器人带来的效率提升——它们并非取代技能,而是让人们在自己已有的工作上做得更快。例如,我们的运营经理使用AI来帮助编写代码以访问数据。
在整个视频演示和实验环节中,你将使用一个聊天机器人作为编程伙伴,遵循数据分析师当前用于获取代码建议、查找错误甚至生成代码的最佳实践。
本课程的目标不是教你死记硬背命令,而是培养你的代码意识、模式识别能力以及对程序运行方式的直观理解。
那么,Andrew,对于现在学习编程的人,考虑到他们拥有所有可用的资源,你有什么建议?
我经常编码的一个原因,坦率地说,就是我觉得这真的很有趣。所以,如果你能在编码中找到乐趣,这可能有助于你坚持下去。学习编码时,要自己动手尝试代码。在本课程中,我们提供了与视频配套的Jupyter笔记本。你可以在电脑上打开一个不同的浏览器窗口,在Sean讲解代码时跟着操作,也可以在看完Sean的演示后自己运行代码。
我鼓励你也测试自己对代码工作原理的理解,因为通常正是通过这种摆弄、修改代码的过程,你才能磨练出对代码行为的直觉。第一次运行不成功也没关系。我的代码也经常出错或有漏洞,坦白说,几乎没有第一次就能正常运行的时候。所以,出错是意料之中的。当你发现错误时,可以尝试自己修复,或者询问你的AI聊天伙伴(如果你有的话)。
我想强调的一点是:亲自动手实践。我编写的第一个真正的软件是用来模拟太空中的低功率卫星轨道。我想我在最终成功运行之前犯了数百个错误。
Andrew,我完全理解那个试错的过程。本课程侧重于实际应用,而非代码的深层内部工作原理。你将学习如何利用聊天机器人来驾驭这个试错过程,你会发现它能给你很多支持。你的目标是获得洞察,而不是编写完美的代码。
课程实践与目标
在视频演示和实验中,你将使用真实世界的数据集,探索公共图书馆收入、珊瑚礁可持续性、股票价格等主题。每个模块都会带你完成一个数据分析项目的案例研究,这些项目可能是你未来工作中会遇到的。
到课程结束时,你将能熟练地使用Python进行数据分析,并能将聊天机器人作为编程伙伴使用。
没想到你的第一个程序是关于卫星的,这很有趣。我想我的第一个程序是一个猜数字游戏,让计算机尝试猜测人类心中所想。是的,那个思考过程很精彩。
如果你已经了解Python,那很好,你可以更快地浏览部分材料,然后深入探索。如果你是第一次学习Python,那也很好,你将获得一套非常有价值的技能。
总结
本节课中,我们一起学习了:
- Python在数据分析领域的普及性和重要性。
- Python处理大规模数据的强大能力及其在Netflix等公司的实际应用。
- 在AI助手时代,学习编程变得更容易且更有价值,核心在于培养代码意识和实践能力。
- 本课程将通过真实案例和AI辅助,重点教你如何高效地使用Python获取数据洞察,而非追求完美代码。
让我们进入下一个视频,开始学习吧。😊
002:生成式AI在本课程中的角色 🤖
在本节课中,我们将探讨生成式人工智能(特别是大型语言模型)如何作为数据分析师的核心技能补充,并学习如何有效地将其与编程工作相结合。
概述
本课程的一个关键要素是学习如何与生成式AI,特别是大型语言模型(LLMs)协同编程。有效使用LLMs将帮助你提升工作效率并在职场中脱颖而出。

LLMs:数据分析师的编程伙伴
上一节我们提到了本课程的核心要素。本节中,我们来看看大型语言模型(LLMs)的具体角色。LLMs如ChatGPT、Claude、Gemini等,是数据分析师技能的补充,而非替代品。
它们是一个优秀的编程伙伴,可以帮助你编写代码和修复错误。然而,只有在你自身懂得如何编程时,才能最大化利用LLM的价值。
在本课程中,你将学习编程基础以及如何与LLM协作。你将构建代码解读能力,并培养对LLM擅长任务及其可能出错之处的直觉。
你还将使用Coursera平台内置的实验聊天机器人来辅助你的代码编写。
课程的前瞻性与核心原则
本课程展示了截至2025年初的最新功能,我们预计在未来数月和数年内会有变化。
本课程旨在传授永恒的原则:即如何在工作中思考和使用生成式AI,无论你使用哪种具体产品。你将培养一种迭代和怀疑的思维模式。
新的模型和功能不断发布,以下是你近期可能看到的一些变化:
以下是未来LLMs可能的发展方向:
- 更先进、更专业的生成式AI工具。
- 更便宜的工具。
- 更快的工具。
- 整体更高质量的输出。

跟上这个领域的快速发展具有挑战性,但无需担心。在本课程中,你将发展所需的元认知技能,以在工作中驾驭这些技术进步。
关于工具与费用的说明
本课程也展示了一些LLM的付费功能,但你无需购买任何额外产品即可完成作业。
让你了解现有的选项(包括付费选项)非常重要,这样你才能有信心去尝试并为你的数据分析工作选择最佳工具。
本课程不推荐任何单一工具,你将在各个模块中看到多种工具。
请记住,你将学到的核心原则将使你准备好与现在及未来的LLMs(无论是免费还是付费的)协同工作。
总结
本节课中,我们一起学习了生成式AI(特别是大型语言模型)在本课程中的定位。我们明确了LLMs是技能的补充而非替代,了解了课程的前瞻性设计及其传授的核心思维原则,并对工具的选择和费用有了清晰的认识。


你将在接下来的几个视频中首次接触到LLM的演示。现在,请与我一起进入下一个视频,了解本模块所有令人兴奋的主题。我们那里见。
003:Python数据分析基础 🐍
在本课程中,我们将学习Python编程的基础知识,并探索它如何使数据分析工作流程更高效、更有效。
概述
欢迎来到模块1:数据分析编程基础。在本模块中,我们将探索激动人心的Python编程世界,并了解它如何提升数据分析的效率。整个模块中,我们将使用真实世界的示例进行实践,包括公共图书馆收入和餐厅安全检查分数。这种实践方法将帮助我们理解这些编程概念如何直接应用于数据分析任务。我们还将对比使用编程方法与基于电子表格的方法有何异同。
上一节我们介绍了本模块的整体目标,本节中我们来看看课程的具体安排。
课程内容安排
以下是本模块三个课程的核心内容简介:
-
课程1:编程与数据分析的角色
我们将学习编程在数据分析中的作用,包括Python为何如此强大,以及它与电子表格的对比。我们还将立即开始使用Jupyter Notebook环境,编写和运行代码。 -
课程2:Python基础
我们将学习不同的数据类型、如何将信息存储在变量中,以及如何使用列表。我们还将涵盖基本的编程工具,例如运行函数来对数据执行计算。在本课程结束时,我们将能够编写第一个Python程序来操作数据。 -
课程3:控制流核心概念
我们将学习控制流这一核心概念,即决定程序如何运行的逻辑。我们将学习如何使用条件语句在代码中做出分支决策,以及如何使用循环在Python中重复执行操作。
关于编程方法的说明
在Python中,通常有多种方法可以完成一项任务。虽然视频中展示的通常是解决问题最直接的途径,但随着编程经验的增加,我们会发现更多的解决方案。我们还将探索使用大型语言模型来辅助修改代码的方法。
编程既充满挑战,又回报丰厚。请跟随我进入第一课,学习编程在数据分析工作流程中的角色。
总结


本节课中,我们一起学习了《Python数据分析》第一模块的课程概述。我们明确了本模块的学习目标,即掌握Python编程基础以服务于数据分析。我们预览了三个核心课程的内容:编程的角色、Python基础语法以及控制流概念。最后,我们了解到编程解决问题的方法具有多样性,并鼓励大家开始实践之旅。
004:计算机编程 🖥️
在本节课中,我们将要学习计算机编程的基本概念,了解编程如何帮助我们高效、可追溯且可重复地完成数据分析任务,并探讨为什么Python是数据分析领域的首选语言。
什么是计算机编程?
计算机编程意味着通过一系列精确的指令,让计算机按照你的意愿执行任务。你的角色是使用计算机能理解的语言(如Python),非常精确地告诉它你想要做什么。计算机的角色则是严格地执行这些命令。
如果你没有准确地告诉计算机如何完成你的要求,它可能会出错或只执行部分指令。这有点像引导一个被蒙住眼睛的人通过障碍赛道。你需要精确地告诉他们该做什么、在哪里转弯、走多远,因为他们无法自己避开障碍。如果他们摔倒了,那就是你的责任。
编程在数据分析中的优势
上一节我们介绍了编程的基本概念,本节中我们来看看编程相较于其他分析工具(如人工手动计算)的优势。计算机在效率、可追溯性和可重复性方面表现出色。
假设你正在与一家滑板店合作分析其销售数据。通常,一位实习生会在月底汇总所有数据。



以下是编程带来的三大核心优势:

1. 效率

效率是指以最少的时间和资源完成任务。假设你需要计算某件产品(如连帽衫)的平均日销售额。
- 人工方式:你的实习生用手机计算这个统计数据需要20秒。
- 编程方式:Python完成同样的任务可能只需要不到千分之一秒。
这看起来差别不大,但如果你有200件库存产品:
- 你的实习生将花费超过一小时来计算平均日销售额。
- Python可以在不到半秒内完成。
如果你需要计算100家门店的销售额:
- 你的实习生将花费超过两周的时间来累加数字。
- Python可能只需要几秒钟。
你可以看到,随着任务规模(即“规模”)的扩大,Python的优势会急剧增长。速度本身就很有价值,但当你处理数百万笔销售数据时,这种优势使得分析成为可能。
2. 可追溯性
可追溯性是指追踪任务完成过程的能力。编程过程涉及定义完成任务所需的每个步骤。

对于滑板店的分析,这些步骤可能是:
- 打开销售数据文件。
- 为每个产品筛选数据行。
- 计算销售额的平均值。
- 保存或显示该平均值。

你对每个步骤应如何工作都有预期。因此,当出现问题时,你可以快速识别并修复它。
例如,如果你的平均值看起来太低,你可以检查第一步,发现它错误地引用了去年的数据(使用了May_2031.csv而不是May_2032.csv)。你可以快速更改文件名并重新运行代码。
相比之下,如果你的实习生计算的数字看起来可疑地低,可能需要一段时间才能找出原因。除非你当时就在旁边看着,否则你可能没有任何关于他们做了什么操作的记录。你可能不得不重新进行整个分析。
可追溯性通过创建清晰的步骤记录来节省时间并减少错误。
3. 可重复性
可重复性是指以相同的方式多次执行同一任务。编程语言使重复任务变得容易。它们不会感到无聊或疲倦,并且只需进行少量修改,你就可以调整代码来完成相关任务,例如计算年平均销售额或绘制销售图表。
例如,假设你在滑板店进行下一年的分析。如果你的数据格式相同,你只需在代码中将文件名更改为May_2033.csv并重新运行代码即可。就这么简单。

与此同时,你的实习生可能需要先教新来的同事她之前是如何进行分析的,而新同事的执行方式可能并不相同。手动流程容易因执行者的不同而产生差异和理解偏差。
为什么选择Python?
Python并非唯一的编程语言。在数据分析领域,你通常还会看到R或Julia等语言。
Python是数据分析师入门的绝佳语言,原因如下:
- 广泛的用户基础:无论是个人程序员还是使用它的公司,Python都拥有庞大的用户群,是行业标准。
- 出色的可读性:与许多其他语言相比,用Python编写等效程序通常更快。
- 强大的功能支持:Python在数据可视化、自动化、Web开发等许多领域都有出色的支持。你可以将Python技能用于多种类型的任务。
- 优秀的技术特性:Python拥有一些出色的技术特性,你将在后续模块中学习到。
因此,Python是数据分析领域的杰出选择。
总结

本节课中我们一起学习了计算机编程的核心概念。我们了解到,编程是通过精确指令指挥计算机完成任务的过程。在数据分析中,编程相较于人工方式,在效率、可追溯性和可重复性方面具有显著优势。最后,我们探讨了Python因其广泛的用户基础、出色的可读性和强大的功能支持,成为数据分析领域的首选语言。

在下一个视频中,你将看到用于处理数据的主要Python工作环境。我们下节课见。
005:Jupyter Notebook环境导航 🧭

在本节课中,我们将学习Jupyter Notebook界面的基本操作。Jupyter Notebook是数据分析师日常使用的行业标准工具,我们将了解其核心组成部分和基本功能。
界面概览
这是您在Coursera平台上将使用的Jupyter Notebook界面,也是您完成本课程实验的地方。它本质上是一种特殊的文本编辑器。
您可以看到它与Google Docs的相似之处:左上角是文件名,顶部功能区有一系列选项,主区域则是您可以编辑文本和代码的地方。
认识单元格
Notebook本身是一个文本文档,其不同的区域被称为单元格。单元格允许您将Notebook划分为不同的部分。
以下是单元格的两种主要类型:
- 文本单元格:这类单元格允许您编写一种名为Markdown的格式化文本。双击单元格即可编辑原始的Markdown。例如,您可以在此处添加一个子标题。虽然编写Markdown不是本课程的重点,但它能让您为代码提供格式美观的上下文说明。按下
Shift + Enter可以渲染或显示格式化后的Markdown。您将在本课程的所有实验中都看到Markdown。 - 代码单元格:这类单元格用于编写和运行代码。运行代码单元格将执行其中的代码。
运行代码与常用操作
运行一个代码单元格将执行其中的命令。例如,运行 print("Hi, it's great to see you!") 这行代码。
Shift + Enter 是运行代码单元格的快捷键,这是Jupyter Notebook中最重要的命令,您需要记住它。代码的输出会直接显示在刚刚运行的单元格下方。
您也可以点击工具栏上的“运行”按钮来执行代码。
以下是其他一些有用的操作:
- 如果您的代码运行时间过长需要中断,可以按下“停止”按钮。
- 如果您想从头开始,可以点击“重启”按钮,这将把所有内容重置到您运行任何代码之前的状态。
- “+”按钮允许您添加一个新的单元格。您可以在任何练习或评分实验中添加新单元格来进行实验。
单元格顺序与界面设置
每个单元格侧边的数字表示您运行它们的顺序,这有助于您跟踪代码的执行进度。如果您再次运行一个单元格,这个数字会改变。
查看顶部的功能区,您不需要使用大多数选项。但有一个有用的选项是“编辑”->“清除所有单元格的输出”。有时输出会很长,您可能希望清理您的Notebook。

在设置中,如果您想感觉像个酷炫的黑客,可以切换到深色主题。在主题菜单下,您可以增大代码或Markdown文本的字体大小。

理解内核
请注意“内核”菜单。Notebook基本上是一个包含您给计算机命令的大文本文件,它本身并不运行这些命令。为此,您需要内核。
内核本质上是Notebook的引擎,它是您计算机中实际接收并运行命令的部分。您不需要担心这些内核选项,但了解内核是什么是有帮助的。
辅助工具:Coursera Coach
在Notebook上方,您会看到“Coursera Coach”选项,这是一个内置的LLM聊天机器人,您可以在编码时随时访问它。您也将在视频中看到它的实际应用。
例如,如果您询问“Python是什么?”,教练会给出回答。如果您关闭聊天窗口后重新打开,您的聊天历史将被保存,因此您不必担心保持会话,稍后可以随时参考。
课程配套资源与实践
以上所有操作都在Coursera平台内进行。本课程的下一个项目是一个练习实验,其中包含了本模块所有讲座中演示的Notebook。您可以用它们来跟随视频学习,或在之后参考代码。
许多初学者发现自己在电脑上设置Jupyter Notebook具有挑战性。目前,您将只在Coursera平台上使用Jupyter Notebook。在本课程的最后一个模块中,您将学习一些在个人电脑上设置Notebook的选项。
本课程还包括一些阅读项目,让您可以练习编码技能。这些是可选的,但我鼓励您完成它们,特别是如果您是编码新手。
每个代码块都类似于Jupyter Notebook中的一个单元格,您可以在其中编写代码并运行。完成练习并运行代码块以获得一些反馈。

总结
本节课中,我们一起学习了Jupyter Notebook界面的核心组成部分和基本操作,包括识别和操作文本与代码单元格、运行代码的快捷键、管理单元格输出、理解内核的作用,以及如何利用Coursera Coach辅助学习。您还了解了本课程提供的配套练习资源。接下来,让我们进入下一个视频,观看一些实际的代码示例。
006:输入-处理-输出模型 🧩
在本节课中,我们将要学习编程的核心模型——输入-处理-输出模型。这个模型是理解计算机程序如何工作的基础,它将帮助我们拆解任何复杂的程序,将其简化为三个基本步骤。
概述:程序的神秘面纱

编程语言的功能可能显得很神秘。你可以将一个计算机程序看作是一系列输入、处理和输出的序列。
计算机程序本质上是在进行数学运算。值得庆幸的是,你的Python代码不会只是一堆数学符号。它看起来更像是英语和数学的混合体,这对你来说很方便。但在底层,发生的正是数学运算。

事实证明,在计算机中,每一种类型的数据都可以用数字来表示。
- 如果你处理的是数字,它们本身就是数字。
- 如果你处理的是文本,每个字符可以用一个数字来代表。
- 在一张数字图像中,每个像素的颜色是一个代表红、绿、蓝显示量的数字。
- 视频只是一连串的图像,加上一些额外信息,以此类推。
从根本上说,计算机所做的,就是对代表你数据的数字进行数学运算,无论数据是什么格式。数学支撑着许多复杂而精彩的操作,例如将彩色图像转换为黑白图像、计算每日滑板销售额的置信区间,或者判断一条Yelp评论是正面还是负面的。

拆解模型:输入、处理、输出
将上述过程分解,代码会接收某种信息,通过进行一些数学运算来处理它,然后输出新的信息。这就是输入、处理、输出。

上一节我们介绍了模型的基本概念,本节中我们来看看几个具体的代码示例。
示例一:简单的数字相加
假设你想将几个数字相加。以下是一个实现此功能的程序。
# 输入:三个数字
num1 = 3
num2 = 10
num3 = 2
# 处理:将它们相加
total = num1 + num2 + num3


# 输出:显示结果
print(total)
- 输入是数字3、10和2。
- 处理涉及将它们相加。
- 当你运行代码时,输出是在屏幕上显示结果15。


示例二:复杂的数据处理
这是一个你将在后续模块中探索的更复杂的例子。


你可能还记得上一门课程中的这个电影数据集,它包含了不同年份的顶级电影及其时长。


以下是更复杂的代码。现在不必关注代码细节,在本课程结束时你会理解这里的每一行。它的作用是将整个数据集作为输入,并通过计算每年的平均电影时长来处理它。


输出将是一个图表,可视化展示这些数据。运行代码后,你会得到一个漂亮的折线图,显示过去80年左右电影时长的增长趋势。
深入理解每个组件
正如你所想象的,每个组成部分都可能变得相当复杂。
关于输入
输入可以直接出现在你的代码中,就像前面看到的三个数字。它也可以是一个数据集、一个图像文件夹或其他东西。你的程序需要编写成能接收那种格式的数据。
关于处理
处理步骤在你对输入运行代码时发生。你为计算机编写了一些命令,一旦运行这些命令,计算机就会一步一步地执行它们。处理过程可能显得很神秘,它发生在你的视野之外,就像魔术师在一阵烟雾中消失,片刻后又以不同的装束出现在电影中一样。在刚才的电影例子中,你实际上从未看到电影数据本身。你编写越多的代码,就会对这种幕后的数学运算越熟悉。
关于输出
输出可以是在屏幕上显示某些内容,如前面的例子所示。它也可以是修改或保存一个新文件,或者将结果发送到另一个程序或另一台计算机。有时你运行一个程序,似乎什么都没有发生。计算机正在遵循你的命令,但可能只是这些命令都不涉及在屏幕上显示内容。


总结与预告
本节课中我们一起学习了编程的输入-处理-输出模型。我们了解到,所有程序都可以归结为接收数据、处理数据并产生结果这三个核心步骤。通过简单的加法运算和复杂的电影数据分析两个例子,我们看到了这个模型在不同复杂度场景下的应用。
在你开始自己编写代码之前,还有最后一个视频。你已经看到了编程的力量,以及如何在Jupyter笔记本中运行代码来接收输入、处理并给出输出。但是,何时应该编写程序,何时又该使用电子表格呢?请观看下一个视频,了解如何做出选择。
007:Python数据分析(第3课)|Python与电子表格的选择
在本节课中,我们将要学习Python与电子表格(如Excel、Google Sheets)这两种数据分析工具的核心区别。我们将从界面、数据结构、分析能力、可视化、可追溯性与可重复性等多个维度进行比较,帮助你理解在何种场景下应选择何种工具。
🖥️ 界面与交互方式
Python与电子表格的一个主要区别在于用户界面。在电子表格中,你需要手动管理所有数据。例如,当你想复制一列数据时,必须选择该列放置的位置,并手动添加对其他单元格的引用。
# 在Python中,数据处理通常在后台进行
df['new_column'] = df['existing_column'] * 2
而在使用Python代码时,这类处理通常在后台自动完成。你可以检查数据,但不会像在电子表格中那样直接管理每个单元格。

此外,在电子表格中,你可以轻松地用颜色和字体样式格式化数据,这有助于利益相关者探索数据。在Jupyter Notebook中,你可以使用Markdown进行格式化,但在美化笔记本外观方面的能力相对有限。不过,这两种格式都旨在共享和探索数据,而不仅仅是展示原始数据。
🗂️ 数据结构与建模
电子表格本质上以一种特定格式存储数据:即行和列组成的表格。然而,并非所有数据都最适合用这种方式表示。你之前学过,像文本和视频这样的非结构化数据无法整齐地放入行和列中。
另一个例子是处理具有多个层级或层次的信息。假设你拥有几家滑板店,每家店可能销售一系列品牌,而每个品牌又有不同的产品。用电子表格为这种组织结构建模会变得非常复杂,最终你需要多个工作表来模拟这些关系。
📈 分析能力与复杂性
电子表格为你提供了许多功能,从排序、筛选到执行假设检验。Python则在这些能力上进行了扩展,使你能够执行更复杂的统计分析、运行模拟甚至创建机器学习模型。
同样,如果你需要进行更自定义的分析,在Python中会更容易。例如,在之前的课程中,你使用Google Sheets中的T检验函数进行了假设检验。该函数返回与检验相关的P值。

# 在Python中,你可以用一行代码执行T检验并获取P值、自由度等
from scipy import stats
t_stat, p_value = stats.ttest_ind(group1, group2)
在Python中,你可以用一行代码执行上述每项任务,并为更复杂的场景计算额外的统计量。
🎨 数据可视化
Python在可用复杂性方面的优势也适用于可视化。你可能记得,在Google Sheets中无法创建真正的箱线图,考虑到箱线图非常有用,这令人沮丧。
# 在Python中,只需几行代码即可创建箱线图
import matplotlib.pyplot as plt
plt.boxplot([data1, data2, data3])
plt.show()
在Python中,你可以用几行代码创建箱线图,还可以自定义绘图的每个方面、应用独特的配色方案,并一次性创建多个绘图。

🔍 可追溯性与可重复性

在可追溯性和可重复性方面,Python是更优的选择。如果你想跟踪在电子表格分析中采取的步骤,可以使用版本历史记录,但功能有限。
另一方面,你的Python代码将包含你完成的每一步,一行一行清晰记录。例如,假设你有一个滑板销售的原始数据文件,以及一个包含更有序数据的第二个版本文件。但你究竟做了什么来整理数据?这就像玩“找不同”游戏。
相反,如果你有用Python Notebook清理数据的代码,你可以逐步检查每个步骤,例如,你可能会看到你导入了数据,过滤掉了价格缺失的行,然后添加了一个新列来跟踪促销商品的折扣金额。
Python的可重复性不仅限于重现过去的分析。你还可以进行微小的更改,以快速产生许多类似的输出。这种策略的一些常见用例包括:对相似数据运行相同的分析,或生成许多分析或可视化以找出最佳方案。
例如,如果你正在与一位拥有15个格式相同的销售数据集的店主合作,你只需更改导入数据的那一行代码,然后单击一下即可运行与之前相同的分析。或者,如果你有一个包含20个特征的数据集,你可以通过对同一命令进行微小调整,为每个特征构建95%的置信区间。
✅ 总结与选择指南

本节课中,我们一起学习了Python与电子表格在数据分析中的关键区别。为了总结所有这些差异,以下是一些选择指南:
在以下情况下,电子表格是更好的选择:
- 你希望快速完成分析,尤其是在小规模情况下。
- 你希望能够看到完整的数据。
- 你对可追溯性或可重复性不太关心。
- 你需要大量的格式化和自定义选项。

在以下情况下,Python将是更强的选择:
- 你寻求高效的大规模分析(即处理越来越大的数据集)。
- 你需要进行复杂或自定义的分析或可视化。
- 你需要一个可追溯的过程,以便轻松在不同数据集或特征上重复任务。
到目前为止,你已经了解了Python编程的基础知识,以及首先为什么要使用Python。完成本课的练习评估后,请加入下一节课,开始动手编码。我们下节课见。😊
008:Python数据类型与表达式 🧱
在本节课中,我们将学习Python代码的基础构建块——数据类型。我们将了解三种核心数据类型:整数、浮点数和字符串,并学习如何对它们进行基本的数学运算。课程将使用一个真实的图书馆年度数据集作为示例,演示如何像使用电子表格一样在Python中执行计算。
数据类型简介
上一节我们介绍了数据分析的基本流程,本节中我们来看看构成代码的基础元素——数据类型。
在Python中,你可以处理不同类型的数据,并根据其类型执行不同的操作。目前,你将主要使用三种核心数据类型:整数、浮点数和字符串。
- 整数:代表整数,包括负数。例如:
-10,177。 - 浮点数:代表实数,包含小数点,也可以是负数。例如:
0.0,1.7,-200.03。 - 字符串:代表文本。在Python中,文本必须包含在引号内,这样Python才能将其识别为文本而非命令。例如:
"oranges and apples"或":-)"。
数据类型的重要性可能远超初看时的印象,因为类型决定了你可以对数据执行何种操作。
类型的重要性:一个例子
理解了基本概念后,我们通过一个例子来看看类型如何影响操作。
请看下图中的两个值,你能分辨它们的类型吗?




左边的 400 是一个整数。而右边带引号的 "400" 是一个字符串。
尽管它们在你我看来相似,但计算机对它们的处理方式截然不同。例如,将左边的数字除以2会得到结果 200:
400 / 2 # 输出: 200.0
而尝试将右边的字符串除以2则会导致错误,因为你无法对一段文本执行除法运算:
"400" / 2 # 这将引发 TypeError(类型错误)
实战演练:图书馆数据分析

现在,让我们将这些知识应用到实际数据分析中。本节中,我们将使用美国康涅狄格州一家图书馆的真实年度数据集。





假设你收到了来自美国康涅狄格州哈特福德普莱恩维尔公共图书馆的邮件。他们发送了一些数据,其中每一行代表图书馆一年的运营情况,每一列是该年的某项特征。
图书馆向你提出了两个问题:
- 2023年的图书馆访问总人次是多少?
- 2023年每次图书馆访问的平均收入是多少?
你会发现,在Python中执行这些操作与你已经熟悉的电子表格操作非常相似。
任务一:计算总访问人次
首先,我们来计算2023年的总访问人次。公式是:
总访问人次 = 人均访问次数 × 总人数
在Python中,你可以像在电子表格中一样,使用星号 * 进行乘法运算:
3.8 * 17479
运行这行代码,得到结果 66420.2,即约66,000次总访问。
任务二:计算每次访问的平均收入
接下来,我们使用刚刚计算出的结果来完成第二个任务。公式是:
每次访问收入 = 总收入 / 总访问人次
830000 / 66420.2
运行代码,得到结果 12.51,即每次图书馆访问的平均收入约为12.51美元。
回顾与总结

在本节课中,我们一起学习了Python的三种核心数据类型及其在表达式中的应用。
你能指出在上述每个表达式中使用了哪些数据类型吗?回顾第一个代码单元格:
3.8是一个浮点数(有小数点的数字)。17479是一个整数(没有小数点的数字)。
以下是Python中你将经常使用的三种关键数据类型总结:
- 整数:整数。
- 浮点数:带小数的数字。
- 字符串:文本。
你可以像在电子表格中一样,在数学表达式中使用整数和浮点数,来计算诸如利润或每次访问收入等指标。
对于当前这个任务,使用电子表格或许看起来更简单。但随着任务变得复杂,Python的优势将变得非常明显。

做得好!你已经认识了每次用Python编写代码时都会用到的核心数据类型。
在接下来的课程中,我们将学习更多关于打印输出和代码注释的知识。
009:打印输出与注释 📝
在本节课中,我们将学习如何通过打印输出和注释来增强代码的可读性。编程不仅仅是进行计算,我们经常需要为自己或他人添加信息说明。我们将学习使用 print 语句来显示信息,以及使用注释来为代码添加说明。
打印输出
上一节我们介绍了基本的计算,本节中我们来看看如何将计算结果清晰地展示出来。在Jupyter Notebook中,默认会显示单元格中最后一个计算的值。然而,使用 print 命令可以更灵活地控制信息的显示。
print 命令可以将信息输出到屏幕上。你可以通过逗号分隔来打印多个信息片段。

以下是使用 print 命令的基本语法:
print("标签文本", 表达式)
这种策略允许你在代码中为信息片段添加标签。例如,你可以先打印一段文本作为标签,然后打印计算结果。
运行包含此代码的单元格,你会得到一个格式清晰的输出。你能看出这个 print 命令中使用了哪些数据类型吗?这里有一个字符串标签和一个浮点数结果。
print 命令会将它们显示在同一行,并用一个空格分隔。
对于第二个任务,你可以这样做:
print("Income per library visit", 表达式)
同样,你也会得到一个格式清晰的输出。😊
良好的实践是使用 print 语句来显示信息,而不是依赖Jupyter Notebook显示最后一个值。print 语句的格式通常更美观,并且你可以在一个单元格中使用多个 print 语句。
处理错误
假设你在编写这些任务的代码时遇到了错误。
你可能会注意到,这个错误是由于缺少右括号引起的。对你我来说,这段代码的意思可能仍然相同。但计算机没有那个括号就无法完成任务。
顺便说一下,忘记括号是一个非常常见的错误。
首先,你可以尝试通过阅读错误信息并修复代码来自行解决这个错误。
然而,错误信息可能会变得冗长而复杂。如果你遇到困难,可以随时向你的LLM(大语言模型)求助。
例如,你可以说:“嘿,我在编码时遇到了这个错误。你能帮我理解为什么会发生这个错误吗?”然后复制整个错误信息,甚至可以使用 Shift+Enter 在聊天窗口中添加新行。
然后它可能会说:“你遇到的错误是一个语法错误,这意味着你的代码结构有误。查看你的代码,问题在于缺少一个右括号。因此,你需要添加那个右括号来纠正这个问题。”你可以复制它建议的代码,看看是否能解决问题。
好的,看起来修复成功了。错误是编码过程中完全正常的一部分。
看似微小的事情,比如漏掉这个逗号,或者不小心在 print 这个词里加了一个空格,都会导致错误。


别忘了,你随时可以请你的LLM帮助解决它们。
代码注释
注释是给你自己或你的协作者看的笔记。在Python中,注释以井号 # 开头。它们可以独占一行,也可以放在已有命令的行的末尾。当计算机看到井号时,它会完全忽略该行井号之后的所有内容,直接转到下一行。
你将在本课程的练习实验、评分实验以及所有视频中看到注释。
假设你要把这部分代码发送给同事,并想用更多信息来标记它。你可以添加一个注释。


注释以井号 # 开头。计算机会完全忽略该行井号之后的所有文本。下一行将正常执行。所以,注释可以从一行的开头开始,也可以放在一行的末尾。
例如,你可能想说:“仅2023年的访问量”,所以这个信息只是给你(人类)看的。计算机会完全忽略注释文本。
再举一个例子,你可以在这里末尾添加一个注释,写上“这应该以美元为单位”,即 # dollars。
计算机会执行井号之前的所有内容,忽略“dollars”,然后执行下一行(如果有的话)。如果你再次用 Shift+Enter 运行该单元格,你会得到相同的输出。无论你添加多少注释,都不会影响代码执行。
你也可以在两行代码之间放置注释,这也是完全可以的。例如,在这里你可以保存“仅2022年的访问量”,然后在下一行计算总数。

两行代码都会按预期工作。

总结
本节课中我们一起学习了如何使用 print 语句来格式化输出信息,以及如何使用 # 符号添加注释来增强代码的可读性和可维护性。我们还了解了如何处理常见的语法错误,并知道在遇到困难时可以寻求LLM的帮助。你已经看到了注释和代码是如何结合的,接下来请跟随我到下一个视频,学习如何在Python中使用变量来存储信息。
010:变量存储 📦
在本节课中,我们将要学习编程中的一个核心概念:变量。变量允许我们存储和重复使用数据,从而提高代码的可读性、可维护性和效率。

概述
编程的一个关键优势是可重复性。实现可重复性的一个重要特性是通过变量来复用数据。假设你再次为普莱恩维尔图书馆工作,需要计算2023年的利润。

你编写了这行代码来完成计算。你注意到最后两个单元格中重复使用了哪个值?2023年的总收入被使用了两次。重复的值正是在代码中使用变量的好机会。
这有几个原因。首先,多次输入这个长数字很麻烦。其次,它可能引发错误,比如拼写错误。另一个常见情况是,如果图书馆发现这个数字记录有误,实际值应为830,000。目前,你必须手动在它出现的每个地方重新输入这个值。想象一下,如果你的代码中有数百处使用了这个值,该如何避免这种繁琐的工作?
创建与使用变量
让我们回到原始的正确值。你可以创建一个变量来存储这个值一次,但多次使用它。
你可以创建一个名为 income_2023 的变量,并在该变量中存储值 830696。你在这里所做的,是将这个整数存储在一个带有此名称的“盒子”中。
income_2023 = 830696
如果你打印 income_2023,会发生什么?
print(income_2023)
你会得到 830696,即存储在这个名称下的数字。现在,你可以在任何需要此值的代码行中使用这个名称。
如果你复制使用这个数字的单元格,可以将所有 830696 的实例替换为 income_2023。
# 替换前
profit_2023 = 830696 - 794398
print(profit_2023)
print(830696)

# 替换后
profit_2023 = income_2023 - 794398
print(profit_2023)
print(income_2023)
运行单元格时,你期望发生什么?你应该会看到打印出两行,每行对应一个打印命令。结果如下,2023年的利润和总收入都与之前的结果一致。
现在,如果图书馆意识到这个数字实际上应该是830,000,你只需在一个地方更改它,再次运行,所有相关结果都会更新。

变量的工作原理
顺便说一下,这个过程与电子表格中的操作非常相似。现在,你有一个包含830696的单元格,它就像一个名为 I4 的变量。盒子 I4 中的值可以改变,但无论内容如何,这个盒子始终被称为 I4。因此,在任何涉及830696的计算中,你都可以使用这个变量名 I4。如果你将 I4 中的值更新为830,000,这里的所有计算都会相应更新。
让我们更详细地看看这里发生了什么,以及变量是如何工作的。
变量用于存储值,特别是那些你预期会更改或复用的值。你可以将每个变量视为一个可以存储某些信息的盒子。
创建变量时,发生两件事:声明它(选择其名称)和赋值(赋予它一个值)。
# 声明变量 income_2023 并赋值为 830696
income_2023 = 830696
你只声明一个特定的变量一次,但可以随意多次为其分配新值。
考虑你刚才看到的代码行。income_2023 = 830696。你有一个标记为 income_2023 的盒子,并将值 830696 存储在其中。当你想在代码中使用这个值时,你告诉计算机检查标记为 income_2023 的盒子,并使用里面的任何值。
Python变量类似于电子表格中的单元格。你有一个单元格,在其中存储一个值,并且该单元格有一个名称。在这种情况下,名称是 income_2023,而不是行和列的引用。
如果这个值需要更新为830,000,之前的值会被完全丢弃并替换。你不再在任何地方保存之前的值。这个过程称为覆盖。只有当你确信不需要之前的值时,才应该这样做;否则,你应该创建一个新变量。
变量在表达式中的求值
你还看到了这个计算:print(income_2023 - 794398)。


刚才,这里到底发生了什么?在这种情况下,你已经为 income_2023 赋值,现在你在一个表达式中使用它。当Python执行到这行代码并看到 income_2023 时,它会寻找具有该名称的盒子(或可以将其视为具有该名称的单元格),并用其当前值替换变量名。在本例中,当前值是 830696。然后,Python继续进行减法运算,将整个表达式替换为 35602,并最终打印出该值作为计算结果。
总结
本节课中,我们一起学习了变量的核心概念。变量是存储数据的“盒子”,通过声明名称和赋值来创建。它们允许我们避免重复输入,轻松更新数据,并使代码更清晰、更易于维护。变量是几乎所有程序中都会出现的强大工具。
在下一个视频中,我们将了解如何避免变量可能引入的常见错误。


011:Python数据分析(第3课)|使用变量与调试 🐛
在本节课中,我们将学习变量的使用以及如何调试代码中的错误。变量是编程中的基础工具,但使用不当也可能引入错误。我们将探讨变量命名的规则、常见错误类型以及有效的调试策略。

变量命名规则 📝
上一节我们介绍了变量的基本概念,本节中我们来看看如何正确地为变量命名。变量命名需要遵循特定规则,以确保代码的可读性和正确性。
以下是变量命名的主要规则:

- 变量名只能包含字母(大写或小写)、数字和下划线(
_)。 - 变量名必须以字母开头。
- 变量名是区分大小写的。例如,
income2023和Income2023是两个完全不同的变量。
你可以通过公式来理解命名规则:有效的变量名 = 字母 + (字母/数字/下划线)*。
关于更具体的命名规则,你可以在接下来的阅读材料中了解更多。
使用描述性变量名 🏷️
理解了命名规则后,我们来看看如何为变量选择一个好名字。使用描述性的变量名至关重要,它能让你的代码更容易被理解。
假设我们需要计算图书馆的总访问量,其值为 人口数 * 人均访问次数。
理论上,你可以将变量命名为 x:
x = 3.8 * 17479
运行这段代码完全没有问题,结果也与预期一致。然而,使用像 total_library_visits 这样的描述性名称会更好。虽然名字更长,但对阅读代码的人(包括未来的你)帮助巨大。计算机并不关心变量名是什么,但清晰的命名能显著提升代码的可维护性。
变量区分大小写与调试 🔍
在使用描述性变量名时,一个常见的错误来源是忽略了大小写敏感性。让我们通过一个例子来理解这一点。
如果你打印 total_library_visits,会得到正确的数字。但如果你尝试打印 Total_library_visits(首字母大写),代码将无法运行并报错。
记住,对计算机而言,大写字母 T 和小写字母 t 是完全不同的字符。如果你遇到此类错误,可以随时向大型语言模型(LLM)求助。例如,你可以提问:“我试图打印 total_library_visits 但遇到了这个错误,请帮我理解原因。” LLM 通常会指出错误是由于变量名大小写不匹配造成的。
变量值的覆盖与逻辑顺序 ⏱️
调试不仅涉及语法错误,也涉及逻辑错误。变量值的意外覆盖就是一种常见的逻辑错误。
假设图书馆要求你计算2022年的总访问量。如果你重用同一个变量名:
total_library_visits = 3.3 * (17479 - 34)
然后打印 total_library_visits,输出结果将是2022年的新值(约57,000),而不是之前2023年的值(约66,000)。这是因为代码按顺序执行,后面的赋值操作会完全覆盖变量之前的值。
如果你后续需要同时使用这两个值,就应该创建两个独立的变量,例如 total_library_visits_2022 和 total_library_visits_2023。
变量定义与使用的顺序 🔄
另一个关键点是变量必须先定义后使用。请看以下两行代码:
print(total_operating_expenses)
total_operating_expenses = 385000
运行它们会导致错误。原因是你试图在变量 total_operating_expenses 被定义之前就打印它的值。简而言之,你必须确保定义变量的代码出现在任何使用该变量的代码之前。在 Jupyter Notebooks 中,这些代码可以出现在不同的单元格里,但保持逻辑顺序(先定义后使用)是最佳实践,这能使代码更易读,并避免令人困惑的错误。

调试策略与心态调整 🛠️
在编程中,调试(寻找并修复错误)是一项核心技能。错误是编码过程中正常的一部分,就像写文章时也会使用退格键修改一样。请将错误视为学习过程中的常规环节。
以下是三种关键的调试策略:
- 尝试修改代码并测试:测试你的代码是完全免费的,只需按
Shift + Enter运行。你可以主动思考如何“破坏”代码,例如,如果漏掉一个引号或括号会发生什么?然后进行测试,看看结果是否符合你的预测。 - 向 LLM 求助:即使是很短的提示也可能非常有效。例如,直接询问“这个错误信息是什么意思?”并粘贴错误信息。LLM 在大量互联网代码上训练过,是优秀的编程伙伴。
- 搜索网络并加入社区:如果你想与他人交流代码问题,我鼓励你搜索网络并加入相关社区(例如 DeepLearning.AI 社区)。你随时可以就本课程的任何问题发起新的话题讨论。
总结 📚
本节课中我们一起学习了变量的高级用法和调试技巧。我们探讨了变量命名的规则、使用描述性名称的重要性,以及变量区分大小写和顺序执行可能带来的错误。最后,我们介绍了三种实用的调试策略:主动测试、利用 LLM 以及参与社区讨论。培养强大的故障排除技能至关重要,因为错误是编程中完全正常且经常遇到的部分。

请跟随我进入下一个视频,开始学习一种新的数据类型:列表。
012:创建列表 📝
在本节课中,我们将要学习Python中一种非常重要的数据结构——列表。列表用于存储有序的数据集合,在数据分析中极为常见。我们将通过一个图书馆收入分析的例子,了解为什么需要列表、如何创建列表,以及列表带来的便利。
为什么需要列表?🤔
单个的整数、浮点数或字符串本身很有用。但在数据分析中,你经常会遇到序列,即有序的值集合。列表是最常见的序列之一。
假设公共图书馆希望你分析过去五年的总收入。数据如下:


如何用Python代码存储这些信息?
一种方法是使用你刚学过的变量:
income_2019 = 723540
income_2020 = 876123
income_2021 = 934567
income_2022 = 1012345
income_2023 = 1123456
但这似乎效率低下。目前只有五年数据,但回顾之前的电子表格,哈特福德康涅狄格州普莱恩维尔图书馆的数据总共有28年。为28年分别创建28个变量非常低效。
让我们询问大语言模型(LLM):“我目前在Python中使用多个变量仅存储收入。我可以用什么替代?”并粘贴这些变量。
LLM建议可以使用列表。
创建你的第一个列表 🛠️
以下是LLM建议的代码:
incomes = [723540, 876123, 934567, 1012345, 1123456]
我们来逐步分析:
- 变量名
incomes是复数形式,因为它代表许多收入,而不仅仅是一个。 - 方括号
[]表示这是一个列表。 - 每个值都包含在方括号内,用逗号分隔。
这个列表很有用,因为现在你只有一个变量就包含了所有数据。运行这个单元格,你就声明并赋值了这个变量,可以在代码中使用它。
列表的威力:使用内置函数 ⚡
创建列表后,你可以对它进行很酷的操作。例如,可以使用专门处理列表的特殊函数,比如 sum 函数。
如果你需要计算这些年的总收入,可以这样做:
print(sum(incomes))
运行后,你会得到约380万。这非常快。
如果你想对所有这些单独的变量求和,则必须这样做:
total = income_2019 + income_2020 + income_2021 + income_2022 + income_2023
print(total)
这两种方法结果等价,但使用列表的那一种更快、更容易,且更不易出错。

列表的灵活性:添加新数据 ➕
假设图书馆又找到了2017年和2018年的数据:

现在怎么办?
如果使用变量,你必须创建两个新变量并输入这些值,然后将其加入计算,以获得新的总和530万。
你认为如何将这些数字添加到你的列表中?在这种情况下,因为这是一个有序的数据结构,你可以将它们添加到列表的开头(对应2017年,然后是2018年)。
看看这行对列表求和的代码:sum(incomes),它会如何变化?答案是它不会变。sum(incomes) 将求和列表中的所有收入,无论列表有多大。运行后,你可以看到这些值是匹配的。
列表的局限性(及暂时解决方案)⚠️
你可能已经注意到列表的一个缺点:将数据放入列表后,你无法知道哪个数字对应哪一年。你只能希望自己按正确顺序输入了数据。
目前,你可以通过创建第二个按顺序包含年份的列表来解决这个问题,如下所示:
years = [2017, 2018, 2019, 2020, 2021, 2022, 2023]
incomes = [654321, 712345, 723540, 876123, 934567, 1012345, 1123456]
这种策略是一种权宜之计。对于这样的小数据集来说还可以,但你将在下一个模块学习更好的选项。
列表概念总结 📚
列表是一种序列,即具有顺序的值集合。让我们分解这行代码中发生了什么:
incomes = [723540, 876123, 934567, 1012345, 1123456]
在这里使用列表存储收入是合适的,因为你有一个项目集合(多个数字),它们都代表相同的事物(图书馆收入),并且应该按年份顺序存储。
关注等号右侧片刻:
- 方括号
[]创建了一个列表。 - 方括号内是用逗号分隔的单个值。
为了以后使用这个列表,你需要将其保存在一个变量中。因此,incomes = 声明了一个名为 incomes 的新变量,并为其赋值为右侧列表的值。你创建了一个标记为 incomes 的新“盒子”,并将这个列表存储在里面。
列表通常使用复数变量名,因为它们代表值的集合,而不是像 income_2023 这样的单个值。


有时,列表内的这些值也被称为项。


本节总结 🎯
本节课中我们一起学习了列表。你已经看到,当你有一个代表同类型数据的有序值集合时,列表极其有价值。这种价值来自于能够使用像 sum 这样酷且有用的函数。
列表是存储和处理数据序列的基础工具。在接下来的视频中,我们将学习可以对列表执行的更多任务。
013:Python列表操作 📋

在本节课中,我们将学习Python中列表的基本操作。列表是存储多个数据项的有序集合,是数据分析中处理数据列的核心工具。我们将通过一个图书馆收入数据的实例,探索如何访问、修改和扩展列表。
从CSV加载数据
首先,我们通过一段代码从CSV文件中加载数据。目前你无需深入理解这段代码的细节,因为在下一个模块中你将学习如何自己编写代码来加载CSV数据。现在只需知道,这段代码从普莱恩维尔公共图书馆的数据中创建了两个列表:一个包含收入数据,另一个包含对应的年份。
每个列表都对应之前电子表格中的一列。现在,我们可以用更多的数据来进行操作了。
列表求和与访问元素
你还记得如何对列表中的所有值求和吗?例如,对 incomes 这个收入列表求和,你可以使用 sum() 函数。
print(sum(incomes))
这将输出超过1700万美元的总和。
现在,图书馆交给你的第一个任务是:计算1996年和1997年的收入总和。为此,你需要分别访问这两年的收入。
在Python(以及绝大多数编程语言)中,列表使用“零基索引”。这意味着列表中的第一个元素位于位置0(索引0)。对人类而言,从零开始计数可能感觉很奇怪(毕竟没有人过“零岁”生日),但由于计算机的底层构建方式,零是第一个索引。
因此,1996年的数据在索引0,1997年的数据在索引1。你可以通过以下方式访问它们:
print(incomes[0]) # 输出1996年收入
print(incomes[1]) # 输出1997年收入


假设输出分别是434,000和439,000,那么要计算总和,只需使用加号运算符:
print(incomes[0] + incomes[1])
结果约为874,000。这样,你就完成了列表操作的第一个任务。
更新列表元素


接下来,你需要将1998年的收入更新为460,000。1998年对应索引2。
你可以先打印当前值确认:
print(incomes[2])
有趣的是,incomes[2] 的行为就像一个变量名。这意味着你可以像给普通变量赋值一样,为它分配一个新值。
使用等号进行赋值:
incomes[2] = 460000


然后在新的一行打印 incomes[2],可以看到它的值确实已经改变。恭喜,你又完成了一个任务。
向列表添加新元素
现在,你需要添加一个2024年的预测收入。这个任务需要考虑的是,列表将从28个项目扩展到29个项目,并且新值需要添加到列表的末尾。
要向列表添加值,需要使用 .append() 方法。具体操作是:以列表名开头,使用点号 .,然后跟上 append(),并在括号内放入要添加的项目。
incomes.append(837404)
这里的点号 . 是一个新的代码元素,它代表一个“方法”或“函数”。这行代码的意思是:对 incomes 这个列表执行 append 操作,将值 837404 添加到它的末尾。
运行这行代码后,列表将包含之前所有的数据,并在最后新增一项代表2024年预测收入的数据。
核心概念回顾与总结
我知道上面的演示节奏很快。请记住,你可以随时回看这些演示,并根据自己的理解速度调整视频播放速度。
以下是本节核心概念的总结:
- 列表是零基索引的:列表中每个项目的索引从0开始,而不是1,这需要一些时间来适应。列表中最后一个项目的索引是
列表长度 - 1。例如,一个有10个项目的列表,其索引范围是0到9。 - 访问元素:使用
列表名[索引]的格式来访问特定位置的元素。 - 更新元素:
incomes[2]这样的表达式就像一个变量名,它始终指向列表中的第三个项目。使用incomes[2] = 新值的命令可以更新列表中的值。 - 添加元素:使用
.append()方法在列表末尾添加新元素。点号.允许你对某个数据(如列表)执行一个操作(这里是append函数)。在数据分析和本课程中,你会经常看到这个点号,因此值得花时间练习。
在结束本节课之前,让我们简单看一下函数。到目前为止,你已经见过几个函数,如 print()、sum() 和 append()。在接下来的视频中,我们将进一步扩展你的知识库。

本节课总结:在本节课中,我们一起学习了Python列表的基本操作。我们了解了列表的零基索引特性,掌握了如何使用索引访问特定元素,如何更新列表中已有的值,以及如何使用 .append() 方法在列表末尾添加新元素。这些是处理数据序列的基础技能,在后续的数据分析工作中将经常用到。
014:Python数据分析 - 函数调用 🧮
在本节课中,我们将学习Python中函数调用的核心概念。函数是执行特定任务的代码块,它们接收输入(称为参数),进行处理,并返回输出。我们将通过具体的例子来理解如何调用函数,以及如何利用它们来处理数据。
函数的基本概念
上一节我们介绍了变量和列表,本节中我们来看看如何使用函数对数据进行操作。在Python中,函数对数据执行操作。计算机程序本质上接收一些输入,进行处理,然后产生输出。函数也是如此:它们接收你提供的输入,进行处理,并产生输出。
例如:
print函数接收你想要打印的内容(可以是一个或多个值或表达式),进行处理,并将其显示在屏幕上。sum函数接收一个列表作为输入,将其中的所有内容相加,并输出总和。append函数则有些不同,它实际上有两个输入。
以下是append函数的两个输入:
- 列表本身。
- 你想要追加到列表末尾的项目。
然后,它通过将项目追加到列表来处理这些输入,并输出新的、更长的列表。
函数调用的语法
现在,让我们进一步分解其中两个函数的代码。
对于 print 和 sum 这类函数,调用语法如下:
函数名(参数)
你从函数名开始,加上开括号,输入参数,然后加上闭括号。如果参数有多个,可以用逗号分隔。
函数的输入被称为参数。这个术语来源于数学。如果你觉得它令人分心,可以简单地将其理解为“输入”,但正式术语是“参数”。
append 函数的调用方式则有所不同:
列表变量.函数名(参数)
在左边,你有一个列表变量,然后是一个点 .,接着是函数名 append、开括号、你想要追加的项目,最后是闭括号。
为什么 append 不同?如你所见,其中一个输入(列表)并不在括号内。但点 . 告诉函数也要将列表作为一个输入。在处理列表和其他集合时,你会经常看到这种格式。
函数实战:分析图书馆数据
现在你已经近距离观察了几个函数的代码,让我们看看更多函数在实际中的应用。
我们回到普莱恩维尔公共图书馆的场景。他们分享了过去几年的运营开支数据。以下是将运营开支数据加载到两个列表中的代码,以及这些列表的内容。
首先,图书馆希望你找出开支的最高金额。使用 max 函数可以非常直接地完成这个任务。
以下是具体步骤:
- 使用
print函数,并为其添加一个数据标签。 - 在
print函数内部,使用max函数,并将expenses列表作为其参数。
运行代码后,你会发现所有年份中的最高开支是 801,000。无论列表有多长,max 函数都能高效地找到最大值。
接下来,计算最早的年份。你可以通过查找 years 列表中的最小值来实现。
以下是具体步骤:
- 使用
print函数并添加标签。 - 在
print函数内部,使用min函数,并将years列表作为其参数。
运行代码后,最早的年份是 1996。同样,如果列表很长或未排序,使用函数比手动查找更高效。
计算平均值
现在,让我们尝试一个稍微复杂一点的任务:计算平均开支。要找到平均值,你需要将所有开支相加,然后除以开支的数量。
以下是计算平均值的步骤:
- 相加所有开支:使用
sum函数对expenses列表求和,并将结果保存到一个变量(例如total)中。 - 计算数量:使用
len函数获取expenses列表中的项目数量(len代表长度)。 - 计算平均值:将总和
total除以数量len(expenses),并将结果保存到另一个变量(例如average)中。 - 打印结果:使用
print函数输出平均值。
运行代码后,你得到的平均值大约为 640,000。这个值落在所列开支的中间范围,符合预期。
数据可视化初探
最后一步,只是为了有趣。这里有一个辅助函数叫 create_line_chart,它接收两个参数:一个年份列表和一个数字列表,并创建一张折线图。这能帮助你直观地了解开支随时间的变化情况。
Python 是数据可视化的一个极其强大的工具,你将在本课程的第三个模块中深入学习。
总结


本节课中我们一起学习了Python函数调用的核心知识。我们从函数的基本概念出发,了解了它们如何接收输入、处理并产生输出。我们学习了两种主要的函数调用语法:直接调用(如 print()、sum())和通过点号调用(如 list.append())。通过分析图书馆运营数据的实战案例,我们练习了使用 max、min、sum 和 len 等内置函数来提取最大值、最小值、总和、长度并计算平均值。最后,我们简要接触了数据可视化,看到了函数如何帮助生成图表以理解数据趋势。掌握从类型、表达式、变量、列表到函数这些核心工具,是你日常作为数据分析师工作的基础。
015:Python数据分析中的状态管理 🧠
在本节课中,我们将要学习Python程序运行时的核心概念——状态管理。理解计算机如何跟踪变量和数据,是编写可靠、高效代码的基础。
概述:什么是程序状态?
当计算机运行Python代码的每一行、每一个单元格时,它会追踪代码产生的所有影响。具体来说,它会记住你创建的变量及其值,以便你在后续代码中使用它们。这种被记住的信息集合,就构成了程序的当前状态。
上一节我们介绍了如何计算数据的总和,本节中我们来看看计算机是如何在幕后记住这些结果的。
查看程序状态:变量检查器
与电子表格不同,在电子表格中你可以直接看到所有数据,而Python默认将变量及其值隐藏在视图之外。虽然这使得Python在处理大型数据集时更高效,但也意味着你需要主动检查变量的值,以避免错误。
以下是查看程序状态的两种主要方法:

- 使用变量检查器:在Jupyter Notebook中,右键点击并选择“打开变量检查器”,会弹出一个新窗口。这个窗口会显示你创建的所有变量、它们的类型、内容或值以及其他信息。这就像是当前笔记本状态的一个快照。
![]()

- 使用打印语句:你可以使用
print()命令在代码的特定点显示变量的值。
你可以将变量检查器窗口拖到右侧,以便并排查看变量和代码。例如,当你运行 total = sum(expenses) 这行代码后,变量检查器中会新增一行,显示变量 total 的当前值是1790万。

理解状态:计算的快照
程序状态是计算中一个非常重要的概念,因为它告诉你:“我的计算进行到哪一步了?我创建了哪些变量?”
计算机状态就像是其当前所有信息的快照。在你关闭Jupyter Notebook或手动重启内核之前,你创建的变量都会被保存。这就是当前的状态。
在电子表格中,你直接查看状态,因为所有数据和计算都显示在单元格里。然而,在Jupyter Notebook中,除非你打开变量检查器,否则你无法直接看到这个状态。变量及其值不会显示给你。
这种设计有两个好处:
- 帮助你专注于程序的输出,而不是所有中间步骤。
- 使计算更快,因为计算机无需耗费资源来显示中间结果。
隐藏状态的利与弊
让我们通过一个例子来理解隐藏状态。你之前见过这几行代码:
git_list = load_column_from_csv('data.csv')
max_value = max(git_list)
min_value = min(git_list)
average_value = sum(git_list) / len(git_list)
你知道 git_list 从CSV文件加载了一列数据,但你实际上看不到列表里有哪些值。你可以在不看到数据本身的情况下计算最大值、最小值和平均值。
当然,你可以选择使用 print(git_list) 命令来确保数据加载正确,并帮助你直观感受最大值、最小值和平均值应该是什么样子。
隐藏状态的优势在于它是Python能够高效扩展的核心。如果你有一台能100%可靠执行计算的计算机,你并不总是需要像在电子表格中那样看到中间步骤。这使得计算非常快速。
同时,隐藏状态也是常见问题的根源。你可能会认为一个变量有某个值,而它实际上有另一个值。你可能认为数据加载正确了,但实际上并没有。
最佳实践:主动管理你的状态
因此,由你来负责探查程序的隐藏状态,通常是通过使用打印语句。print() 语句帮助你在代码的特定点显示变量的值。你之前看到的变量检查器也是一个选择。
关键建议是:不要对你的程序状态做假设。当你的代码运行结果不符合你的预期时,使用打印语句或变量检查器来查看你实际在处理哪些值。
总结与下一步
本节课中,我们一起学习了Python中的状态管理。我们了解到:
- 程序状态是计算机记住的所有变量和值的集合。
- 与电子表格不同,Python的状态默认是隐藏的。
- 我们可以使用变量检查器和
print()语句来主动查看和管理状态。 - 理解并检查状态是避免错误、编写可靠代码的关键。

一旦你完成了本课的练习实验和作业,请跟随我进入下一课,学习更多关于控制流的知识——如何在程序中重复执行代码和创建分支代码。下次见!😊

016:控制流
在本节课中,我们将要学习Python中的控制流。控制流决定了代码执行的顺序,它让程序能够做出决策和重复执行任务,而不仅仅是按顺序从上到下运行每一行代码。
什么是控制流? 🔄
在您目前编写的程序中,单元格里的每一行代码都是按顺序从上到下执行的。然而,您经常需要程序能够做出决策或重复执行任务。这些模式就称为控制流。
控制流是代码中各个语句被执行或运行的顺序。它决定了计算机执行代码的路径。
控制流主要有四种类型:顺序执行、条件执行、重复执行和函数调用。本节课我们将重点学习前三种,函数调用将在后续课程中详细介绍。
顺序控制流 📜
您目前编写的代码中已经见过了顺序控制流。这是代码运行的默认方式。除非您引入了本节课将要学习的一些控制结构,否则您的代码行将按顺序执行。
条件控制流 🚦
上一节我们介绍了顺序执行,本节中我们来看看条件控制流。条件控制流仅在指定条件为真时,才执行特定的代码行。它在您的代码中创建了分支路径,有点像道路上的分叉口,您的代码可以选择走一条路或另一条路,但不会同时走两条。

让我们举一个现实世界的例子。假设您正在处理一个包含世界各地图书馆的数据集,您想统计位于巴西的图书馆数量。

对于第一个图书馆,您会查看其国家字段,然后根据该值采取行动:
- 如果国家字段的值是“巴西”,那么您就在总数上加1。
- 如果值是其他任何内容,那么您什么都不做。
顺便一提,巴西有超过75,000个图书馆。
您可能已经在电子表格中遇到过条件语句。像 COUNTIF、SUMIF 和 AVERAGEIF 这样的函数可以处理不同的条件。例如,COUNTIF 可以处理这个精确的图书馆统计任务,计算国家为“巴西”的行数。
在Python中,条件控制流通常使用 if、elif 和 else 语句来实现。其核心逻辑可以用以下伪代码描述:
if 条件为真:
执行这段代码
else:
执行另一段代码
重复控制流 🔁

接下来是重复控制流。如果您有一个包含100个项目的列表,并且需要将它们全部除以2,您肯定不想写100行代码。
重复控制流允许您编写几行代码来重复执行某个操作。例如:打印1到100之间的所有数字,或者将列表中的每个项目加到我的总数变量中。
重复控制流类似于电子表格中的数组公式函数。您有一个操作(比如文本处理),并且希望在许多单元格上执行它,而不必手动将公式添加到每个单元格。数组公式只需一个公式,就能为每个单元格重复该操作。
在Python中,这通常通过 for 循环或 while 循环来实现。例如,对一个列表中的每个元素进行操作:
for 项目 in 列表:
对项目执行操作
控制流为您设计程序提供了极大的灵活性。

总结 📝
本节课中我们一起学习了Python控制流的三种基本类型:
- 顺序控制流:代码默认的、按行顺序执行的方式。
- 条件控制流:使用
if等语句,让程序根据条件判断选择执行不同的代码分支。 - 重复控制流:使用
for或while循环,让程序能够高效地重复执行特定任务。
掌握这些概念是编写动态、高效Python程序的基础。在接下来的视频中,我们将学习Python中的比较操作,这是构建条件判断的关键。
017:Python数据分析基础 - 比较运算 🔍

在本节课中,我们将要学习如何在Python中使用比较运算符。这些运算符能帮助我们根据数据做出判断,例如,根据餐厅的卫生检查分数来评定等级。
概述
在数据分析的基础中,数据是任何可用于决策的信息。那么,如何在Python中基于数据做出决策呢?
假设你正在与一个执行餐厅检查的政府机构合作。检查员巡视餐厅,并根据其卫生状况给出0到100的分数。这些原始分数随后被分析,以更好地了解餐厅的整体表现,并告知顾客有关健康和安全违规行为。
- 如果分数为90或以上,则被视为A级。餐厅可以公开展示A级,并且通常检查频率较低。
- 80到89分为B级。餐厅必须展示B级,并且可能被更频繁地检查。
- 70到79分为C级。餐厅必须展示C级,并且需要立即采取纠正措施,否则将面临关闭。
- 任何低于70分的都被视为不合格,将导致立即关闭。
请注意,不同的分数如何导致不同的行动方案。假设你获得了一个类似这样的数据集(改编自美国加利福尼亚州洛杉矶县发布的数据集),其中有一列分数。但这些分数需要转换为评级,以便发送正确的标识并安排必要的检查或关闭。
这个数据有67000行,每一行代表一次检查。因此,尽管你可以手动完成这项工作,但你肯定不想这样做。让我们使用一个包含五行的随机样本来看看如何将这些分数转换为评级,然后稍后可以扩展到整个数据集。
开始进行比较
以下是代表两列数据的两个列表:餐厅名称和对应的分数。
names = ["Beverly falafel", "De Paoverma", "Melrose shrimp", "Modern E's", "The Original Pantry"]
scores = [96, 90, 79, 82, 69]

所以,names[0] 是 "Beverly falafel",而 scores[0] 是96,即Beverly falafel的分数。
顺便说一下,像这样存储多行数据的列表是完全可行的。你也可以将A级的分数线存储在变量 a 中,即90。
你可能会问的第一个问题是:Beverly falafel的分数是A级吗?要回答这个问题,可以这样写:
print(names[0], "got an A?", scores[0] >= a)
你认为应该打印什么?scores[0] 的值是96,a 的值是90,96确实大于90。因此,当你运行这个单元格时,会得到值 True。
True 是一种特殊类型的值,稍后我们会进一步探讨。现在,你可以对其他分数进行同样的检查。让我们检查一下Melrose shrimp是否得了A。
print(scores[2] >= a)
答案是 False。Melrose shrimp的分数是79,实际上是C级,很不幸。
因此,大于或等于(>=)是一种比较运算符。
使用其他比较运算符
你如何检查一家餐厅的分数是否低于70分,这将意味着立即关闭?

你可以请你的LLM(大语言模型)帮助修改这段代码。LLM建议你可以更改打印语句中的条件,并给出了一些代码来进行这个新的比较。你可以试试那段代码:Melrose shrimp没有不及格。
请注意,LLM选择了一个不同的比较运算符:小于(<)。

让我们看看Python中可用的比较运算符选项。
大于或等于(>=)只是众多比较运算符中的一个。比较运算符接受两个值,一个在左边,一个在右边,并回答关于这些值的问题。这些问题只能有两个可能的答案:True 或 False,没有中间状态。这种类型的输出值称为布尔值。
布尔值听起来很高级,但它只意味着真/假值。它只是Python中的另一种数据类型,就像整数(int)、浮点数(float)和列表(list)一样。
Python中有六种比较运算符:
- 小于(
<) - 小于或等于(
<=) - 大于(
>) - 大于或等于(
>=) - 等于(
==) - 不等于(
!=)
前四个在电子表格和计算机中看起来完全一样,根据不等式返回布尔值 True 或 False。
接下来是等于,它用两个等号(==)表示,以及不等于,用感叹号加等号(!=)表示。
为什么相等运算符要用两个等号?这是因为单个等号(=)已经被赋值运算符占用了,赋值运算符用于给变量赋值。请务必记住:如果你要检查相等性,请始终写两个等号。
应用比较运算符
以下是不同等级的分数范围(左侧)以及餐厅分数的随机样本(右侧)。
| 等级 | 分数范围 |
|---|---|
| A | >= 90 |
| B | 80 - 89 |
| C | 70 - 79 |
| 不合格 | < 70 |
| 餐厅 | 分数 |
|---|---|
| Beverly falafel | 96 |
| De Paoverma | 90 |
| Melrose shrimp | 79 |
| Modern E's | 82 |
| The Original Pantry | 69 |
以下是一些你可能提出的问题,以及可以回答每个问题的不等式:

- Beverly falafel的分数是A吗? 你已经看到这可以用
scores[0] >= 90来回答。 - Modern E's检查不及格吗? 在这种情况下,你可以使用代码
scores[3] < 70。你能想到另一种回答同样问题的方法吗?那将是scores[3] <= 69。这个不等式回答了完全相同的问题(假设分数是整数类型)。请注意,如果分数是浮点数,第二个表达式就不起作用,因为像69.5这样的值会被算作通过检查。 - De Paoverma的分数正好是90吗? 你可以使用代码
scores[1] == 90。
小测试
让我们测试一下你的知识。如何检查Beverly falafel的分数是否正好是100分?
正确答案是:scores[0] == 100。

总结

本节课中,我们一起学习了Python中的比较运算和布尔值。这些运算符允许你在代码中使用条件语句来做出决策。掌握了如何比较数值并得到真或假的答案,是编写智能、自动化程序的关键一步。
在接下来的课程中,我们将学习如何利用这些布尔值,通过 if、else 等条件语句来控制程序的执行流程,从而根据不同的数据情况执行不同的操作。
018:if-else 🧭
在本节课中,我们将要学习如何使用 if-else 语句在代码中做出决策。我们将基于餐厅的评分来分配等级,并逐步构建能够处理大量数据的逻辑。
从比较到决策
上一节我们介绍了如何使用比较运算符。本节中我们来看看如何利用这些比较结果,在代码中执行不同的操作。
你的任务是根据餐厅的评分来分配等级。你已经看到了判断评分是否达到A级(大于等于90分)的代码。为了基于这个判断执行特定操作,你需要使用 if 语句。


例如,第一步可以先简单地打印出该餐厅是否获得了A级评分。使用 print 语句来验证分支代码是否正确运行是一种常见做法。
你的任务是检查每家餐厅是否获得了A级评分。
构建第一个 if 语句
我们以列表中的第一家餐厅“Beverly Falafel”为例。你已经知道,以下比较用于检查其评分是否大于等于A级标准(90分):
score >= 90
要基于这个比较结果执行操作,可以编写一个 if 语句。
- 输入
if,然后粘贴你刚才看到的比较表达式。 - 接着输入一个冒号
:。 - 按下回车后,你会看到代码自动缩进。
冒号和缩进表明,接下来的所有代码都属于这个 if 语句的一部分。只有缩进的代码行会在条件(score >= 90)为真时运行。
以下是具体的代码示例:
if scores[0] >= 90:
print(names[0] + " got an A.")
运行这段代码,会输出:Beverly falafel got an A.
引入 else 处理其他情况
现在,让我们看看评分未达到A级的餐厅“Melrose Shrimp”(评分为79分)。如果你对 scores[2] 和 names[2] 运行上面的代码,会发生什么?
实际上,什么也不会发生。因为条件 scores[2] >= 90 评估为 False,if 语句块内的代码不会执行。
为了处理条件为假的情况,你可以在代码中添加一个单独的分支,即 else 语句。
以下是添加 else 分支后的代码:
if scores[2] >= 90:
print(names[2] + " got an A.")
else:
print(names[2] + " did not get an A.")
现在,无论 scores[2] 的值是多少,这两块代码中总有一块会执行。运行后,代码会打印:Melrose shrimp did not get an A.

理解代码的执行路径
观察以下代码片段,思考它有多少种可能的执行路径?

print("Start of code")
if score >= 90:
print("A")
else:
print("Less than A")
print("End of code")
这段代码有两条不同的执行路径,具体取决于 score 的值:
- 如果
score大于等于90,将执行第1、2、4行print语句。程序输出:Start of code A End of code - 如果
score小于90,计算机将走另一条路径,执行第1、3、4行print语句。程序输出:Start of code Less than A End of code
因此,你可以使用 if 语句在代码中做出决策并创建分支路径。你可以单独使用 if 语句在特定情况下执行某些代码,也可以在 if 块后面添加一个 else 块。
关于 else 的要点
一个常见的问题是:能否在没有 if 语句的情况下单独使用 else 块?

答案是否定的。else 块不能独立存在,它必须跟在 if 语句(或 elif 语句)之后。else 块用于定义当 if 语句中的条件不满足时应发生的情况。


总结与展望
本节课中我们一起学习了 if-else 分支结构。我们掌握了如何根据条件判断执行不同的代码块,并理解了代码的两种基本执行路径。
分支代码是编程的基础。在数据分析中,并非所有数据都与你试图回答的问题相关,不同类型的数据也需要不同的处理方式。
在接下来的课程中,我们将学习如何将条件判断扩展到整个数据集。
019:for循环
在本节课中,我们将要学习Python中的for循环结构。循环是编程中用于重复执行代码块的核心工具,它能极大提升代码效率,避免重复劳动。我们将从基础概念开始,逐步理解for循环的工作原理及其强大之处。
循环的必要性

到目前为止,你已经学会了如何编写条件语句来一次检查一个数据。但这是一个繁琐的过程,无法体现Python的效率。为了实现高效编程,你需要编写能够重复执行动作的代码。
请看以下两个代码块,它们是上一视频中代码的简化版本:
if scores[0] > 90:
print("A")
else:
print("Less than A")
if scores[1] > 90:
print("A")
else:
print("Less than A")
你注意到了什么?它们看起来非常相似,实际上,它们仅在一个字符上不同:列表的索引号。那么,有没有办法重写这段代码,使其能为列表中的每一项运行呢?
引入for循环
你可以向大语言模型提问:“我有一个餐厅评分列表,并编写了以下代码来检查它们的分数是否为A或更低。我想检查所有分数,如何重写代码以避免重复?”
大语言模型会回复:你可以创建一个循环来遍历列表中的所有分数。
好的,假设scores和A已经定义,你可以跳过那部分,直接复制循环代码并运行看看会发生什么。
以下是使用for循环的代码:
scores = [96, 91, 85, 88, 93]
for score in scores:
if score > 90:
print("A")
else:
print("Less than A")
这段代码打印了五次,对应列表中的每一项。如果分数高于90,它执行第一个分支(if分支),打印“A”;否则,执行else分支,打印“Less than A”。
注意,for score in scores是唯一新增的代码行。这创建了一个称为for循环的控制结构。
for循环的工作原理
for循环会为列表scores中的每一项运行一次缩进的代码块。每次运行时,变量score会取列表中的一个新值,依次遍历。

首先,score将是96,然后是91,依此类推。实际上,你可以再写一个循环来打印score,以观察循环内部发生了什么:
for score in scores:
print(score)
这样你就能得到列表中的每一个值。
编写这个循环几乎等同于拥有五份相同的代码副本。事实上,以下是不使用循环的等效代码:
score = scores[0]
if score > 90:
print("A")
else:
print("Less than A")
score = scores[1]
if score > 90:
print("A")
else:
print("Less than A")
# ... 为scores[2], scores[3], scores[4]重复
运行这段代码会得到相同的输出,但使用循环无疑节省了大量时间。
解析for循环的组成部分
让我们仔细看看刚才使用的代码,每个部分的作用是什么?
-
scores = [96, 91, 85, 88, 93]
这行代码你之前见过,它创建了一个类型为列表的新变量,用于存储所有餐厅评分。 -
for score in scores:
这行代码创建了一个循环。循环会重复执行一个代码块。for是一个Python关键字,表示你将重复执行代码块一定次数。score in scores创建了一个新变量score,它在每次循环运行时都会改变,并依次取scores中的每一个值。
退一步看,这行被称为for循环的代码,允许你为列表中的每个项目运行相同的代码行,而无需每次都创建新变量。
它之所以被称为“循环”,是因为一旦你执行到缩进代码块的末尾,就会循环回到它的顶部。当所有操作完成后(在本例中,即循环处理完列表中的最后一项),循环停止,计算机继续执行循环之后的代码行。

for循环的强大之处:处理大规模数据
以下是一个快速演示,说明for循环为何如此强大。
让我们导入一个辅助函数,从整个数据集中读取分数并将其保存在变量scores中。现在,如果你打印scores的长度,会得到超过67,000。这是完整的数据集。
你可以编写一个循环来计算这些数据中A级评分的数量:
total = 0
for score in scores:
if score >= 90:
total = total + 1
print(total)
- 从变量
total开始,值为0。表示尚未开始计数。 for score in scores:依次检查每个分数。- 如果分数大于或等于A(90分),你将给
total加1。即total = total + 1。 - 循环结束后(注意
print不在缩进内),打印total。
这段代码统计了获得A级评分的餐厅数量。你猜猜在67,000家餐厅中有多少家?超过63,000家!几乎是95%。
请注意,从处理5个项目的列表扩展到处理超过60,000个项目的列表是多么容易。你根本不需要更改任何循环代码。这段代码运行也仅需几分之一秒(通常约2-3毫秒),尽管数据集如此庞大,它可能导致Google Sheets延迟或Excel工作簿崩溃。通过创建循环来处理数万行数据,你开始看到Python效率的强大之处。
总结

本节课中,我们一起学习了Python中的for循环结构。我们了解了其基本语法 for item in list:,并理解了它是如何通过遍历列表中的每个元素来重复执行代码块,从而避免重复劳动、提升代码效率的。我们还通过一个统计大规模数据中A级评分数量的实例,亲眼见证了for循环在处理海量数据时的强大性能和可扩展性。掌握for循环是迈向高效数据分析的关键一步。
020:缩进规则 📐

在本节课中,我们将要学习Python中一个至关重要的概念——缩进。缩进是Python语法结构的一部分,尤其在条件语句和循环中扮演着关键角色。我们将探讨缩进的工作原理、常见的错误类型,以及如何避免和调试这些错误。
缩进是什么?
上一节我们介绍了条件语句和循环,它们能帮助你创建复杂的工作流程。本节中我们来看看这些控制结构都涉及的一个共同特性:缩进。
缩进是指在代码行前添加空格(通常是4个),用于告诉Python哪些代码行属于同一个代码块。在Python中,缩进本身就是语法的一部分,而不仅仅是让代码看起来美观。
当你编写一个 if 语句或一个 for 循环时,该行以冒号 : 结尾。这个冒号表示Python期望后面跟着一个缩进的代码块,即属于该控制结构的一组代码行。
以下是上一节视频中使用过的一个 for 循环示例:
for item in list:
# 这是循环内部的代码
print(item)
# 这是循环外部的代码
人们常说代码在循环“内部”或“外部”。在上面的例子中,所有缩进的代码都在循环内部,这是你希望为列表中的每个项目执行的代码。没有缩进的代码则在循环外部。
缩进错误示例

缩进错误可能导致程序无法运行,或者更隐蔽地,导致程序运行结果与预期不符。让我们通过一些代码示例来看看缩进可能出错的方式。
错误类型一:缺少缩进块
在之前的视频中,你见过类似下面的循环代码:
scores = [96, 85, 91, 78, 93]
a_scores = []
for score in scores:
if score >= 90:
print("A")
a_scores.append(score)
这段代码遍历每个分数,检查是否为A(>=90分),如果是,则执行两件事:打印“A”并将该分数添加到 a_scores 列表中。
现在,想象一下 if 语句没有正确缩进,如下所示:
for score in scores:
if score >= 90: # 错误:这行应该缩进
print("A")
a_scores.append(score)
会发生什么?
你会得到一个错误:IndentationError: expected an indented block。这是因为Python看到了冒号 :,它期望你提供属于这个 for 循环内部的代码。从技术上讲,现在这行代码在循环外部。
错误类型二:条件语句内部缺少缩进
如果 print 行没有缩进呢?
for score in scores:
if score >= 90:
print("A") # 错误:这行应该缩进
a_scores.append(score)
同样,你会得到一个缩进错误:IndentationError: expected an indented block。因为Python看到 if 语句后的冒号,期望你提供当条件为真时要执行的代码。
隐蔽的“静默错误”
有时,你的代码能运行,不会抛出错误,但做的事情却是错的。这被称为“静默错误”。
以下是一个正确工作的代码示例:
scores = [96, 85, 91, 78, 93]
a_scores = []
for score in scores:
if score >= 90:
print("A")
a_scores.append(score)
print(a_scores)
运行后,你期望看到什么?
我们有5个分数,但只有3个是A。所以应该打印三次“A”,并且 a_scores 列表应该包含 [96, 91, 93]。结果确实如此。
现在,如果 append 这行代码没有正确缩进,会发生什么?
scores = [96, 85, 91, 78, 93]
a_scores = []
for score in scores:
if score >= 90:
print("A")
a_scores.append(score) # 注意:这行现在只在for循环内,不在if语句内
print(a_scores)
结果:
代码没有报错。“A”打印了三次,这正确。但所有分数都被添加到了 a_scores 列表中,而不仅仅是三个A。输出会是 [96, 85, 91, 78, 93]。
原因:
a_scores.append(score) 这行代码不再位于 if 语句内部。它只在 for 循环内部。因此,print(“A”) 这行只会在分数>=90时执行,但 append 这行会对每一个分数都执行。
更极端的错误
如果这行代码完全缩进到最左边呢?
scores = [96, 85, 91, 78, 93]
a_scores = []
for score in scores:
if score >= 90:
print("A")
a_scores.append(score) # 注意:这行现在完全在循环外部
print(a_scores)
结果:
代码再次运行,但工作不正常。append 这行现在完全不在循环内部。因此,无论 score 的最后一个值是什么(在这个例子中是93),它都会被添加到列表中。循环结束后,列表 a_scores 只包含 [93]。

如何调试缩进问题

如果你需要关于缩进的第二意见,不要害怕向你的LLM(大语言模型)求助。
你可以这样说:
“我写了这段代码,目的是将所有高于A阈值的分数添加到列表
a_scores中。然而,它只添加了值86。为什么?”
然后粘贴你的代码。
LLM可能会指出:
“代码的问题与
a_scores.append(score)这行的缩进有关。因为这行在if语句外部,它只在循环结束后追加了分数列表中的最后一个分数。”
然后它会提供一个修正方案。你可以复制粘贴这个代码块,看看是否纠正了你的问题。
除了求助LLM,使用 print 语句也是调试的好方法。通过在关键位置打印变量的值,你可以观察程序的实际执行流程。
本节总结
本节课中我们一起学习了Python的缩进规则:
- 缩进是语法:条件语句和循环都需要包含一个缩进的代码块。这个代码块位于冒号
:之后,如果你不包含它,Python会抛出错误。 - 缩进定义范围:缩进用于划定当条件为真时或在循环内要执行的代码。
- 警惕静默错误:有时缩进会导致静默错误。即你的代码能运行,不会用红色的错误框警告你,但它没有正常工作或没有做你期望它做的事。
- 学会调试:你可以尝试用LLM调试,或使用
print语句来帮助你找到错误。请记住,并非所有错误都会停止你的程序,代码可以运行但仍然做错事。

现在你对缩进更加熟悉了,可以扩展你在代码中创建分支路径的能力。到目前为止,你已经学会了如何创建两条路径(if/else),但在Python中,你可以创建三条或更多路径。请跟随下一节视频学习如何实现。
021:elif 🧩
概述
在本节课中,我们将学习如何结合循环和条件语句,为餐厅食品安全评分分配等级。核心内容是使用elif创建多分支代码结构,实现更复杂的逻辑判断。

回顾与引入
上一节我们介绍了使用if-else进行简单的二分支判断。本节中,我们来看看如何创建两个以上的分支路径。
在之前的视频中,我们编写了检查每个餐厅评分并分配等级的代码。以下是当时的代码状态:
if score >= 90:
print("A")
else:
print("Less than A")
这段代码打印出评分是“A”还是“低于A”。目前,代码只有两个分支:A或低于A。
为了分配B和C等级,我们需要创建多于两个的分支路径。

使用elif添加新分支
你可以使用elif来添加新的分支。elif代表“else if”,其含义是“为我检查另一个条件”。
如果评分大于或等于B级分数线,我们希望打印“B”。以下是修改后的代码结构:
if score >= 90:
print("A")
elif score >= 80:
print("B")
else:
print("Less than B")
这三个分支为代码执行提供了独特的路径。对于每个评分,代码只能选择其中一条路径执行。
你可以将它们想象成一个渐进式过滤器:
- 任何大于等于90的评分,会进入第一个分支并打印“A”。
elif会检查另一个条件:评分是否大于等于80。如果是,则打印“B”。- 现在,
else成为了捕获所有低于B评分的“兜底”分支。

运行此代码,你将得到A、A、低于B、A和B等输出。
添加更多分支
你可以根据需要添加任意数量的elif语句,直到创建出代码所需的所有分支。
例如,我们可以再添加一个elif来检查C级:
if score >= 90:
print("A")
elif score >= 80:
print("B")
elif score >= 70:
print("C")
else:
print("Failed")
现在,你需要将else语句的含义改为“未通过”:如果你没有得到A、B或C,那就是未通过。
运行该代码后,你的数据中也会出现C等级。
在循环中进行数据操作
现在你已经在循环内创建了不同的分支,可以进行一些很酷的操作。
例如,假设你正在处理之前用辅助函数创建的完整数据集,你可能想创建一个包含所有餐厅分配等级的新列表。
你可以创建一个新的空列表grades,并在循环内部为每个评分追加新分配的等级。
所以,与其print("A"),不如写成grades.append("A")。
如何完成这段代码的修改?你只需在每个条件分支内追加相应的等级即可:B、C和Failed。
最后一个问题:假设这个循环运行完毕,之后你打印grades列表的长度。你预计这个列表有多长?
它应该与scores列表的长度相同,大约67,000条。你应该检查一下数据,确认你的代码是否正常工作。请记住,代码能运行并不代表它正确无误。
验证代码结果

你可以尝试询问你的大语言模型来协助验证。这里有一个提示词示例:
“请为我编写代码,打印出列表
scores和列表grades的前10项。”
运行该代码,你可以检查数据。如果结果显示第一个等级是B,其余都是A(且评分都在90分以上),那么看起来是正确的。这也符合你的直觉,因为之前你已经看到大约95%的评分都是A。
用流程图巩固理解
让我们用流程图来模拟你刚刚编写的分支代码,以巩固所学知识。
- 第一个
if语句检查评分是否大于等于A级标准(90分)。如果为真,则代码将“A”追加到等级列表中。 - 如果为假,则代码沿此路径向下,检查第二个
elif语句的真假。 - 如果为真,则代码追加“B”。
- 如果该语句为假,则代码进入下一个
elif,检查是否追加“C”。 - 如果最后的条件也为假,则进入
else代码块,追加“Failed”。
这段代码为每个评分创建了四种可能的分支路径。对于列表scores中的每个评分,代码将选择这四条路径中的一条执行。
请记住,所有这些都发生在for循环内部。因此,对于列表中的每个评分,都会执行一次这条决策链。如果有5个条目,这个决策链就发生5次。如果有60,000个条目,它就发生60,000次。

核心模式总结
你可以根据需要创建任意多的分支。你总是有一个if语句,以及一个可选的else语句。如果你需要两个以上的分支,可以在中间添加elif语句:1个elif,2个elif,或任意多个。
你也可以只有if和elif语句,这是一种在末尾不需要“兜底”分支时可以使用的模式。
请注意评分条件中递减的模式。这种模式利用了if语句的顺序特性。每个条件都只在前一个条件为假时才被应用。这样,你就避免了为每个等级同时检查评分的高边界和低边界。
总结

本节课中,我们一起学习了如何使用elif创建多分支代码。我们掌握了如何将循环与复杂的条件判断结合,为数据分配多个类别,并通过创建新列表来存储结果。我们还探讨了验证代码正确性的方法,并用流程图可视化了多分支逻辑的执行过程。
在下一个视频中,你将学习本模块的最后一个关键概念:如何同时遍历多个列表。我们下节课见。
022:使用range函数进行循环 🔄
在本节课中,我们将学习如何使用 range 函数和索引来同时遍历多个列表。这种方法在处理相关联的多列数据时非常有用。
概述
你已经见过如何编写循环来遍历单个列表。然而,for 循环非常灵活。在查看代码之前,我们先了解一下如何同时遍历多个列表。
回想一下,你可以使用索引来访问列表中的元素。例如,scores[0] 访问第一个元素,scores[100] 访问第101个元素,依此类推。
这里的核心思想是,你不仅可以像 for score in scores: 这样遍历单个列表,还可以通过获取一个数字列表来遍历数字,并用每个数字同时访问多个列表。这种策略允许你同时访问多个列表中相同位置的元素。
问题场景:找出不合格的餐厅


假设你需要创建一个所有未通过检查的餐厅名单。这个名单可能很短,因为95%的餐厅都获得了A级评分。
首先,从餐厅数据中获取两个列表:scores(分数)和 names(名称)。你已经见过 scores 列表的样子。如果你打印 names 列表的前10个值,会得到一系列不同餐厅的名称。
现在你有了数据中的两列。这个问题的挑战在于,你需要遍历 scores 列表,但要根据分数保存对应的餐厅名称,而不是分数本身。
如果你从 for score in scores: 这样的循环开始,在循环内部你只能访问分数,无法访问名称。让我们来规划一下:
- 你可以判断
if score < 70,这是一个不合格的分数。 - 然后你想将餐厅名称添加到一个失败餐厅的列表中。
因此,在顶部创建一个空列表:failed_restaurants = []。但问题在于,在循环的任何时刻,你如何知道正在处理的是哪家餐厅?这种循环结构无法解决这个问题。
解决方案:使用索引同时遍历
不过,你还有另一个选择。你可能记得这段代码,它有一个简短的名称和分数列表,并通过索引(即元素在列表中的位置)来访问这两个值。
names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]
print(names[0], scores[0]) # 输出: Alice 85
所以,如果你能遍历一个数字列表,就可以使用相同的数字来同时访问 names 和 scores 列表。这听起来有点抽象,让我们来写代码。
认识 range 函数
我们将要这样做:for i in range(10):(这里 i 代表索引)。然后 print(i)。
for i in range(10):
print(i)
# 输出: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
这里的新内容是 range 函数。range 本质上会创建一个数字列表,默认从0开始,直到(但不包括)你输入的这个值。在这个例子中,就是0到9。这些数字将是循环中 i 所取的不同值。
这些数字正好与一个长度为10的列表的索引相同。你的列表索引从0开始,一直到9。
同时遍历两个列表
因此,要同时遍历这两个列表,你可以这样做:
for i in range(len(scores)):(使用 len(scores) 获取列表长度,两个列表都可以,因为它们长度相同)。
range 函数会创建一个从0到67,573的范围(假设 scores 列表长度为67,574)。这些就是你访问列表所需的所有索引。

现在,你可以在循环内部使用相同的索引 i 来同时访问 scores 和 names。这样你就可以同步遍历两个列表,同时访问 scores[i] 和 names[i]。如果你访问第10个分数,你也在访问第10个餐厅名称。
于是,你可以这样写:
failed_restaurants = []
for i in range(len(scores)):
if scores[i] < 70: # 如果分数不合格
failed_restaurants.append(names[i]) # 将对应的名称添加到列表
循环结束后,你可以打印 failed_restaurants 来查看结果。运行速度会非常快,你将得到一个分数低于70的餐厅名称列表。
本节总结
在本视频中,你学习了两个新概念:range 函数和使用索引遍历列表。
range函数:本质上创建一个你可以遍历的数字列表,默认从0开始,直到(但不包括)你指定的数字。- 常见模式:你会经常看到
for i in range(len(scores)):这样的模式,用于遍历列表中的所有索引(本例中是分数列表)。 - 索引访问:一旦你用
for i in range(len(scores)):创建了循环,就可以使用i来访问列表中的每个元素,如scores[i]。 - 处理多列表:如果你有两个对应的列表,可以用相同的索引访问对应的元素,如
scores[i]和names[i]。
所以,总结一下:
- 如果你只需要访问单个列表,可以使用之前学过的
for score in scores:代码。 - 如果你需要更大的灵活性,或者需要访问多个列表,可以使用本课学习的基于索引的循环。
你在处理多列数据方面做得很好!在下一个模块中,你将学习更多细节。

现在,请跟随我进入本课的最后一个视频,我们将深入探讨代码的执行顺序。我们那里见。
023:Python数据分析 - 执行顺序 🧭
在本节课中,我们将要学习程序执行顺序的概念。执行顺序是指程序运行代码行的先后序列。理解这一点对于调试代码和预测程序行为至关重要。
什么是执行顺序?
执行顺序是你的程序逐行运行代码的序列。
你已经了解了控制流如何允许你重复代码或选择不同的执行分支。现在,让我们通过一个例子来追踪代码的执行过程。

代码追踪示例
以下是一段统计数据中A、B、C等级数量的代码。在调试时,逐行跟踪代码会很有帮助。
以下是你可以采用的方法。让我们在遍历列表前五个值时,跟踪每个变量的值。请特别注意控制结构。
首先,你需要明确在代码运行过程中,哪些变量的值你预期会保持不变。

变量 A、B、C 和 scores 将保持不变。因为分数线是常量,并且你不会对列表进行追加或其他操作。
与此同时,变量 num_A、num_B 和 num_C 会随着分数统计而改变。变量 score 的值也会随着循环运行而改变。
因此,你可以观察每个计数器和 score 在循环中的值变化。
逐步执行分析
在第一个循环周期或迭代中,score 获得值 96。
然后,计算机检查 score 是否大于或等于 A(A 的值为 90)。由于 96 大于 90,条件为真。
因此,计算机将执行下一行代码,将变量 num_A 的值加 1。现在 num_A 等于 1。
接着,计算机跳过后续的 elif 和 else 代码块,并返回到循环的第一行。
在下一个迭代中,score 获得值 91。计算机首先检查该值是否大于或等于 A(90)。由于表达式为真,它执行下一行,将变量 num_A 加 1。现在 num_A 等于 2。
elif 和 else 代码块被跳过,循环返回顶部。
在下一个迭代中,score 的值为 79。计算机首先检查 score 是否大于或等于 A(90),但该表达式为假。因此,下一行代码被跳过。
然后,计算机检查下一个条件:elif score >= B。由于 B 是 80,这个表达式也为假。所以计算机跳过下一行,移动到下一个 elif 代码块。
这个条件(elif score >= C)为真。因此,计算机执行 elif 下的代码行,将 num_C 加 1。现在 num_C 等于 1。
循环然后返回顶部。现在 score 的值为 93。第一个条件为真,因此计算机执行下一行,将 num_A 加 1。现在 num_A 等于 3。
循环返回顶部。最后,score 获得值 86。第一个条件为假,因为 86 不大于等于 90。下一行被跳过。
然后计算机检查 elif 条件:score 是否大于等于 80,该条件为真。
因此,执行第一个 elif 下的代码行,将 num_B 加 1。现在 num_B 等于 1。
循环继续这个过程,直到到达列表的末尾。然后,计算机可以继续执行下一行代码,这涉及到计算列表的长度。
核心模式总结
干得好,你刚刚构建了一个常见的编码模式:统计列表中不同类型项目的数量。


这与你可能在电子表格中使用的 SUMIF 操作类似。
课程总结
在本节课中,我们一起学习了Python计算机编程所需的核心技能:数据类型、变量、条件语句和循环。
你仅在一个模块中就涵盖了大量内容。接下来的作业和评分实验将让你尝试应用这些知识。请跟随我进入下一个视频,了解如何完成你的第一个评分实验。
024:你的首次分级实验 📝
在本节课中,我们将学习如何完成本课程的第一次分级Python实验。你将分析一个真实世界的数据集来测试你的Python技能。课程中的所有实验都是自动评分的,这意味着我们会将你的代码输出与正确答案进行比对。

实验环境与规则
上一节我们介绍了实验的目标,本节中我们来看看实验的具体环境和需要遵守的规则。
实验在Coursera平台上的Jupyter Lab环境中进行,其界面与你在此模块视频中看到的相同,但顶部多了一些Coursera选项。
以下是完成实验时需要注意的几个关键点:
- 使用提供的变量名:例如,你不应更改变量名
num_observations,因为自动评分器将无法识别它。 - 替换
None占位符:代码中出现的None仅作为占位符。如果你看到None,那就表示你需要在那里添加自己的代码。 - 仅修改指定单元格:你只需要修改包含
# GRADED CELL注释的单元格。 - 可以添加新单元格:你可以添加新的单元格进行实验,但只有被标记为分级的单元格才会被评估。
实验界面详解
了解了基本规则后,我们来看看实验界面的具体功能。

在界面顶部,有几个重要的按钮:
- Coursera Coach:点击此按钮可以与一个大型语言模型(LLM)聊天,无论是提问还是寻求帮助解决错误信息。
- Grades:查看你的成绩。
- Submit Assignment:提交作业。
例如,如果你问“如何在Python中定义一个新变量?”,教练会给出包含示例的回复。聊天记录会被保存,方便你后续查阅。

为了获得更多工作空间,你可以点击左侧的文件浏览器按钮将其隐藏。

如何完成与提交
现在,让我们具体看看如何填写答案并提交作业。
在每个练习中,你会看到标有 # GRADED CELL 的注释,这意味着你需要填写该单元格。你的代码必须写在 # YOUR CODE HERE 和 ### END CODE HERE 这两行注释之间。
代码示例:
# GRADED CELL
# YOUR CODE HERE
result = calculate_total(data) # 替换此处的 None
### END CODE HERE
如果你将代码写在这些注释之外,自动评分器将无法识别。
完成所有分级单元格后,即可提交。点击右上角的 Submit Assignment 按钮,你可能需要在提交前确认荣誉准则。提交后,评分可能需要几分钟。你可以通过 Grades 选项卡查看结果。
查看成绩与反馈
提交后,你将获得详细的成绩反馈,这有助于你改进。


成绩页面会显示:
- 你是否通过了该练习。
- 你获得的分数以及通过所需分数(通常是70%或更高)。
- 你的代码运行后的输出,这为你提供了改进的反馈。
你可以根据需要多次重新提交。重要提示:在关闭窗口前,请务必点击 Save 按钮,否则你将丢失进度。
课程资源与准备
在开始实验前,请善用课程提供的学习资源。
本课程的下一个项目是 Python速查表,它包含了你在本课程中学到的所有概念的便捷参考。你可以结合Coursera Coach来帮助你完成作业。在本课程的每个分级实验之前,你都会获得一份更新版的速查表,其中包含你在每个模块中学到的新概念。


准备好开始你的第一次实验了吗?你将使用一家本地商店的数据来计算不同类型产品的销售额。完成实验后,我们将在下一个模块中一起探索如何在代码中处理整个电子表格。
本节课总结:我们一起学习了如何在本课程的Jupyter Lab环境中完成并提交第一次分级Python实验,了解了自动评分的规则、界面功能、代码填写规范以及如何查看成绩和利用学习资源。现在,你可以自信地开始你的数据分析实践了。到目前为止做得很好,我们下一个模块见!
025:数据结构和描述性统计 📊
在本课程中,我们将学习如何使用Python的Pandas库来组织、分析数据,并从数据中提取有意义的见解。我们将探索核心的数据结构,学习排序、筛选以及计算描述性统计量的方法,最终能够将庞大的数据集转化为可操作的洞察。

欢迎来到模块2:数据结构和描述性统计

在本模块中,你将学习如何使用一个名为Pandas的强大Python库来组织、分析数据,并从中提取有意义的见解。
你将学习如何使用核心的数据结构,包括数据框(DataFrame)和序列(Series),这些结构能让你高效地处理大型数据集。
在整个模块中,你将使用一个关于编码习惯的真实调查问卷数据集。
第一课:探索数据结构
上一节我们介绍了本模块的目标,本节中我们来看看具体的学习内容。在第一课中,我们将探索列表之外的数据结构,学习数据框如何像电子表格一样存储和组织复杂数据,但具备更强大的分析能力。
以下是本课你将学习的具体技能:
- 学习如何读取数据。
- 学习如何绘制直方图。
- 学习如何计算数据的计数和总和。
第二课:排序与筛选
掌握了基本的数据操作后,我们需要学习如何聚焦于关键信息。第二课的重点是排序和筛选,这些关键技能能让你精确找到所需的信息。
以下是本课你将学习的具体技能:
- 学习如何以有意义的方式对数据进行排序。
- 学习如何筛选数据以精确查找目标内容。
第三课:计算描述性统计与可视化
在能够有效组织和筛选数据之后,我们将深入分析数据本身。在最后一课中,你将学习如何使用Pandas计算描述性统计量,从集中趋势的度量到特征间的相关性及数据分割。
你还会创建可视化图表来有效地传达你的发现。
以下是本课你将学习创建的可视化图表:
- 条形图
- 散点图


总结
在本节课中,我们一起学习了如何利用Python和Pandas库处理数据。到本模块结束时,你将能够使用Python将海量数据集转化为可操作的洞察。
请跟随我进入第一课,开始探索这些强大的数据结构。
026:Python数据分析进阶列表操作 📊

在本节课中,我们将要学习列表在数据分析中的局限性,并了解为什么需要其他数据结构来处理更复杂的数据场景。我们将探讨列表的维度限制、类型灵活性以及在大规模数据下的效率问题,并简要介绍向量化的概念。
列表的回顾与数据存储的重要性
在之前的模块中,我们广泛使用了列表来按顺序存储数据。

事实证明,在编程时存储信息的方式非常重要。在Python中,你可以使用不同的结构在代码中存储数据。数据结构只是数据如何排列和组织的一个专业术语,而列表只是其中一种类型的数据结构。
列表的局限性
上一节我们介绍了列表的基本用途,本节中我们来看看列表在数据分析中的几个关键限制。在之前的模块中,你处理了28年的图书馆数据或大约600万条餐厅评分。列表帮助你执行快速分析,并且你暂时不需要扩展到数百万行。当你有一个项目集合并且需要通过对这些项目进行存储来对它们采取行动时,列表非常有用,这使得采取行动变得更加方便。
然而,列表有几个关键的限制。具体来说,它们是一维的、过于灵活,并且在大规模时效率低下。一旦你理解了这些限制,你就会更从容地从其他可用的数据结构中进行选择。
维度限制
关于维度,列表本质上只能存储一列数据。假设你有一个餐厅评分列表,你想回答诸如“Melrose Shrimp得了多少分”这样的问题。你缺少一些关键信息。你能看出是什么吗?那就是餐厅名称。
对于某些应用,仅有一个分数列表是有用的,例如计算平均餐厅分数。但大多数时候,你将处理二维数据,即具有行和列的数据。
你在上一个模块中看到了解决此维度约束的一种变通方法,即维护两个独立但相关的列表,如names和scores。然而,这种方法很笨拙,因为没有固有的行和列组织,只有两个独立的列表。其他数据结构是二维的,允许你将多列数据存储在一起,就像在电子表格中一样。
类型灵活性限制
列表也非常灵活。例如,Python中的列表实际上可以存储多种数据类型。以下列表完全有效:

my_list = [1, 2, "hello", 4.5]
但是,当你运行这行代码来对值求和时,你认为会发生什么?

它会抛出一个错误。这是因为Python没有内置的方法让你将整数和字符串类型相加。就Python而言,你的列表可能只包含数字和字符串的混合,因此它不支持混合数字和非数字类型的操作。
这种灵活性在某些应用中是理想的,但在数据分析中,它会阻碍你的分析。数据中的每一列应包含一种类型的数据,例如全部是整数或全部是字符串。你希望选择一种数据结构,以防止意外地将多种类型引入一列。
大规模效率限制
列表对于非常大的数据集(即大规模数据)也会引入低效率。例如,在之前的模块中,你使用for循环为列表中的每个项目运行代码。这个解决方案非常有效,并且for循环是Python编程中非常常见的工具。
然而,它们不是最高效的扩展选项。当这个for循环运行时,它基本上按顺序逐步执行每个操作,依次为每个分数运行缩进的代码。想象一条分数的传送带一个接一个地从你面前经过,你的工作是依次为每个分数盖章,如果它是A的话。


然而,一些用于数据分析的专用数据结构使这种类型的操作更加高效。你将在接下来的几个视频中遇到其中两个:数据帧(DataFrame) 和 序列(Series)。
你可以对整个数据结构一次性执行相同的操作,而不是单独对数据结构中的每个项目进行操作。如果你想象分数的传送带在这个例子中经过,你有一个非常宽的印章,如果需要,可以一次性盖住所有五个分数。
在第一个例子中,如果每个任务需要一秒钟,for循环代码将需要五秒钟,而更高效的代码只需要一秒钟。当然,这其中有更多的复杂性,但在大规模处理非常大的数据集时,这种效率会显著累积。
这种对整个数据结构一次性执行操作的过程称为向量化(Vectorization)。不要太担心这个术语,你不需要编写向量化代码,它是你将使用的数据结构的内置功能。
总结与展望
所以,虽然列表非常有用,但它们并不是唯一的数据结构。


本节课中我们一起学习了列表在数据分析中的三个主要局限性:一维性、类型过于灵活以及大规模处理时的效率问题。我们还了解了向量化的概念,它允许对整个数据集进行高效操作。
在下一节视频中,我们将开始学习如何从笔记本外部的文件导入代码,这将允许你使用由他人开发的数据结构。我们下节课见。
027:Python数据分析(第3课)|模块导入 📦
概述
在本节课中,我们将要学习如何在Python中导入模块。模块是包含已编写好的Python代码的文件,通过导入模块,我们可以复用自己或他人编写的代码,从而提升开发效率。我们将介绍几种不同的导入方式,并通过具体示例演示其用法。
模块导入的基本概念
当你在Notebook中工作时,你当然可以访问该Notebook内的所有代码。

但你也可以通过从其他文件引入代码来增强你的程序。
这些文件可以是你自己编写的,也可以是他人编写的。除了你已编写的代码,你还可以自动访问许多内置函数,例如 sum 和 len。


你也可以借用其他程序员的代码,包括你自己以前编写的代码,这需要使用 import 命令。

导入模块的实践示例
假设你仍在处理上一个模块中的餐厅评分数据,并且你想创建一个列表,包含所有不同餐厅获得的唯一评分。
在上一个模块中,你看到了这两行代码,它们将餐厅数据的评分列加载到一个名为 scores 的列表变量中。
from helper_functions import get_restaurant_list
scores = get_restaurant_list('restaurant_scores.csv', 'score')
在第一行中,你从名为 helper_functions 的模块中导入了 get_restaurant_list 函数。
这是如何工作的?helper_functions 在哪里?
首先,在这个Notebook所在的同一文件夹中,有另一个名为 helper_functions.py 的文件。
它是一个Python文件,包含一些有用的函数。以下是这些函数的样子:
# helper_functions.py 文件内容
def get_restaurant_list(filename, column_name):
# ... 函数实现细节 ...
pass
def print_pythons():
print("🐍🐍🐍")
这是 helper_functions.py 文件的全部内容。现在不必过于担心这段代码,你只是要借用这个函数在你的Notebook中使用。
你可以直接将所有这些代码复制并粘贴到你的Notebook中。然而,如果你想借用大量代码,或者无法轻松访问该文件,这样做可能会很笨拙。
相反,你可以导入这段代码。在这个 import 命令之后,你就可以访问 get_restaurant_list 这个函数了。
你可以调用那个函数。这是从你自己那里借用代码的好方法。
你在另一个文件中有一些代码,并且你想在这个文件中使用它。
Python中的不同导入方式
Python中有几种不同的导入选项。
1. 导入特定函数

from module import function 这个选项允许你选择想要导入的函数。
from helper_functions import get_restaurant_list

2. 导入整个模块
你也可以通过使用 import helper_functions 来导入此模块中的所有函数。

所以,使用 import module。
现在,你可以尝试使用文件中的其他函数,比如 print_pythons。

嘿,这个错误是什么?print_pythons 未定义。
让我们用LLM(大语言模型)来检查如何修复这个问题。假设我正在尝试使用 helper_functions.py 中的 print_pythons 函数。为什么会出现这个错误?
看起来,你需要引用模块名称才能访问其函数。它给出了你可以复制并粘贴回单元格中运行的正确代码。
你可以看到,它通过引用模块名称来调用函数。
import helper_functions
helper_functions.print_pythons()
好的,非常可爱的Python(🐍)。每次你想打印Python时都必须写这么长的 helper_functions 部分,这有点烦人。

使用别名简化代码
你可以使用 as 给这个模块起一个昵称。
import helper_functions as hf
现在你可以说 hf.print_pythons(),这样就完成了。这个昵称只是让你的代码更短。

核心概念总结
模块是一个包含已编写好的Python代码的文件。
你刚刚看到了两种在Notebook中导入模块的方法:
-
导入特定函数:使用类似
from helper_functions import get_restaurant_list的代码行。然后你就可以直接在代码中使用get_restaurant_list。- 通用命令格式:
from module import function_name
- 通用命令格式:
-
导入整个模块:如果你想导入模块中的所有函数,而不是列出特定的函数,可以使用
import helper_functions这样的命令。这个命令允许你借用helper_functions.py中包含的所有函数。- 如果你使用这种风格的命令,调用特定函数时也必须使用模块名称,例如
helper_functions.get_restaurant_list()。 - 你也可以使用
as给模块起一个昵称,这样可以节省一些输入。例如,你可以使用import helper_functions as hf来给helper_functions一个更短的昵称。
- 如果你使用这种风格的命令,调用特定函数时也必须使用模块名称,例如

扩展与过渡

你可以从计算机上的另一个文件导入代码,也可以从互联网、其他程序员编写的代码中导入。
在下一节中,我们将看看如何导入 pandas 模块,它为数据分析提供了强大的数据结构。请跟随我到下一个视频学习。
总结
本节课中,我们一起学习了Python模块导入的核心知识。我们了解了模块是什么,掌握了使用 from ... import ... 导入特定函数和使用 import ... 导入整个模块的方法,并学会了使用 as 关键字为模块设置别名以简化代码。理解这些导入方式是有效复用代码、构建复杂程序的基础。
028:Pandas库应用 🐼
在本节课中,我们将要学习Python数据分析中一个极其重要的库——Pandas。我们将了解Pandas是什么,它为何如此重要,以及如何利用它来高效地处理和分析数据。
全球有数百万的Python程序员,你就是其中之一。

事实证明,你可以借用其他程序员发布的代码。
对于数据分析而言,最重要的模块之一,你将借用的,就是名为Pandas的模块。作为一名数据分析师,你很可能会每天使用Pandas模块。

Pandas最初于2008年编写,是一个非常流行的数据科学模块,它提供了强大的数据结构和功能。
它提供的两个基础数据结构是:DataFrame(存储表格数据)和Series(类似于列表的增强版)。
Pandas允许你高效地操作、清理和分析大型数据集。
它提供了多种函数,可以轻松处理缺失数据、排序、筛选和数据透视,合并或连接数据集,对数据进行分组和聚合,以及执行时间序列分析。
它还支持从各种文件格式(如CSV、Excel甚至数据库)中导入数据。
遗憾的是,Pandas这个名字与现实世界中可爱、毛茸茸的动物“熊猫”无关。但这里有一张熊猫的图片来弥补这个事实。
回想之前,你曾尝试使用餐厅数据创建一个唯一的卫生评分列表。你可以使用Pandas来完成这个任务。
Pandas并非由你或你认识的人编写。这是Python社区中其他人编写的一大堆代码,实际上有数十万行。

你通常会看到Pandas以 import pandas as pd 的方式导入,并给它一个昵称 pd。

现在Pandas已经导入,你可以使用所有这些强大的代码了。举一个简单的例子(在接下来的视频中你会探索更多),你可以使用 pd.unique() 函数来获取一个唯一值的列表。
这完全类似于电子表格中的 UNIQUE 函数。试想一下,如果你必须从头开始编写这段代码,这个操作会有多复杂。它可能需要循环和一两个条件判断,而且那可能还不是寻找这些唯一值的最佳或最快方法。
因此,从Pandas库中借用这个 unique 函数,就像从朋友那里借用一件电动工具。你以零成本获得了一种超能力。

Pandas有很多很酷的函数。要开始使用,你很可能需要从CSV文件中读取你的数据。
请跟随我到下一个视频,看看具体如何操作。

本节课中,我们一起学习了Pandas库的基础知识。我们了解到Pandas是数据分析的核心工具,它提供了DataFrame和Series两种强大的数据结构,以及一系列高效的数据处理功能。通过导入Pandas并利用其现成的函数(如 pd.unique()),我们可以极大地简化数据分析任务,无需重复造轮子。下一节,我们将学习如何使用Pandas读取数据文件。
029:将CSV数据读入Python 📊

在本节课中,我们将学习如何使用Python的pandas库来读取和分析CSV格式的数据文件。我们将通过一个关于新程序员调查数据的实际案例,演示从获取数据到将其加载到Python环境中的完整流程。
测试Pandas:分析新程序员数据
上一节我们介绍了数据分析的基本概念,本节中我们来看看如何将实际数据加载到Python中进行分析。
假设你在一家为新手程序员提供教育产品的公司工作。你被要求调查全球程序员的特点,以辅助市场营销工作。这项计划的目标是创建一份关于新程序员特征的报告。你的团队对人口统计数据感兴趣,并希望在报告中包含描述性统计和可视化图表。
你在网上找到了一些关于新程序员的调查数据。你需要将这些数据加载到Python中,进行探索,并描述其不同特征,从而得出关于什么样的人开始学习编程的结论。
你对这些数据一无所知,所以第一步是查看数据来源。
检查数据来源
这是公开可用的数据,存储在Github上。Github是一个用于共享代码的网站。不必过于担心Github的具体细节,你只是在调查数据本身。
这些数据由freeCodeCamp和CodeNewbie于2016年收集。数据本身位于“clean_data”目录中。进入该目录,你会发现这里唯一的CSV文件就是新程序员调查数据。

点击这个文件,你可以直接使用下载按钮来下载它。


你还可以在“raw_data”文件夹中看到调查的问题,例如“你是否已经是一名软件开发者?”、“你每周花多少小时学习?”等等。
准备数据文件
下载文件后,你会发现它有一个很长的文件名。你可以将文件重命名为更短的名称,例如“survey_data.csv”。
现在,如何将这个文件导入到你的代码中呢?在本课程的实验环节,这一步已经为你完成,但你需要了解其工作原理。

你需要确保“survey_data.csv”文件与你的Jupyter笔记本文件位于同一个文件夹中。在这个演示中,文件需要被上传到Coursera的Jupyter Lab环境中,并且与笔记本在同一文件夹。
请注意,在本演示中,你将看到原始数据集的修改版本,它包含了原始特征的一个子集,并且列名更短。
将CSV文件读入Python
因为这两个文件在同一个文件夹中,你可以仅使用文件名来访问CSV文件。
首先,导入pandas库,通常缩写为pd。习惯上,将所有导入语句放在代码的顶部。

import pandas as pd
然后,你将使用pd.read_csv()函数,并将文件名‘survey_data.csv’作为唯一的参数传入。注意,文件名是一个字符串。
df = pd.read_csv('survey_data.csv')
将此函数的结果存储在一个变量中,我们称它为df。df是“dataframe”的常用缩写。
这个数据的类型是什么?让我们使用Python的type()函数来查看。
type(df)
df的类型是pandas的DataFrame。DataFrame类似于Python版本的电子表格。
初步查看数据
加载数据后,你的第一步应该是查看它。例如,你可以直接输入df并按Shift+Enter来查看你的DataFrame。
每一行代表一个人提交的调查问卷,每一列代表该调查中的一个问题。查看输出的底部,有超过15000份调查回复,你正在处理16个特征。
你可能还会注意到,其中一些回复有NaN,代表“Not a Number”(非数字)。这些单元格是空的,没有信息。另外,DataFrame的索引从0开始,就像列表一样。
顺便说一下,你也可以使用print(df),但得到的输出格式不如Jupyter笔记本默认的DataFrame显示方式美观。
构想研究问题
你可能已经在思考一些研究问题了。例如:
- 这份调查中年龄的分布是怎样的?
- 人们在学习编程上花了多少钱?
- 他们编程了多少个月?(这个列可以帮助你判断这是否真的是针对初学者的调查。)
你可能还对数据中特征之间的关系感到好奇。例如:
- 每周学习编码的小时数与个人收入之间有什么关系?
- 个人收入与编程月数之间有什么关系?也许编程时间越长,收入越高。
这里有很多值得探索的内容。
快速回顾:使用Pandas读取CSV数据
你的目标是将一些CSV数据加载到笔记本中,以便用Python进行分析。
以下是需要遵循的步骤:
- 获取文件:知道你正在处理的文件名。最简单的情况是,该文件与你的笔记本位于同一文件夹。在Coursera的实验环节,这一步已为你完成。
- 使用读取函数:使用命令
pd.read_csv(),并给该函数一个参数——文件名(字符串形式),例如‘survey_data.csv’。 - 存储数据:将此函数创建的数据框(DataFrame)赋值给一个变量,以便后续使用。在演示中,变量是
df,这是DataFrame的常用缩写。你也可以使用data、survey_data或其他你认为有意义的名称。
# 完整代码示例
import pandas as pd
df = pd.read_csv('survey_data.csv')
现在你已经加载了数据,可以开始研究你感兴趣的问题了。
请跟随我进入下一个视频,学习如何探索你的DataFrame。
本节课总结

在本节课中,我们一起学习了如何将外部的CSV数据文件读入Python环境。我们了解了查看数据来源、准备文件路径的重要性,并掌握了使用pd.read_csv()函数加载数据到pandas DataFrame的核心操作。最后,我们初步查看了数据,并构想了一些可以基于此数据集进行探索的分析问题。这是进行任何数据分析项目的第一步。
030:Python数据分析(第3课)|数据框基础 📊

在本节课中,我们将要学习Python数据分析的核心工具——数据框(DataFrame)。我们将探索如何查看、总结和理解数据框的基本结构,包括其列名、数据类型以及如何处理缺失值。通过本课,你将掌握初步探索数据框的实用方法。
探索数据框的基本方法 🔍
数据框是Python中用于表示行列数据的主要工具。Pandas库提供了多种选项来探索和总结这类数据。
上一节我们介绍了数据框的基本概念,本节中我们来看看如何开始探索一个数据框。如果你不确定如何开始,可以尝试向大语言模型提问,例如:“在Python中,如何获取数据框的一些基本信息?”
以下是几种探索数据框的实用方法:
df.head():此方法返回数据框的前五行。你也可以传入一个数字参数来指定查看的行数,例如df.head(3)查看前三行。df.sample():此方法随机返回数据框中的一行。与head()类似,你也可以传入数字参数,例如df.sample(5)会随机抽取五行。对数据框进行抽样可以让你看到更多样化的响应,从而更好地了解数据中值的范围。
查看数据框的结构 📐

了解数据的基本结构是分析的第一步。除了查看具体数据行,我们还需要知道数据包含哪些列以及每列的数据类型。
以下是获取数据框结构信息的方法:
df.columns:此命令会简洁地显示所有列的名称。df.dtypes:此命令用于查询数据框中每一列的数据类型。在Python和数据框中,数据类型至关重要,每一列都有指定的数据类型,意味着该列中的每个值都是同一类型。你会看到float64和object等类型。float64本质上是浮点数或小数。df.info():此命令提供了所有列及其类型的摘要信息。你还会看到一个新的信息:非空值计数。这个数字越低,表示该列的缺失数据点越多。例如,如果超过一半的受访者没有分享他们的收入,该列的非空计数就会相对较低。
理解数据框与数据类型 🧩


让我们更仔细地看看数据框在Python中是如何工作的。数据框是一种数据结构,它以行和列的形式存储数据。你可以将数据框想象成多个存储在一起的列表,每个列表代表一列。
你之前看到数据框中的一些列具有 object 类型。object 类型用于存储比简单数字或布尔值更复杂的数据。你可以将这种复杂性类比为选择运输包裹:数字就像标准信封,总是占用相同的空间;但文本则不同,可能需要标准信封,也可能需要大箱子。Pandas使用 object 类型来处理文本,因为它需要这种灵活性来应对任意长度的字符串。目前,当你看到 object 类型时,可以假定该列包含文本。
总结 📝

本节课中我们一起学习了数据框的基础知识。我们掌握了如何使用 head() 和 sample() 初步查看数据,学会了通过 columns、dtypes 和 info() 来了解数据框的结构、列名和数据类型,并理解了 object 类型通常用于存储文本数据。数据框拥有许多高级功能,我们将在本模块的后续课程中继续探索。
031:Python数据分析(第3课)|Python for Data Analytics
课程编号:P31
章节标题:属性与方法 🧩

在本节课中,我们将要学习数据框(DataFrame)的两个核心概念:属性与方法。理解它们的区别对于高效操作和分析数据至关重要。
数据框以行和列的形式存储数据。除了数据本身,数据框还附带一些额外的信息,这些信息分为两类:属性(或称为特征)和方法。属性描述了数据框拥有什么,而方法描述了数据框可以执行什么操作。
在上一节视频中,我们学习了几个不同的命令。你注意到它们之间的区别了吗?
以下是几个命令示例:
df.columns和df.dtypes后面不需要括号。df.info()后面则需要括号。
这些命令之所以不同,是因为 columns 和 dtypes 是属性,而 info 是一个方法。属性描述了数据框具有的特征,例如它的列名。方法则描述了数据框可以执行的动作,例如生成数据摘要。方法本质上就是“函数”的一种更专业的说法,虽然技术上略有不同,但本课程中我们不做严格区分。
像 sum、max 和 len 这样的命令都需要括号,因为它们代表需要执行的动作。以 sum 为例,计算机需要去将所有值相加才能得到结果。而对于 df.dtypes 这类属性,数据框已经存储了这些信息,计算机只需直接获取并展示给你,无需进行计算。
用一个现实世界的类比来理解:思考你如何回答关于自己的不同问题。例如,“你叫什么名字?”或“你多大了?”。你可能不需要思考就能回答,这些是你的属性或特征。但如果我问你:“距离你上次去公园已经过去多少天了?”,我猜你不会把这个答案记在脑子里以备有人提问。你可能需要回想上次是什么时候,然后计算从那以后过去了多少天。这个过程更类似于使用一个方法或函数,你需要进行计算才能得到答案。
计算机在处理数据框时也采用了类似的策略。对于经常访问的基础信息(如列名、数据类型),Python将其存储为属性,以便快速访问。对于更复杂的问题,如生成数据摘要、查找唯一值、求和或生成直方图等,这些都属于方法。计算机需要执行某些动作或计算才能为你提供答案。
因此,总的来说,你需要区分数据框的属性和方法。当你访问一个属性(如 columns 或 dtypes)时,不需要使用括号。当你使用一个方法时,则需要使用括号,并且通常还会向方法传递参数。
幸运的是,属性并不多。你可能会经常用到的属性包括 columns、dtypes,以及其他少数几个,如数据框的维度(行数和列数)。

现在你已经探索了作为数据框的数据,接下来很可能需要将分析范围缩小到少数几列。在下一节视频中,我们将学习如何选择特定的列。
032:列选择 📊
在本节课中,我们将要学习如何在Python中从大型数据集中选择特定的列进行分析。这是数据分析中缩小数据范围、聚焦于特定特征的关键操作。
概述
在数据分析过程中,经常需要从大型数据集中提取出你关心的特定特征(列)来进行分析。在Python中,这个操作被称为“选择”。选择数据的具体部分,如行、列或单个值,都称为选择。你已经见过几次选择操作,例如在列表中使用类似 scores[0] 的代码来选择列表中的第一个项目。从数据框中选择列使用类似的命令。
选择单列
假设在你的分析中,你已经将数据加载到变量 df 中,并查看了列名和一些样本行。现在,你正在处理报告中的“地理分布”部分,想了解受访者在家中使用的不同语言数量。你可能只对“家中语言”这一列感兴趣。

以下是选择“家中语言”列的步骤:

- 从数据框的名称
df开始。 - 使用方括号
[]选择列,就像从列表中选择一样。 - 在方括号内,使用要选择的列名作为字符串。在本例中是
‘language_at_home’。 - 如果想稍后使用结果,将其赋值给一个变量,例如
languages。
对应的代码如下:
languages = df[‘language_at_home’]
运行该代码后,让我们查看一下 languages。它的数据类型是什么?
你可以使用 type() 函数来查看数据类型。languages 是一个 Series。数据框中的每一列都是一个 Series,这是一种一维的、类似列表的数据结构。和数据框一样,你可以使用 .head() 或 .sample() 来查看部分值。languages.head() 会显示前几个值。
使用 len() 函数,你期望 languages 变量的长度是多少?你会得到 15620,这与数据中的回答数量相同。这很合理,每一行对应一个回答。
你还记得如何获取唯一语言的列表吗?你可以使用 pd.unique(languages)。将其存储在一个变量中并打印。看起来确实有很多独特的语言,其中一些是世界上相对小众的语言,这看起来像是一个相当多样化的全球调查。唯一语言列表 l 的长度是 149。
选择多列
你也可以选择多个列。例如,你可能想同时分析“居住国家”和“家中语言”,以查看它们之间的关系。
你将使用与选择单个“家中语言”列类似的命令,但需要使用列名列表,而不是单个列名。
- 创建一个新变量
columns,其中包含你感兴趣的列名(作为字符串)。 columns的类型只是一个列表,其长度为 2。- 要从数据框中选择这两列,使用
df[columns]。 - 将结果赋值给一个变量,例如
country_cols。
对应的代码如下:
columns = [‘country_of_residence’, ‘language_at_home’]
country_cols = df[columns]
运行该单元格。你认为 country_cols 的类型是什么?这是一个 DataFrame。为什么不是 Series?让我们看看 country_cols.head()。现在你有两个维度,两列。每一行都包含国家和家中使用的语言。你也可以对 country_cols 进行抽样,以查看一些不同的回答。看起来有一些来自印度尼西亚、英国和美国的受访者。
常见错误与调试
现在你已经使用数据框一段时间了,你能发现下面这段代码中的错误吗?提示:这是一个拼写错误。
# 错误示例
df[‘country of residence’]
编写这段代码会导致错误。向下滚动查看,这是一个 KeyError。

让我们请大语言模型帮助调试,因为这是一个非常常见的错误,尤其是对于像这样长的列名。你可以询问错误的来源,然后粘贴错误信息。
大语言模型会指出你遇到了一个 KeyError,并告诉你这通常发生在尝试访问数据框中不存在的列时。在本例中,数据框 df 中找不到名为 ‘country of residence’ 的列。然后它会给出一些建议,例如检查拼写错误,确保列名拼写正确。
回到你的代码,你会发现代码中确实有一个拼写错误:‘of’ 中的 ‘o’ 实际上是大写的。所以,这里一个小小的拼写错误就会导致代码中断。
和变量名一样,列名是区分大小写的。

回顾与总结


回顾一下,你可以使用像 df[‘language_at_home’] 这样的代码行来选择单个列,它会返回一个 pandas Series,这是一个包含每个受访者家中语言答案的一维数据结构。然后,你可以将返回的内容保存在一个变量中,如 languages。
你也可以通过将列名保存在一个列表中,然后将该列表放在方括号内来选择多个列。
请记住,列名是区分大小写的,因此需要与数据框中的名称完全匹配。
本节课中我们一起学习了如何从Pandas DataFrame中选择单列和多列,理解了Series和DataFrame在选择操作后的区别,并认识了因列名拼写错误(包括大小写)导致的常见KeyError及其调试方法。

接下来,让我们进入一些计数、排序和可视化操作,为你的报告生成见解。我们下个视频见。😊
033:计数、求和与直方图 📊

在本节课中,我们将要学习数据分析中的核心描述性统计方法:计数、求和以及使用直方图进行数据可视化。这些是理解数据分布和特征的基础工具。

上一节我们介绍了如何加载和初步查看数据。本节中我们来看看如何对数据进行基础的统计分析和可视化。
首先,我们直接选择数据集中的“年龄”列,并将其保存到一个名为 age 的变量中。

age = df['Age']
为了可视化年龄的分布,我们可以使用 .hist() 方法来绘制直方图。运行代码后,我们就能清晰地看到这个特征的分布情况。

从直方图可以看出,大多数受访者的年龄在20到30岁之间,整体分布呈现一定的偏态。
以下是绘制基础直方图的代码:
age.hist()
在下一个模块中,我们将学习如何自定义这些直方图。不过现在,你可以随时向你的大语言模型助手提问,例如:“你能让这个图看起来更美观吗?请只使用 .hist() 方法的参数。” 注意,我们不希望助手导入新的模块。
尝试生成的代码后,图表看起来更好了。请记住,在调查中,受访者可能在某些问题上留空。因此,每一列的空值数量是不同的。
要计算在调查中提供了年龄信息的人数(即非空值的数量),可以使用 age.count()。这将返回一个整数,例如 13613。这里的 int64 是一种整数数据类型。count 方法与 len 不同,因为它不包含空值,而 len 会包含。
虽然我们经常需要详细检查某个特征,但实际上我们也可以对整个数据框使用 count 方法。这个快捷方式可以让你一眼看出每一列的非空值数量。例如,你可能发现“resource_books”(通过书籍学习编程的资源)这一列的响应最少,这可能是因为并非每个人都通过书籍学习。
你还可以看到“marital_status”、“student”和“income”等列的响应也相对较少,“number_of_children”列也是如此,这可能是因为没有那么多受访者有孩子或愿意分享该信息。
假设你正在为你的教育产品制定定价和功能策略,你可能需要计算学习编程的总小时数和花费的总金额。
首先,检查它们的分布。将“学习编程花费的小时数”列保存到变量 hours 中。
hours = df['HoursLearning']
然后,你可以使用 .hist() 方法绘制数据。如果你愿意,可以使用之前从助手那里得到的参数让图表更美观。
从直方图可以看到,超过一半的人每周花费0到20小时学习编程。顺便提一下,如果你将 bins 参数设置为40,会发现一个有趣的现象:许多答案恰好是10、15、20等整数,而更精确的答案则较少。
现在,要对学习编程的总小时数求和,使用 hours.sum()。你会得到一个 float64 类型的十进制数,总和超过20万小时。这表明,受访者们在学习编程上总共投入了大量时间。
对于学习编程的花费,将该列保存到变量 money 中。
money = df['MoneySpent']

用 .hist() 绘制这个序列的直方图,你会得到一个极度偏斜的分布。将 bins 增加到40,可以看到绝大多数人花费相对较少,但存在少数极高的异常值。money.sum() 的结果显示,受访者们总共花费了超过1600万美元,总金额非常庞大。
本节课中我们一起学习了数据分析的基础操作。
总结一下,你可以直接在数据框上使用 .count() 方法来查看每列的非空值数量,也可以在单个序列上使用。我们还看到,可以使用 .hist() 方法快速绘制简单的直方图,以展示数值特征的分布。最后,只要列是数值型的,就可以使用 .sum() 方法对列中的所有值进行求和。
计数和求和是任何分析的基础,而 pandas 的直方图方法能帮助你快速可视化数值特征。请继续练习使用数据框和序列。

接下来,你将完成本课的练习作业以及一个实践实验室,以测试你的 pandas 技能。完成后,我们将在下一节关于排序和筛选的课程中再见。
034:Python数据分析 第3课 - 数据排序 📊
在本节课中,我们将要学习如何使用Python的Pandas库对数据进行排序。排序是数据分析中一项强大且灵活的操作,能够帮助我们快速整理和理解数据。
导入数据与基础排序
上一节我们介绍了数据清洗,本节中我们来看看如何对数据进行排序。首先,我们需要导入Pandas库并读取数据。
import pandas as pd
df = pd.read_csv('survey_data.csv')
你的第一个目标是将受访者按年龄从大到小排序。以下是实现此目标的基本步骤:
- 从数据框开始。
- 使用
sort_values方法。 - 默认情况下,
sort_values不会改变原始数据框,而是创建一个新的。 - 你需要将排序操作的结果存储在一个变量中。

以下是实现代码:
df_sorted_by_age = df.sort_values(by='age')
在这行代码中,by 是一个命名参数,用于指定要排序的列。执行后,df_sorted_by_age 是一个新的数据框,其行数应与原始数据框相同,只是顺序发生了变化。
查看排序后数据框的前几行,你会发现最年轻的受访者(例如10岁、11岁)。
print(df_sorted_by_age.head())
降序排序与命名参数
目前我们得到的是升序排列的结果,但我们的目标是从大到小排序。你可以通过修改代码来实现降序排序。
以下是修改后的代码:
df_sorted_by_age = df.sort_values(by='age', ascending=False)
在这行代码中,我们添加了第二个命名参数 ascending 并将其设置为 False。默认情况下,ascending=True 表示升序。通过设置 ascending=False,我们覆盖了默认值,实现了降序排序。
现在查看数据框的头部,你将看到最年长的受访者。
关于 by 和 ascending 这类命名参数,其主要好处是你可以以任意顺序提供它们。例如,以下两行代码是等效的:

df_sorted = df.sort_values(by='age', ascending=False)
df_sorted = df.sort_values(ascending=False, by='age')
本节总结
本节课中我们一起学习了在Pandas中进行数据排序的基础知识。

- 我们学会了使用
sort_values()方法对数据框进行排序。 - 我们了解到必须使用命名参数
by=来指定要排序的列名。 - 我们明白了
sort_values()会创建一个新的数据框,因此需要将其保存到一个新变量中。 - 我们掌握了通过设置
ascending=False来实现降序排序。 - 我们认识了命名参数,它们允许我们以任意顺序传递参数,这在Pandas中很常见。
现在你已经熟悉了Pandas排序的基础。在下一个视频中,你将学习如何同时按多列进行排序。
035:Pandas多列排序 📊
在本节课中,我们将要学习如何在Pandas中对数据框(DataFrame)进行多列排序。这是一种强大的功能,允许我们根据多个条件来组织和查看数据。
上一节我们介绍了单列排序,本节中我们来看看如何根据多个列的组合条件来排序数据。
概述
如果你需要在Pandas中根据多列进行排序,可以使用与之前类似的方法,但需要向sort_values方法提供一个列名的列表。
假设在加载数据并创建了一个按年龄排序的新数据框后,你可能想进一步研究每个年龄段中学习时间最长的人。例如,你想先按年龄降序排列,再按每周学习编码的小时数降序排列,以找出每个年龄段中学习最刻苦的人。

以下是实现多列排序的步骤:
首先,创建一个包含你想要排序的列的列表。列表的顺序很重要,第一个元素是你想首先排序的列,即先按年龄,再按学习编码的小时数。
columns = ['age', 'hours_spent_learning_to_code']
然后,你还需要为ascending参数创建一个列表。在本例中,你希望这两列都按降序排列。
因此,你需要一个布尔值列表。将其命名为order,包含两个False值。
order = [False, False]
接着,调用数据框的sort_values方法。
sorted_df = df.sort_values(by=columns, ascending=order)
在这里,你通过一个长度为2的列名列表进行排序。同时,你通过另一个长度为2的列表告诉Pandas这两列都按降序排序。最后,将结果保存到一个新变量中,例如sorted_by_age_and_hours。
这段代码初看可能有些复杂,我们稍后会逐步分解。现在,让我们先执行它。
你预期这个结果的数据类型是什么?它应该是一个数据框。并且,其长度应该与原始数据框完全相同。你并没有添加或删除任何数据,只是改变了行的顺序。
当你查看前五行数据时,你预期会看到什么?运行该单元格后,前两行确实与之前相同,但现在你有了按年龄和小时数降序排列的75行数据,其中第1846行以每周6小时的学习时间位居榜首。
代码分解
让我们一起来分解这几行代码,因为其中包含了许多操作。
首先,你创建了两个列表:
- 第一个列表
columns包含了你想要排序的列,本例中是age,然后是hours。 - 第二个列表
order包含了ascending参数的值。在本例中,你希望按降序排序(数值大的排在前面),因此两个值都是False。
第三行代码,在等号右侧,你调用了数据框的sort_values方法。
- 你通过
columns列表中的列进行排序,即先按年龄,再按学习编码的小时数。 - 然后,你使用
order列表指定每列是按升序还是降序排序。因此,年龄先按降序排序,然后小时数也按降序排序。
sort_values方法会创建一个新的数据框,所以你将其保存到新变量sorted_by_age_and_hours中。

总结

本节课中我们一起学习了Pandas中的多列排序。你掌握了如何通过提供一个列名列表和对应的排序顺序列表,来根据多个条件对数据进行排序。这是一个非常实用的技能,能帮助你在数据分析中更精确地组织和筛选数据。
关于排序的出色工作就到这里。接下来,你将学习如何过滤数据,以仅选择你感兴趣的行。我们下个视频再见。


036:Python数据分析 第3课 - 数据筛选 🎯
在本节课中,我们将要学习如何在Python中使用Pandas库对数据进行筛选。数据筛选是数据分析中的一项核心技能,它允许我们根据特定条件从数据集中选取感兴趣的行,从而专注于分析特定的数据子集。
概述 📋
你已经了解如何在电子表格中筛选数据,即只选择满足特定条件的行。那么,如何在Python中完成这项任务呢?在接下来的报告部分,你将分析受访者的性别构成。理解这一构成将有助于你制定营销策略和产品功能。

分析性别构成 👥
首先,我们需要分析“性别”列中的唯一响应值。以下是具体步骤。
以下是分析性别列唯一值的代码:
pd.unique(df['gender'])
然后,你可以打印结果。选项包括男性、女性、性别酷儿、跨性别者、无性别者以及NaN(非数字)。NaN是空值,表示受访者将该字段留空。
你可能会注意到这些值被单引号包围,但在Python中它们仍然是字符串。在Python中,你也可以使用单引号来定义字符串。
创建筛选数据集 🔍
如果你想比较例如男性和女性的编码习惯,你可以创建一个仅包含女性的筛选数据集。
因此,你需要从数据框中选择那些“性别”列等于“女性”的受访者。
以下是筛选女性受访者的代码:
female_respondents = df[df['gender'] == 'female']
那么,这行代码将做什么?它会遍历数据框中的每一个响应。对于每个响应,它会查看“性别”列中的值。如果性别等于“女性”,那么该行将被包含在筛选后的数据框中;如果不等于,则不会被包含。
例如,在按年龄和小时数排序的数据框中,只有第三行和第四行会被包含进来。将这个结果保存到一个变量中,例如female_respondents。
female_respondents的类型是什么?它是一个数据框。

让我们查看该数据框的前五行。


你可以看到已成功筛选出仅包含女性的受访者。注意,原始的整数索引被保留了下来,因此你知道第0、1、2行的性别值不同,依此类推。
分析筛选后的数据 📊

现在,如果你只想对女性受访者进行分析,就可以进行了。例如,female_respondents的长度是2840。这个值是数据框中的行数。在总共约15,000名受访者中,女性受访者大约有3000名。
你还可以绘制她们年龄的直方图。
如果你还记得上一课中包含所有年龄的直方图,你可以看到在这个20多岁的年龄段中,女性受访者更多。
使用数值列进行筛选 🔢
上一节我们介绍了如何根据文本条件筛选数据,本节中我们来看看如何处理数值列。
如果你处理的是数值列,可以使用其他条件运算符进行筛选,例如大于或等于。

例如,要选择“学习编码小时数”大于30的行,请使用以下代码:
above_30_respondents = df[df['hours_spent_learning_to_code'] > 30]

同样,要选择年龄大于30的行,请使用以下代码:
above_30_respondents = df[df['age'] > 30]
然后,将该结果存储在above_30_respondents中,并在直方图中绘制年龄列。
你应该看到X轴的下限应该是30。在电子表格中,这将是一个复杂得多的操作,需要一种自定义筛选器。
筛选原理详解 ⚙️
为了总结,为了筛选你的数据,即选择符合特定条件的行,你需要使用布尔表达式从数据框中进行选择。
例如,你看到了如何使用命令df[df[‘gender’] == ‘female’]来选择调查参与者回答性别为“女性”的响应。你正在从整个数据框中选择“性别”列中的值与字符串“女性”匹配的行。
你还看到括号内的布尔表达式可以是等于、大于,也可以是小于。在下一个视频中,你将看到更多筛选选项。
看看这段代码。你正在选择匹配这个布尔表达式的行。那么,这对于原始数据框的前五行实际上做了什么?
前五行的性别是男性、男性、男性、女性、女性。右侧这个表达式df[‘gender’] == ‘female’的类型是一个序列。它是一个布尔值序列,起始值为False、False、False、True、True。
如果该行的性别是女性,则每个值为True,否则为False。
当你使用这个表达式从数据框中进行选择时,计算机将逐个查看序列中的每个值。如果序列中的值为False,它将不包含该行,并将其丢弃。如果值为True,它将把该行包含在选择中。
这就是为什么在female_respondents中,前两个索引是3和4。这些是序列中前两个值为True的行的索引。

总结 📝
本节课中我们一起学习了如何在Python中使用Pandas进行数据筛选。筛选为你分析数据的子集提供了极大的灵活性。在下一个视频中,你将学习使用多个条件进行筛选。我们下节课再见。
037:Python数据分析(第3课)|多条件筛选 🎯
在本节课中,我们将学习如何使用pandas库进行多条件数据筛选。多条件筛选允许我们基于多个标准从数据集中提取更复杂的子集,例如同时满足“女性”和“年龄大于30岁”的受访者。

多条件筛选的应用场景
上一节我们介绍了单条件筛选,本节中我们来看看如何组合多个条件。假设你正在为报告构建用户画像,需要分析同时满足“女性”和“年龄大于30岁”这两个条件的个体数据。
使用LLM辅助生成代码
在编写多条件筛选代码时,你可以借助大型语言模型(LLM)获取帮助。以下是向LLM提问的示例提示:
我在代码中创建了两个独立的数据框:一个仅包含女性,另一个仅包含年龄大于30岁的受访者。如何组合这两个筛选条件,得到一个仅包含同时满足“女性”和“年龄大于30岁”的受访者的数据框?请分享代码。
LLM会建议你直接在单个数据框上组合条件,并提供如下示例代码:
female_and_above_30 = df[(df['gender'] == 'female') & (df['age'] > 30)]
你可以尝试运行这段代码,并将变量名改为更简洁的形式,例如female_above_30。注意,LLM可能使用“大于或等于”条件,但你可能只需要“大于”条件。
理解筛选结果
以下是关于筛选结果的预期:
- 筛选后的数据框行数应少于仅包含女性的数据框,因为它是后者的子集。
- 实际结果符合预期:筛选后数据框大约有1100行。
- 随机抽样10行进行验证,确认筛选条件已正确应用。
代码结构解析
这段代码有几个新特点,但也有一些相似之处:
- 两个条件与之前相同:
gender == 'female'和age > 30。 - 每个条件都用括号括起来。
- 条件之间用&符号连接,表示“且”关系,即两条件必须同时满足。
使用“或”条件筛选
你也可以筛选满足至少一个条件的行。例如,如果你对“女性”或“年龄大于30岁”的受访者感兴趣,只需将&改为|(管道符):
female_or_above_30 = df[(df['gender'] == 'female') | (df['age'] > 30)]

管道符通常位于键盘回车键上方,表示“或”关系。将结果变量命名为females_or_above_30并抽样查看,你会发现结果中包含了:
- 年龄大于30岁的男性受访者。
- 年龄小于30岁的女性受访者。
- 年龄大于30岁的女性受访者。


所有这些都是至少满足一个指定条件的受访者。
核心要点总结
以下是多条件筛选的核心要点:

- 使用&(且)和|(或)运算符进行多条件筛选。
- 每个条件都应放在括号内。
- &用于选择同时满足所有条件的行。
- |用于选择至少满足一个条件的行。
本节课中我们一起学习了如何使用pandas进行多条件数据筛选,掌握了“且”与“或”运算符的应用。现在你已经熟悉了数据的排序和筛选,接下来可能希望选择数据中的特定行或数据切片。我们将在下一个视频中学习如何实现。
038:行选择 📊
在本节课中,我们将学习如何在Pandas数据框中选择特定的行。我们将探讨如何设置自定义索引,以及如何使用.loc和.iloc两种方法来精确地选取数据行。
概述
处理数据时,除了筛选列,分析数据行的子集也很常见。你可以更新数据框的索引,为行选择提供更大的灵活性。目前我们使用的数据框和序列都具有数字索引,即每行都有一个从0开始的唯一数字标识符。然而,Pandas也允许你分配自己的索引。
如果你的数据包含唯一标识符,如学生ID或国家代码,通常的做法是分配自定义索引。你也可以将字符串甚至日期时间等类型作为索引,这对于时间序列数据尤其有用。
设置自定义索引
你可能已经注意到,这个调查数据集包含一个“ID”列,它是每位受访者的唯一标识符。你可以用这些唯一的ID替换左侧的数字索引,从而允许你根据受访者的ID来选择特定的行。
注:此“ID”列并非原始公开数据集的一部分,我们为本次演示创建了它。原始调查是匿名的。
要将唯一的ID设置为索引,你可以使用set_index方法,并传入一个参数:列名(字符串形式)。


代码示例:
indexed_df = df.set_index('ID')
检查数据框的前五行。现在,索引不再是整数,而是ID,并且ID列已从数据框中移除。
使用 .loc 按索引选择行
现在,如果你的团队说他们正在采访ID为25447的受访者,并希望你提取该人的信息以帮助生成一些面试问题,你可以使用.loc方法通过索引来选择该行。
代码示例:
indexed_df.loc[25447]
这将提取出该个体的信息:一位来自孟加拉国的35岁男性。
使用 .iloc 按位置选择行
无论索引如何设置,你始终可以使用.iloc(整数位置)根据行在数据框中的位置来选择行。即使你刚才将索引设置为ID列,这个数据框仍然有从0开始的整数行号。
例如,如果要求你找到索引为1000的行,你可以使用:
代码示例:
indexed_df.iloc[1000]
结果显示,该受访者是一位来自美国的25岁男性。
你可以将此值保存到一个变量中,例如response_1000。请记住,这些行是从0开始计数的,所以这实际上是第1001行。
现在,response_1000变量的类型是什么?输入type(response_1000)。它也是一个序列。
它相对较短,因为每列只有一个值,总共有16列。这位受访者是一位25岁的男性,居住在美国,说英语,每周花费大约20小时学习编程,等等。
这个序列看起来有点不寻常,不是吗?左侧的列名实际上是右侧值的索引。这是一个使用字符串作为索引的例子。
由于这个序列的结构,你可以使用“Age”作为索引来选择此人的年龄。
代码示例:
response_1000['Age']
这将直接返回数字25。
使用切片选择多行
你的同事要求你调查从整数位置8664开始的五行数据,因为他们认为这些响应可能存在问题,包含大量缺失值。

为此,你可以使用冒号运算符来切片数据,这与你在之前模块中对列表使用的操作类似。
代码示例:
range_of_rows = indexed_df.iloc[8664:8669]
这将选择从8664开始(包括8664)到8669结束(不包括8669)的五行数据。你可以将选择结果保存在一个变量中,如range_of_rows。
range_of_rows的类型是什么?它是一个数据框。这是因为你选择了多个行的所有列,构成了一个二维结构。
查看这些响应,你的同事是对的,确实存在一个包含大量缺失值的异常数据块。
这个操作被称为数据框切片,因为你切出了一部分数据来进一步检查。这就像为自己切一块蛋糕:你进行两次切割来定义切片的起点和终点,然后得到整个切片。
行选择方法回顾
刚开始接触行选择时可能会感到复杂。我们来回顾一下:
- 如果你使用
.set_index方法设置了列名作为索引,可以使用.loc基于索引访问行。 - 你也可以使用
.iloc基于行在数据框中的位置来选择行,类似于列表。 - 数据框是0索引的,所以第一行的索引是0。
- 要选择一行切片或一个行范围,你将使用一个非常相似的命令,但这次使用冒号来选择范围。

因此,如果你有一行代码像indexed_df.iloc[1000:1006],它将选择第1000行到第1005行(不包括第1006行)。
更一般地说,如果你有一个像indexed_df.iloc[a:b]的命令,它将选择从a(包括a)到b-1的所有行,即不包括b。
为什么切片不包括最后一个值?
在切片时输入值1006却得不到该行,这可能看起来有违直觉。为什么切片不包括最后一个值?这样做有几个好处,但主要好处之一是切片的长度始终是 end - start。

例如,1006 - 1000 = 6。所以切片的长度是6。

如果切片包括最后一个值,长度将是7,这会更 awkward(不直观/不方便)。
总结
本节课中,我们一起学习了如何在Pandas数据框中选择行。我们掌握了设置自定义索引的方法,并学会了使用.loc通过索引选择行,以及使用.iloc通过整数位置选择行。我们还探讨了如何使用切片操作来选择连续的多行数据,并理解了切片范围“左闭右开”的设计原理。
你现在已经熟悉了数据框和序列,包括排序、筛选以及选择行和列。你将在接下来的实践练习和作业中测试这些技能。完成后,请跟随我进入本模块关于描述性统计的最后一课。我们那里见。😊
039:Python数据分析(第3课)|集中趋势、离散度与偏态 📊
概述
在本节课中,我们将要学习如何使用Pandas库来分析数据集中数值型特征的分布。具体来说,我们将探索如何计算和解读数据的集中趋势(如均值、中位数)、离散度(如标准差)以及偏态。这些描述性统计量是理解数据基本特征的关键第一步。
在完成了数据计数、求和、图表绘制以及筛选之后,你很可能希望获取每个特征分布的更多信息。
我们从数值型特征开始分析。首先,创建一个新的笔记本。
导入Pandas库并读取数据,同时设置索引。这只是常规的数据准备工作。
import pandas as pd
df = pd.read_csv('your_data.csv')
df.set_index('some_column', inplace=True)
分析分布与计算统计量
上一节我们完成了数据导入,本节中我们来看看如何分析单个数值特征的分布。
分析的下一个步骤可能是描述“每周编码小时数”这一特征的分布情况。
请记住,.hist()方法可以用于生成直方图。
df['HoursLearningToCode'].hist()

这个分布呈现出强烈的正偏态。你可以看到,大多数受访者每周编码时间少于20小时,而花费更多时间编码的受访者数量则越来越少。


现在,你可以计算描述性统计量了。首先计算平均小时数。

mean_hours = df['HoursLearningToCode'].mean()
均值大约是每周15小时。这相当于一份兼职工作的时间。
因此,这项调查似乎主要捕捉的是那些通常在业余时间学习编程的人,而非进行正规学习的人。
请注意,这个值的类型是numpy.float64。所以numpy又出现了。它只是一个带小数点的数字。如果你愿意,可以使用print来避免看到numpy.float部分。
print(mean_hours)
你也可以使用.median()方法检查中位数,其值为10。
median_hours = df['HoursLearningToCode'].median()
这个值是有意义的,因为在偏态分布中,均值会被拉向分布尾部——在本例中是更高的数值方向。
你还可以使用.std()获取标准差,其值大约为14。对于偏态分布的数据,标准差的意义不如对更接近正态分布的数据那么明确。
以下是计算这些常见描述性统计量的方法总结:
- 均值:
.mean() - 中位数:
.median() - 标准差:
.std()
所有这些常见的描述性统计量计算起来都非常直接。你不需要在这些函数中提供任何参数,可以直接在你的Series上调用它们。

作为一个快速提醒,所有这些计算与直接在列名上使用这些方法会产生相同的结果。


计算分位数
你可能还想获取分位数,即数据在25%、50%和75%位置的值。
如何做到这一点呢?如果你尝试像在电子表格中那样,用这三个值调用hours.quartile,你会得到一个错误:Series对象没有quartile属性。
让我们向大语言模型寻求一些调试帮助。我尝试了这段代码来获取Series的25、50和75百分位数,但我得到了下面的错误。正确的代码是什么?
然后粘贴错误信息。注意,你不需要复制代码,因为该行已经是错误信息的一部分。
大语言模型纠正了你的代码,你需要使用.quantile方法,而不是.quartile。
尝试提供的代码,你会得到这些漂亮的整数:5、10和20。
q25 = df['HoursLearningToCode'].quantile(0.25)
q50 = df['HoursLearningToCode'].quantile(0.50) # 等同于中位数
q75 = df['HoursLearningToCode'].quantile(0.75)
正如你在之前的视频中看到的,大多数人对这个问题的回答都是整数,所以这些值是合理的。
你还可以通过传入一个列表作为参数,而不是单个数字,来一次性获取多个分位数。
例如,你可能希望一次性获取所有三个分位数。
quantiles = df['HoursLearningToCode'].quantile([0.25, 0.50, 0.75])
查看这个结果的类型,你可以看到返回的是一个Series。你可以通过引用相关的索引来访问每个分位数。
使用.describe()方法
正如你刚才看到的,你可以分别计算所有这些描述性统计量,或者你也可以使用hours.describe()非常容易地获取它们。
df['HoursLearningToCode'].describe()
这个方法与df.info()类似,因为它能立即为你提供大量有用的统计信息:有多少个值、均值、标准差、最小值、最大值、不同的分位数(包括中位数)。这是一个非常方便的快捷方式。
你可能注意到偏度没有被包含在.describe()中。但是,你可以使用.skew()方法。

skewness = df['HoursLearningToCode'].skew()
这个方法给出的值与电子表格中SKEW函数的解释相同。对于hours.skew(),你的结果大约是2。因此,这个值表明数据存在强烈的正偏态。
应用于整个DataFrame
你现在已经看到了.describe()方法应用于一个Series。请记住,任何给定列的类型都是一个Series,它是一维的。
你也可以在整个DataFrame上使用.describe()。
df.describe()
这会给出大量信息。df.describe()为你提供了一个非常美观的表格,列出了所有特征及其分布统计量——只要它们是数值型特征。你无法计算分类特征的标准差。
因此,这里有很多可以研究的内容,你可以快速获取大量信息。
总结
本节课中我们一起学习了用于分析数值型特征的中心趋势、变异性和偏态的工具。

你可以对一个Series或整个DataFrame使用.describe()来快速计算数据中数值特征的描述性统计量,包括计数、均值、中位数等。
你也可以使用Pandas提供的不同方法单独计算这些值:mean、median、std、max、min、var和quantile。这些方法大多不需要参数,除了quantile方法,你需要为其指定一个数字或一个数字列表以一次性获取多个分位数。
你可以轻而易举地获取关于数据特征的众多信息。
一旦处理完数值型特征,你将希望继续处理分类特征。请跟随我进入下一个视频了解如何操作。
040:Python数据分析 第3课 - 分类数据处理 📊

在本节课中,我们将要学习如何处理和分析分类数据。分类数据与数值型数据的分析方法不同,Python提供了一些关键工具来执行这些分析,包括value_counts方法和绘图功能。
概述
分类数据通常指文本或类别型数据,例如性别、国家、语言等。分析这类数据时,我们主要关注不同类别的分布情况。本节将介绍如何使用value_counts方法统计类别频次,以及如何通过条形图直观展示这些分布。
选择分类数据列
上一节我们介绍了如何计算数值型数据的描述性统计量。本节中我们来看看如何分析分类数据。首先,需要确定数据集中哪些列是分类数据。如果记不清所有列,可以使用df.dtypes来查看列的数据类型。在Pandas中,object类型通常表示文本数据,即分类数据。

例如,性别、居住国家、家庭语言等列很可能就是分类数据。我们将首先选择要分析的列,例如“性别”列。
使用 value_counts 方法
分析分类数据的主要方法是value_counts。该方法返回一个Series,其中包含该列中每个唯一值及其出现的次数。由于我们可能要用这些计数来生成图表或进行其他分析,建议将结果保存到变量中以便后续使用。
以下是具体操作步骤:
- 选择目标列并应用
value_counts方法。 - 将结果保存到一个变量中。

例如,对于性别列:
counts_of_gender = df['gender'].value_counts()
查看counts_of_gender,可以看到男性约占非空响应的78%,女性约占21%,其他性别多样性答案约占1%。
counts_of_gender是一个Series类型。该Series的索引是不同的性别类别(如“男性”、“女性”等),而值则是每个类别对应的计数。
绘制条形图
对于数值型列,我们可以直接绘制直方图。对于非数值型列,我们需要使用保存的计数Series来绘图。具体方法是调用plot方法,并通过kind参数指定图表类型为条形图。
运行以下代码可以生成一个基础的条形图:
counts_of_gender.plot(kind='bar')
这个图表以易于理解的方式直观展示了性别分布信息。
为了使图表更美观,可以调整plot方法的参数。例如,可以添加标题、调整颜色和图形尺寸。以下是优化后的代码示例:
counts_of_gender.plot(
kind='bar',
title='Distribution of Gender',
color='skyblue',
figsize=(10, 6)
)
请注意,这里使用的是kind='bar'。虽然生成的图表是柱状图,但在Pandas绘图方法中它被称为条形图。如果尝试使用kind='column',将会收到错误提示。
分析家庭语言数据
接下来,我们想找出调查受访者在家中使用的五大语言。
首先,选择“家庭语言”列并应用value_counts方法:
counts_of_languages = df['language_at_home'].value_counts()
counts_of_languages同样是一个Series。我们可以对它进行Series支持的任何操作。
例如,使用.head()方法查看前五个最常见的语言:
counts_of_languages.head()
结果显示,英语是最常用的家庭语言,其出现频率几乎是第二名西班牙语的十倍。俄语、印地语和葡萄牙语位列前五。

我们还可以检查这个Series的长度,它表示该列中出现了多少种不同的语言:
len(counts_of_languages)
在这个数据集中,有148种不同的语言被列为家庭语言。
可视化语言数据
如果直接对包含148种语言的完整Series绘制条形图:
counts_of_languages.plot(kind='bar')
生成的图表会非常庞大且难以解读。

由于我们只关心前五大语言,可以先使用.head()方法获取前五个数据,然后直接在其上调用plot方法:
top_five_languages = counts_of_languages.head()
top_five_languages.plot(kind='bar')
这样就能得到一个清晰、简洁的条形图,直观展示家庭中使用最多的五种语言。

总结
本节课中我们一起学习了如何处理分类数据。核心方法是使用value_counts,它返回一个按出现次数降序排列的Series,其中分类特征的唯一值作为索引,计数作为值。我们可以通过先保存value_counts的结果,再使用df.plot(kind='bar')方法来创建条形图,从而直观展示分类数据的分布情况。

理解分类特征的分布后,我们就可以进一步深入挖掘数据中的关系了。
041:Python数据分析(第3课)| 相关分析 📊
概述

在本节课中,我们将要学习如何使用Pandas进行相关分析。相关分析是量化两个数值型特征之间关系强度和方向的重要工具。我们将学习如何创建散点图来直观地观察关系,以及如何计算皮尔逊相关系数来精确地量化这种关系。

散点图:可视化关系
上一节我们介绍了如何对数据进行描述性统计和绘制直方图、条形图。本节中我们来看看如何可视化两个数值变量之间的关系。
散点图是观察两个数值特征之间关系的首选方法。在绘制散点图时,你需要同时指定两个列,因此需要从DataFrame开始操作,而不是单个Series。
以下是创建散点图的步骤:
- 使用DataFrame的
.plot()方法。 - 将
kind参数设置为‘scatter’。 - 通过
x和y参数分别指定X轴和Y轴对应的列名。
例如,我们想探究“收入”和“学习编程的花费”之间的关系:
df.plot(kind='scatter', x='income', y='money_spent_learning_code')
观察生成的图表,可能并未发现预期的明显模式。X轴上的“收入”似乎对Y轴上的“学习编程的花费”影响不大。
接下来,我们复制代码来观察“年龄”和“编程月数”之间的关系:


df.plot(kind='scatter', x='age', y='months_spent_programming')

这个图表显示出更有趣的关系。可以看到许多人的“编程月数”为零,表明他们是初学者。但同时,似乎存在一种正向关系:有一组受访者年龄越大,编程的月数也越多。此外,还有一大群初学者分布在各个年龄段。
计算相关系数
散点图提供了直观感受,而皮尔逊相关系数则能精确量化关系的强度和方向。为了计算它,我们将使用Pandas的.corr()方法。
.corr()方法用于DataFrame,而非单个列,因为计算相关性需要两个列。与.describe()方法类似,当你在DataFrame上调用.corr()时,它会显示所有特征对之间的相关性。
如果你直接在包含非数值列(如分类数据)的原始DataFrame上调用.corr(),会导致错误。因此,你需要首先选择所有感兴趣的数值型列。
以下是计算相关系数的步骤:
- 创建一个包含你感兴趣的数值型列名的列表。
- 使用这个列表从DataFrame中选取这些列,生成一个只包含数值数据的新DataFrame。
- 在这个新的DataFrame上调用
.corr()方法。
# 1. 创建数值列列表
columns_of_interest = ['age', 'number_of_children', 'money_spent_learning_code', 'months_spent_programming', 'income']
# 2. 从原始DataFrame中选取这些列
selected_columns = df[columns_of_interest]
# 3. 计算相关系数矩阵
correlation_matrix = selected_columns.corr()
correlation_matrix
运行后会得到一个大的相关性结果表。对角线上的值都是1,表示每个特征与自身完全相关。
在结果中,我们可以找到之前感兴趣的关系:
- “收入”和“学习编程的花费”之间的相关系数约为 0.08,这是一个非常弱的相关性。
- “年龄”和“编程月数”之间的相关系数约为 0.22,这是一个稍强但仍属弱相关的正相关性。这意味着年龄可以解释约22%的编程月数变化。

关键要点总结
本节课中我们一起学习了如何使用Pandas进行相关分析。
当调查两个数值变量之间的关系时:
- 要创建散点图,你需要在DataFrame上使用
.plot()方法,将kind参数设为‘scatter’,并通过x和y参数指定特征。 - 要计算相关系数,你需要在DataFrame上调用
.corr()方法。如果DataFrame包含分类列会导致错误,因此你需要先从中选取感兴趣的数值型列构成子集,然后在这个新DataFrame上使用.corr()方法,从而得到相关性表格。
请注意,相关性表格中超过一半的结果是冗余的,因为每个特征与自身的完美相关性(1)以及相关性计算的对称性(A与B的相关性等于B与A的相关性)使得每个结果在表中出现了两次。

后续内容
你已经接近本模块的尾声,学习了Pandas中许多有用的方法,从读取数据、选择、排序、筛选、计算描述性统计量,到绘制直方图、柱状图和散点图。
现在你已经在Python中学习了这么多计算和可视化技能,你可能希望将它们应用到数据的各个细分部分中。请跟随我进入本模块最后两个关于数据分段的视频。
042:Python数据分析(第3课)|单特征分群 🎯
在本节课中,我们将要学习如何使用pandas库中的groupby方法,基于一个特征对数据进行分群。分群能帮助我们观察一个特征如何随另一个特征的变化而变化,是分析特征间交互作用的强大工具。

数据分群概述 📊
数据分群允许你基于另一个特征来观察某个特征的模式。这是一个分析特征如何相互作用的强大工具。让我们看看如何使用pandas在Python中进行分群。
假设在你的报告的最后部分,你感兴趣的是确定学习编码的时间是否因一个人所拥有的孩子数量而异。因此,你需要基于一个特征(孩子数量)进行分群,然后分析学习编码的时间。
开始分群:使用groupby方法
由于你需要同时访问“孩子数量”和“学习编码时间”这两列数据,你需要从整个DataFrame开始操作。从一个Series开始是不行的,因为那样你会缺失所需的其中一列。
以下是开始分群的步骤:
- 使用
groupby方法:通过df.groupby('number_of_children')这行代码,你的数据会根据“孩子数量”的值被切割成多个子集。 - 保存结果:将结果保存到一个变量中,例如
group_by_children。
当你运行这段代码并查看结果时,你可能期望看到一个类似DataFrame的表格。然而,你只会得到一个类似pandas.core.groupby.generic.DataFrameGroupBy的对象。这是因为groupby本身并不立即进行计算,它只是将数据分好组。要看到任何结果,你需要执行下一步:对这些分组结果进行某种计算。
计算分组统计量
为了生成有意义的结果,你需要执行几个中间步骤,包括选择你想要探索的列,并应用一个函数来计算某种描述性统计量。
以下是具体操作:
- 从
groupby对象中选择你感兴趣的列,例如“学习编码时间”。 - 然后应用一个计算函数,比如
.count()(计数)或.mean()(平均值)。
通过执行这些步骤,你将得到基于孩子数量分群后的学习编码时间数据。例如,调查结果显示,约有100名受访者有一个孩子,938名受访者有两个孩子,依此类推。当孩子数量超过四个时,响应数据变得非常稀疏;超过六个时,由于样本量太小,几乎无法得出有意义的结论。
更有趣的可能是查看不同孩子数量下学习编码的平均时间。例如,有一个孩子的受访者平均学习时间为14.1小时,有两个孩子的为12.4小时,之后略有波动。对于孩子数量超过四个的组,由于样本量小,评估价值较低。

groupby方法的核心概念总结
对于分群,你可以从你的DataFrame开始使用groupby方法。
groupby对象的类型:调用groupby方法的结果类型是一个GroupBy对象,它不是一个DataFrame,但有一些相似之处。- 选择列:你可以从这个
GroupBy对象中选择列,就像刚才演示中选择“学习编码时间”列一样。 - 执行计算:选择列后,你可以执行计算,如计算计数、总和、平均值或其他描述性统计量。这些结果将按每个分组进行汇总展示。
核心要点:groupby本身不会计算任何均值、计数,甚至不会明确划分出不同的组。只有当你实际执行下一步计算操作(如选择一列并计算其均值或总和)时,这些计算才会发生。
课程总结 🎓

本节课中,我们一起学习了单特征分群。我们了解到,pandas的groupby方法是一个强大的工具,它能将数据按指定列的值进行分组。关键在于,groupby本身只创建分组结构,必须后续结合聚合函数(如.mean(), .count())才能计算出每个组的统计结果。这种方法对于探索一个变量如何随另一个分类变量变化非常有用。
然而,如果你想要基于多个特征进行分群,则需要使用不同的方法——数据透视表。我们将在下一个视频中学习如何使用它。
043:多特征分群 📊
在本节课中,我们将学习如何使用Pandas库对数据进行多特征分群。这是数据描述性分析的最后一项任务,能帮助我们同时基于多个类别特征来观察数据的变化。
上一节我们介绍了如何按单个特征(如子女数量)对数据进行分组。本节中,我们来看看如何同时基于两个类别特征进行分群,例如,分析每周学习编码的时间是否同时受“子女数量”和“当前是否为软件开发人员”这两个因素的影响。

使用数据透视表进行分群

如果你想基于两个类别特征对数据进行分群,数据透视表是最合适的工具。
以下是创建数据透视表的基本步骤:
- 在电子表格软件中,选择你的数据。
- 插入数据透视表。
- 将“子女数量”字段拖入“行”区域。
- 将“是否为软件开发人员”字段拖入“列”区域。
- 将“每周学习编码时间”字段拖入“值”区域。
- 默认的汇总函数是求和,但通常我们更关心平均值,因此需要将值字段的汇总方式改为“平均值”。
通过这个操作,你可以得到每个特征组合(例如,有一个孩子且不是开发者,有一个孩子且是开发者)对应的平均学习时间。
在Python中使用Pandas实现
在Python的Pandas库中,我们可以通过pivot_table方法快速实现类似的功能,其逻辑与电子表格中的数据透视表非常相似。
import pandas as pd

# 假设df是你的DataFrame
pivot_result = df.pivot_table(
index='number_of_children', # 对应行
columns='is_software_dev', # 对应列
values='hours_spent_learning_code' # 要分析的值
)
运行以上代码后,pivot_result将是一个数据透视表,默认使用均值作为每个特征组合的汇总值。例如,表格会显示“有一个孩子且不是开发者”的群体的平均学习时间,以及“有一个孩子且是开发者”的群体的平均学习时间。
自定义汇总函数
与电子表格一样,pivot_table方法也允许你指定不同的汇总(聚合)函数。这是通过aggfunc参数实现的。
aggfunc参数的默认值是‘mean’(均值)。你可以将其更改为其他函数:
aggfunc=‘sum’:计算每组的总和。aggfunc=‘std’:计算每组的标准差。aggfunc=‘min’/aggfunc=‘max’:找出每组的最小值或最大值。
例如,要计算总学习时间,代码如下:
pivot_sum = df.pivot_table(
index='number_of_children',
columns='is_software_dev',
values='hours_spent_learning_code',
aggfunc='sum' # 改为求和
)
使用多个汇总函数
一个更强大的功能是,你可以为aggfunc参数传入一个函数列表,从而一次性计算多个统计量。
例如,如果你同时想了解每组的最小值、中位数和最大值,可以这样做:
pivot_multi = df.pivot_table(
index='number_of_children',
columns='is_software_dev',
values='hours_spent_learning_code',
aggfunc=['min', 'median', 'max'] # 传入函数列表
)
运行后,你将得到一个包含多级列索引的数据透视表,分别展示了每个特征组合下的最小值、中位数和最大值。这能提供比单一均值更丰富的数据分布信息。
总结
本节课中我们一起学习了如何使用Pandas的pivot_table方法进行多特征分群分析。

- 核心方法:
df.pivot_table(index, columns, values, aggfunc) - 应用场景:当你需要基于两个或更多类别特征对数据进行分组和汇总时。
- 关键参数:
index和columns:对应你想要分组的特征。values:你关心的结果数值。aggfunc:指定汇总函数,如‘mean’(默认)、‘sum’、‘std’、[‘min’, ‘max’]等。

数据透视表是进行多维数据探索和生成汇总报告的强大工具。掌握它,能让你更高效地从数据中发现有价值的模式和洞察。
至此,本模块关于数据读取、分析和可视化的核心内容已接近尾声。接下来,你将通过分级作业和实验来巩固所学。在实验中,你将有机会运用本模块学到的所有Python技巧,深入分析零售销售数据。
期待在下一个关于数据可视化的模块中与你再见!😊
044:数据可视化 📊
在本课程中,我们将学习如何使用Python进行数据可视化。数据可视化是将数据转化为图表的过程,它能帮助我们更直观地理解数据背后的故事。我们将重点掌握两个核心库:Matplotlib 用于创建高度自定义的图表,以及 Seaborn 用于制作更具视觉吸引力的统计图形。整个课程中,我们将通过分析一个真实的P2P贷款数据集,来帮助一家初创公司制定产品策略。
第一课:Matplotlib绘图基础 📈
上一段我们概述了本课程的目标,本节中我们来看看如何使用Matplotlib进行基础绘图。Matplotlib是Python中最基础的绘图库,它提供了强大的灵活性来创建各种类型的图表。
以下是本课将涵盖的核心内容:
- 学习创建美观的图表,包括柱状图(单个、分组和堆叠柱状图)以及散点图。
- 学习如何阅读链式方法,即在同一行命令中链接多个方法。
第二课:使用Seaborn提升图表美观度 🎨
掌握了基础的绘图方法后,本节我们将专注于使用Seaborn库来创建更具视觉吸引力的图表。Seaborn基于Matplotlib,提供了更高级的接口和精美的默认样式。
以下是本课将学习的技能:
- 通过设置样式和调色板来增强图表的美观度。
- 掌握专业统计图形的绘制,如箱线图、直方图等。
第三课:高级绘图技巧 🔄
在学习了单个图表的创建后,本节我们将发展同时绘制多个图表的技能。这在对比分析不同数据维度时非常有用。
以下是本课的核心内容:
- 学习绘制复合图表,包括叠加图表和并排图表。
- 学习使用高级循环技术,仅用几行代码即可创建多个图表。


在本节课中,我们一起学习了数据可视化的完整流程:从使用Matplotlib进行基础绘图,到利用Seaborn提升图表的视觉表现力,最后掌握了同时创建多个图表的高级技巧。课程结束后,你将能够创建具有专业质量的数据可视化作品,从而从数据中提炼出有意义的见解。
接下来,请跟随我进入第一课,开始使用Matplotlib模块探索绘图世界。我们课堂上见。
045:Python数据分析 第3课 - Matplotlib绘图 📊
概述
在本节课中,我们将要学习Python中最常用的可视化库之一——Matplotlib。我们将了解其核心概念,并通过一个实际的贷款数据分析案例,学习如何使用Matplotlib来创建和美化图表,从而更清晰地向客户展示数据分析结果。
Matplotlib简介
Python中最常用的可视化库之一是Matplotlib。程序员尤其看重其灵活性和高度可定制性。
Matplotlib是一个可视化模块,你可以将其导入到代码中。它允许你在Pandas创建的基础图表之上进行扩展,添加诸如标题、注释、颜色、坐标轴限制、标签格式化等自定义功能。与Pandas类似,Matplotlib包含了数十万行已为你编写好的代码。当你进行探索性数据分析或为报告开发精美的可视化图表时,你很可能会用到Matplotlib。


上一节我们介绍了Matplotlib的基本概念,本节中我们来看看它的核心组成部分。
Matplotlib可视化图表由几个核心组件构成。
- 图形(Figure):你可以将其想象为绘图的画布。一个图形可以容纳一个或多个绘图。它本质上是一个容器。
- 绘图(Axes):在Matplotlib中,绘图被称为“坐标轴”。每个坐标轴都有自己的一套绘图元素,如标签、数据、图例、网格等。

你可以直接创建一个图形,尽管这不是必须的。例如,你可能希望控制画布的大小或设置其他选项,如背景颜色。
以下是创建和定制图表的基本步骤:
- 使用不同的函数(如
plot、scatter、hist等)创建一组坐标轴,这些函数生成你认为是图形或图表的东西。 - 这些函数也有命名参数,你可以在其中指定用于绘图的数据以及该图表类型的数据墨水,如边界、标记、颜色、线条样式和其他参数。
- 然后,你还可以使用添加标题、X轴和Y轴标签、注释、图例等功能的函数,在图表上叠加额外的图表元素。
实战案例:贷款数据分析
现在,让我们通过一个实际案例来应用这些知识。你正在为一家希望通过新产品颠覆点对点借贷的初创公司工作。他们的计划是开发一种先进的风险管理策略,为美国各地的不同社区提供贷款。
你正在处理来自点对点借贷平台Lending Tree的贷款数据集,你可能在前面的课程中还记得它。你的任务是进行探索性数据分析,以更好地了解不同风险等级贷款的特征。你需要撰写一份包含你发现的报告,与银行分享。你的计划是开发富有洞察力的可视化图表,帮助你的客户理解不同的风险状况。毕竟,一图胜千言。

首先,从文件 loan_data.csv 中导入这个数据集。请记住,这行代码之所以有效,是因为CSV文件与你的笔记本文件位于同一文件夹中。在本课程的实验中,你不需要进行任何文件管理,但你应该能够解释这行代码为何有效。
import pandas as pd
loans = pd.read_csv('loan_data.csv')
数据整体看起来相当干净,列名格式良好。似乎没有唯一的标识符,因此你可以为此分析保留数值索引。


可视化贷款等级分布
首先可视化贷款等级,以便更好地了解整个贷款组合的构成。贷款被分配从A到G的等级,A级贷款的预期损失风险最低,通常利率也最低。
使用 pd.unique 函数检查 grade 列中出现的值。
pd.unique(loans['grade'])
要绘制不同贷款等级的频率,你可以使用 value_counts 方法创建一个包含数据集中每个等级计数的序列。然后使用 plot 方法并设置 kind='bar' 来创建图表。请记住,没有“柱状图”这种说法,在Pandas中,条形图就是柱状图。
grade_counts = loans['grade'].value_counts()
grade_counts.plot(kind='bar')


你可以看到B级贷款最常见,其次是C级,然后是A级,而E、F和G级的贷款只有少数几笔。这个可视化可能是一个很好的选择,可以帮助你的利益相关者了解整个投资组合中风险是如何平衡的。
然而,它的实用性可以显著提高。首先,grade 列是有顺序的。因此,适当地排序这些等级会很有帮助。
你可以使用 sort_index 方法,正如你可能猜到的,它按索引对数据进行排序。它很像 sort_values,只是它按索引排序。如果你在 value_counts 的结果(这是一个序列)上调用 sort_index 方法,你将按字母等级A到G对这个序列进行排序。将其保存到一个变量中,例如 sorted_grades,或者任何对你来说最有意义的名称。
sorted_grades = loans['grade'].value_counts().sort_index()
sorted_grades.plot(kind='bar')
现在,你得到了一个排序良好的图表,能更好地可视化等级的分布。因此,你的客户可能会得出结论,他们应该谨慎发放被评为E、F或G级的贷款,因为他们的竞争对手Lending Tree很少发放这类贷款。
使用Matplotlib增强图表



目前这是一个相当简陋的图表,你可以使用Matplotlib来增强它。首先,你需要导入 matplotlib.pyplot 作为 plt。请记住,as plt 创建了一个昵称,你通常会看到 plt 作为 matplotlib.pyplot 的别名。你可以在笔记本的任何位置添加导入命令,尽管你会看到许多程序员将它们分组放在顶部。只需确保你运行了它们。


你可以从之前相同的图表开始,现在为其添加更多图层。如果你看这个图表,这里已经有一个图形(或画布)供你绘图,并且已经有一个绘图。你可以使用例如 plot.title 命令来增强这个绘图。这个命令将在这个图表上叠加一个标题,几乎是作为另一个图层。
import matplotlib.pyplot as plt
sorted_grades.plot(kind='bar')
plt.title('Frequency of Loan by Grade')
你也可以使用 plt.xlabel 和 plt.ylabel 来标记你的坐标轴。“贷款等级”有点不言自明,也许标签是多余的,所以你可以添加一个空字符串('')来移除X轴标签。plt.ylabel 可以是“频率”。

请注意,当你运行这段代码时,你会得到一个标签清晰的图表,但你也会得到一行输出,写着“Text(…)”之类的。在使用Matplotlib时,你还需要添加 plt.show() 命令。这个命令明确告诉计算机显示绘图。

sorted_grades.plot(kind='bar')
plt.title('Frequency of Loan by Grade')
plt.xlabel('')
plt.ylabel('Frequency')
plt.show()
它有两个副作用。首先,它隐藏了你在Jupyter笔记本中得到的额外输出(显示单元格中的最后一个项目)。其次,它显示Matplotlib当前正在处理的绘图,然后从计算机内存中清除该绘图,以便你可以重新开始(如果你愿意的话)。因此,plt.show() 允许你在同一个单元格中显示多个绘图(如果需要的话)。在每个绘图后使用 plt.show() 是一个好习惯,可以使你的代码更易于阅读。
总结
本节课中我们一起学习了如何使用Matplotlib来增强数据可视化。
首先,我们通过选择想要在柱状图中绘制的数据并使用Pandas的 sort_index 方法对其进行排序来开始分析。
然后,我们学习了如何将Matplotlib命令叠加到图表上以增强可视化效果。我们导入了 matplotlib.pyplot 并使用了昵称 plt。接着,我们使用Pandas的 plot 方法创建了一个图表。之后,我们使用了Matplotlib的 xlabel、ylabel 和 title 函数来使我们的可视化更加清晰。


最后,我们学习了使用 plt.show() 函数来清理每个代码单元的输出。如果你希望在一个单元格中显示多个绘图,可以多次使用 plt.show()。
Matplotlib具有很大的实用性和强大的功能。它非常适合进行定制,而Pandas自带的简单可视化功能则非常适合快速将图表呈现在页面上。跟随我到下一个视频,看看柱状图的一些出色增强功能。
046:图表颜色、网格与保存 📊
在本节课中,我们将学习如何通过添加颜色和网格线来增强基础图表的可读性,并最终将图表保存为图像文件,以便用于报告或演示。
上一节我们介绍了如何创建和标注一个基础的柱状图。本节中,我们来看看如何通过颜色和网格等特性,让图表更具表现力和实用性。
为图表添加颜色 🎨



创建并标注好基础图表后,你可以使用颜色等附加功能来增强其可解释性。
假设你已导入数据、Pandas和Matplotlib,并创建了一个展示成绩频率的柱状图。现在,你想提升其可读性,并将此图表保存为图像添加到报告中。
你可以向 plot 方法添加额外的命名参数来美化图表。例如,如果你的客户品牌主色调是紫色,你可以为图表选择该颜色。
plot 方法有很多参数,你可以选择将每个参数放在单独一行以提高代码可读性,如下所示:


grades.plot(kind='bar',
color='purple')

color 参数有很多选项。你可以提供十六进制颜色代码,也可以使用任何HTML颜色名称。HTML颜色代码网站维护了一个可用颜色名称列表,例如 salmon(鲑鱼红)和 deep pink(深粉色)。

# 使用HTML颜色名称
grades.plot(kind='bar', color='salmon')
# 使用十六进制颜色代码
grades.plot(kind='bar', color='#FF6347')
color 参数也可以接受一个颜色列表。如果你能为这个图表选择一个渐变色,你会选什么?

一个从绿色到红色或从蓝色到橙色的渐变,可以为“贷款等级”添加双重编码,这很有用。要实现这一点,你可以创建一个颜色名称或十六进制代码的列表。
手动创建这样的列表可能有些繁琐,因此你可以向你的大语言模型(LLM)寻求帮助。
以下是向LLM提问的示例:“使用HTML颜色名称,创建一个包含七种颜色的Python列表,颜色需从绿色渐变到红色,中间经过橙色和黄色。”
然后,将生成的 colors 列表添加到你的笔记本中,并将 color 命名参数的值改为这个列表。
colors = ['green', 'chartreuse', 'yellow', 'gold', 'orange', 'darkorange', 'red']
grades.plot(kind='bar',
color=colors)


这个渐变色将帮助你的客户快速解读图表。


添加网格线 📐
你可能会注意到,对于靠右侧的柱状条,从Y轴读取数值有点困难。为了进一步提高图表的可读性,你可以添加网格线。
添加网格线非常简单,只需调用 plot.grid() 方法。
grades.plot(kind='bar', color=colors)
plt.grid()
grid 函数也有很多命名参数可供使用。首先,在X轴上显示网格线是多余的,因为柱状条的颜色和标签已经帮助观察者理解贷款等级。因此,你可以使用 axis='y' 参数来移除X轴的网格线。
plt.grid(axis='y')
这个函数的默认值是 'both',这就是为什么最初会显示两组网格线。你会发现Matplotlib函数的一个共同特点:几乎每个方面都可以自定义。
例如,你可能想让网格线颜色更深一些,比如黑色,但透明度(alpha)设为0.7。你也可以改变线条样式,虚线写作 '--'。

plt.grid(axis='y',
color='black',
alpha=0.7,
linestyle='--')
如果你想进一步自定义这个图表,随时可以向你的LLM寻求灵感。

保存图表为图像 💾


Matplotlib最后一个很酷的功能是,你可以使用 plot.savefig() 函数将图形保存到文件。
你唯一需要的参数是想要保存的文件名,包括文件扩展名(它指示了你保存的文件类型,如 .png 或 .jpeg 等)。
plt.savefig('loan_column_chart.png')
该图形将作为一个图像文件,保存在与你的笔记本相同的位置。
执行上述代码后,你就得到了一个精美的图像,可以将其包含在给客户的报告中。
课程总结 📝
本节课中我们一起学习了如何美化并保存Matplotlib图表。
- 使用颜色:你学会了使用
plot方法的color命名参数来指定图表颜色。你可以使用十六进制代码或HTML颜色名称(如salmon或mediumseagreen)作为color参数的值。 - 使用颜色列表:你还学会了如何使用颜色列表为每个柱状条赋予独立的颜色,并利用LLM来生成这样的列表。
- 添加网格线:你使用
plot.grid()为图表添加了网格线。axis参数允许你指定在X轴、Y轴或两者上都显示网格线。你还可以使用grid函数的命名参数来自定义线条样式、颜色等特性。 - 保存图像:最后,你学会了如何使用
plot.savefig()保存图像。该函数的参数是你想要使用的文件名,并且需要包含文件扩展名。我们使用了.png,但任何常见的图像格式都适用,如.jpeg、.svg、.pdf等。

现在,你已经创建了一个可读性显著提升的图表。在下一个视频中,我们将学习如何进一步提高图表中文本的清晰度,并添加文本注释。
047:Matplotlib 文本标注与美化
在本节课中,我们将学习如何通过调整文本样式和添加标注来提升 Matplotlib 图表的可读性与信息传达效果。我们将从基本的文本样式控制开始,逐步学习如何添加指向性标注和柱状图标签,最终使图表更加清晰、专业。
🎨 文本样式控制




上一节我们介绍了如何创建和自定义 Matplotlib 图表。本节中,我们来看看如何控制图表中文本元素的样式,例如标题和坐标轴标签。
对于标题、X轴标签、Y轴标签等文本元素,可以使用命名参数控制字体大小、粗细等属性。
以下是常用参数示例:
fontsize:控制字体大小,例如fontsize=16。fontweight:控制字体粗细,例如fontweight='bold'可使文本加粗。pad:为元素周围添加额外空间(内边距),例如pad=15。
代码示例:
# 设置标题样式
plt.title('Loan Grades Frequency', fontsize=16, fontweight='bold', pad=15)
# 设置Y轴标签样式
plt.ylabel('Frequency', fontsize=14)



应用这些样式后,图表文本的辨识度会显著提高。
📝 添加图表标注
调整好基础文本样式后,我们可以通过添加标注来突出图表中的关键信息,帮助观众理解数据背后的含义。
例如,在展示不同等级贷款频率的柱状图中,研究发现等级低于 D 的贷款违约风险极高。我们可以添加一个标注来说明这一点。
使用 plt.annotate() 函数添加标注。该函数包含多个参数,核心参数如下:




text:标注的文本内容。xy:标注所指向的数据点坐标(元组形式)。xytext:标注文本本身的坐标(元组形式)。textcoords:定义xytext参数的坐标系。
初始代码示例:
plt.annotate(text='Loans grade E and below\nare very high risk',
xy=(4, 50), # 指向第5个柱(E等级,索引为4),Y轴高度约50
xytext=(4, 50)) # 文本初始位置与指向点相同
此时标注文本可能会与数据柱重叠,影响可读性。
🎯 调整标注位置与箭头


为了使标注更清晰,我们需要将文本移动到合适的位置,并可以添加箭头指向具体数据点。



我们可以将 xytext 参数视为相对于 xy 点的偏移量,并通过设置 textcoords='offset points' 来明确这一点。同时,使用 arrowprops 参数添加箭头。

优化后的代码示例:
plt.annotate(text='Loans grade E and below\nare very high risk',
xy=(4, 50), # 指向点不变
xytext=(-10, 30), # 文本向左偏移10点,向上偏移30点
textcoords='offset points', # xytext 为偏移量
arrowprops=dict(arrowstyle='->', color='black')) # 添加黑色箭头
为了让标注更易读,还可以调浅网格线颜色:plt.grid(alpha=0.3)。

🔢 为柱状图添加数据标签




在柱状图中,一个常见的需求是在每个柱子的顶部显示其具体数值。这可以通过循环和 plt.text() 函数实现。
以下是实现方法:

- 遍历每个柱子的位置和高度。
- 在每个柱子的顶部中心位置添加文本标签。
代码示例:
# 假设 bars 是柱状图对象,heights 是各柱子高度
for i, height in enumerate(heights):
plt.text(x=i, # X坐标:柱子索引
y=height + 1, # Y坐标:柱子高度加一小段偏移
s=str(height), # 文本内容:高度值
ha='center', # 水平对齐方式:居中
va='bottom') # 垂直对齐方式:底部对齐
这样,图表就通过柱高和顶部标签实现了数据的“双重编码”,更加清晰直观。
📚 本节总结
本节课中我们一起学习了如何美化 Matplotlib 图表的文本并添加信息标注。


- 我们学习了使用
fontsize、fontweight、pad等参数控制标题、坐标轴标签的样式。 - 我们掌握了使用
plt.annotate()函数添加文本标注的方法,并通过xy参数指定标注点。 - 我们了解到可以使用
xytext和textcoords='offset points'将标注文本独立于标注点进行定位。 - 我们使用
arrowprops参数为标注添加了指向箭头。 - 我们学习了通过循环和
plt.text()为柱状图的每个柱子添加数据标签。
完成图表的文本标注和美化后,下一步是自定义坐标轴以更好地展示数据。让我们进入下一节课继续学习。
048:P48 - 自定义刻度与轴线

在本节课中,我们将学习如何使用Matplotlib自定义图表的边界,即通常所说的轴。我们将重点学习如何调整刻度标签、添加次要刻度、修改轴线(spines)以及创建更简洁、专业的图表。
概述:图表的边界与轴线
Matplotlib提供了多种选项来格式化图表的边界,这些选项包括对刻度和轴线的自定义。上一节我们创建了基础图表,本节中我们来看看如何通过调整这些元素来提升图表的可读性和美观度。
假设你正在处理一个简单的条形图,但对其旋转的X轴标签感到不满意。

你可以使用 plot.xticks 函数来调整这些标签。从设置 rotation=0 开始,这会让标签恢复水平显示,看起来更清晰。
保存图表对象以便后续修改
在之前LLM生成的代码中,图表被保存到了一个名为 ax 的变量中。这是一种在Matplotlib中非常常见的模式。
代码示例:
ax = df.plot(...) # 将绘图结果保存到变量ax中
ax 代表“坐标轴”。在Matplotlib中,一个Axes对象本质上就是一个单独的图表。这种策略允许你访问和修改正在处理的图表的特定属性和方法。
运行单元格后,图表会正常显示,但现在你可以更轻松地修改图表的各个方面。
添加次要刻度以增强可读性
如果你的客户需要从图表中读取更精确的数值,你可能希望在每1000个频率值处添加额外的刻度。



以下是添加次要刻度的步骤:
首先,从 matplotlib.ticker 模块导入 AutoMinorLocator 工具。这种导入方式只从模块中获取一个特定的项目。

代码示例:
from matplotlib.ticker import AutoMinorLocator

接着,使用你的图表对象 ax 来修改Y轴。你可以使用 ax.yaxis.set_minor_locator() 这个方法。
方法解析:
set_:表示你正在设置或改变轴上的某些内容,而不仅仅是获取信息。minor:指的是次要刻度标记。locator:意味着你想要改变信息显示的位置。
在这个方法中,你将使用 AutoMinorLocator(2) 作为参数,表示将每个主刻度区间分成两等份。
完整代码示例:
ax.yaxis.set_minor_locator(AutoMinorLocator(2))
尝试运行它,现在你得到了间距均匀的刻度线,其中较短的线就是次要刻度。

注意,新的次要刻度位置并没有自动生成网格线。如果你想为次要刻度也添加网格线,可以在 grid 函数中添加一个新的命名参数 which='both'。
代码示例:
ax.grid(which='both')
这将会同时为主刻度和次要刻度创建网格线。

寻求帮助:理解代码



当你遇到新代码时,可以随时向LLM(大型语言模型)寻求帮助来解释它。


例如,你可以提问:“用简单的语言逐行解释这段代码”,然后粘贴你的代码。LLM会从解释导入语句开始,然后逐一解释代码单元中的每一行。


创建极简主义图表:移除轴线和标签
现在,假设你正在处理一个更简约的图表,你可能想进一步修改它,移除这里的轴线(边界)以及Y轴标签。

你已经知道如何移除Y轴标签:只需将 ylabel 的值设置为空字符串。

代码示例:
ax.set_ylabel('')
要移除轴线(spines),请确保你的图表已保存为 ax 变量,然后使用 ax.spines。spines 代表图表的四个边界:left、right、top 和 bottom。

你可以像从数据框中选择列一样选择它们,并使用 .set_visible(False) 方法。

代码示例:
ax.spines['top'].set_visible(False) # 移除顶部轴线
运行此命令将移除顶部轴线。你可以对右侧和左侧轴线进行同样的操作。
代码示例:
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)


最后,还剩下这些刻度线。要移除它们,可以使用 ax.yaxis.set_ticks() 并传入一个空列表作为参数。空列表用一对空的方括号 [] 表示。
代码示例:
ax.yaxis.set_ticks([])
运行这些代码后,你将得到一个非常简洁的图表,有助于向利益相关者清晰地传达重要信息。




还有一件事,让我们把X轴标签旋转回水平方向。
代码示例:
ax.set_xticklabels(ax.get_xticklabels(), rotation=0)
总结
本节课中我们一起学习了如何精细控制Matplotlib图表的边界元素:
- 你学会了使用
plot.xticks方法来旋转X轴标签。 - 你学会了如何将绘图方法的结果保存到变量(通常称为
ax)中,以便后续修改图表的各个方面。 - 你可以使用这个
ax变量来访问图表的各个部分,如Y轴或轴线。 - 你使用了Matplotlib的
AutoMinorLocator工具为图表添加更多刻度,从而增强了图表的可读性。 - 你学会了如何提示LLM帮助你解释代码,以便更好地理解它。
- 最后,你使用了诸如
ax.spines[‘left’].set_visible(False)等命令来移除图表的轴线或外边界。

通过这些技巧,你已经能够创建外观更专业、信息更清晰的图表。

你已经学习了许多Matplotlib的功能。为了解锁更复杂的图表,你需要熟悉如何重塑数据,换句话说,即为绘图准备正确的行和列。请跟随下一个视频,学习如何使用分组柱状图来实现这一点。
049:分组柱状图教程
在本节课中,我们将学习如何使用Python的Pandas和Matplotlib库创建分组柱状图。分组柱状图允许我们在多个分类变量之间比较一个数值特征。我们将通过一个具体的案例,分析美国三个州(哥伦比亚特区、阿拉斯加和夏威夷)不同信用等级的贷款平均金额,来掌握这一可视化技巧。
概述
在探索性数据分析和可视化过程中,创建分组柱状图前需要先对数据进行适当的设置。本教程将引导你完成从数据筛选、分组聚合到最终绘制并美化图表的全过程。
数据准备步骤
以下是创建分组柱状图前需要完成的数据准备步骤。



-
筛选数据:首先,我们需要将数据框(DataFrame)筛选到只包含我们感兴趣的三个州。
states_of_interest = ['DC', 'AK', 'HI'] filtered_df = df[df['state'].isin(states_of_interest)] -
分组聚合:接下来,我们需要按“州”(state)和“信用等级”(grade)对数据进行分组,并计算每个分组的“贷款金额”(loan amount)的平均值。
grouped_data = filtered_df.groupby(['state', 'grade'])['loan_amnt'].mean()执行此操作后,我们会得到一个具有多级索引的Series。
-
数据重塑:为了正确绘制分组柱状图,我们需要使用
.unstack()方法将多级索引的第二层(grade)转换为列。unstacked_data = grouped_data.unstack()现在,数据框的索引是“州”,列是各个“信用等级”,单元格值是对应的平均贷款金额。
绘制基础图表
数据准备就绪后,我们可以开始绘制基础的分组柱状图。

unstacked_data.plot(kind='bar')
plt.show()
然而,直接绘制的图表在可读性上存在不足,例如图例位置不当、坐标轴标签不清晰等。
美化图表
上一节我们绘制了基础图表,本节中我们来看看如何通过添加标题、调整图例和坐标轴来美化它,使其更具可读性和专业性。





以下是美化图表的关键步骤:

- 添加标题和坐标轴标签:使用
plt.title()、plt.xlabel()和plt.ylabel()函数。 - 旋转X轴刻度标签:使用
plt.xticks(rotation=0)使标签水平显示。 - 调整图例位置:使用
plt.legend(bbox_to_anchor=(1.05, 1))将图例移动到图表右外侧,避免遮挡数据。 - 应用网格和颜色:使用
plt.grid(True)添加网格线,并使用合适的配色方案。
让我们将这些改进应用到图表上:
# 绘制分组柱状图
ax = unstacked_data.plot(kind='bar')

# 设置图表标题和坐标轴标签
plt.title('各州不同信用等级的平均贷款金额')
plt.xlabel('州')
plt.ylabel('平均贷款金额')


# 旋转X轴刻度标签为水平
plt.xticks(rotation=0)
# 将图例移动到图表右外侧
plt.legend(title='信用等级', bbox_to_anchor=(1.05, 1))
# 添加网格线
plt.grid(True, axis='y', linestyle='--', alpha=0.7)
# 显示图表
plt.tight_layout()
plt.show()


结果解读与保存
完成图表美化后,我们可以对可视化结果进行解读。


从生成的分组柱状图中,我们可以观察到一些有趣的模式:夏威夷(HI)的贷款模式与阿拉斯加(AK)和哥伦比亚特区(DC)明显不同。阿拉斯加和哥伦比亚特区主要以低风险(A级)贷款为主,而夏威夷则有大额但风险较高(如C、D级)的贷款。此外,哥伦比亚特区的A级贷款平均金额很高,这可能为你的客户提供了一个有利可图的策略线索。
最后,你可以使用plt.savefig()函数将图表保存为图片文件,以便将其包含在给客户的报告中。
plt.savefig('grouped_bar_chart.png', dpi=300, bbox_inches='tight')

总结
本节课中我们一起学习了创建分组柱状图的完整流程。
- 核心步骤:我们首先筛选了目标数据,然后按两个分类变量(州和信用等级)进行分组并计算均值,得到了一个具有多级索引的Series。
- 关键操作:为了正确绘图,我们使用了
.unstack()方法将多级索引的第二层转换为数据框的列,从而完成了数据重塑。 - 可视化与美化:我们使用
.plot(kind=‘bar’)绘制了基础图表,并通过添加标题、调整图例位置、设置坐标轴标签和网格线等方法美化了图表,使其更加清晰易懂。 - 公式/代码核心:整个过程的核心代码链可以概括为:
df[筛选].groupby([列1, 列2])[数值列].mean().unstack().plot(kind=‘bar’)。

分组柱状图是进行多维度对比的强大工具。掌握了它的创建方法后,学习堆叠柱状图将不再复杂,因为它们所需的数据准备工作是相似的。
050:Python数据分析(第3课)|堆叠柱状图

在本节课中,我们将学习如何创建堆叠柱状图。堆叠柱状图非常适合展示不同类别数据在总量中的构成比例。我们将从数据准备开始,逐步完成图表的创建与美化,并最终生成可用于报告的图表。
数据准备
上一节我们介绍了分组柱状图,本节中我们来看看堆叠柱状图。与分组柱状图类似,大部分工作在于数据准备。
假设我们想探索不同信用等级(grade)和房屋所有权状态(home ownership)下的贷款总额。这个分析有助于理解贷款风险状况是否会影响房屋所有权构成的差异。我们特别希望突出每个信用等级中租房者(RENT)的比例。
堆叠柱状图是理想的选择,因为它可以比较每个信用等级内部贷款金额的构成。
以下是创建堆叠柱状图所需的数据准备步骤:
- 导入必要的模块并读取数据。
- 按“grade”和“home_ownership”对数据进行分组。
- 选择“loan_amnt”列进行汇总。
- 使用
sum方法计算每个分组内的贷款总额。 - 使用
unstack方法将数据重塑为适合绘制的格式。
import pandas as pd
import matplotlib.pyplot as plt
# 读取数据
df = pd.read_csv('your_data.csv')
# 数据分组、聚合与重塑
stack_data = df.groupby(['grade', 'home_ownership'])['loan_amnt'].sum().unstack()
创建基础堆叠柱状图
数据准备完成后,创建堆叠柱状图就非常简单了。我们使用plot方法,并设置参数kind='bar'和stacked=True。

# 创建堆叠柱状图
stack_data.plot(kind='bar', stacked=True)
plt.show()

运行代码后,你将得到一个清晰的堆叠柱状图。从图中可以看出,“OWN”类别的占比最小,大多数客户拥有抵押贷款(MORTGAGE)。
美化图表

基础的图表已经能传达信息,但我们可以进一步修改它以提升可读性。
以下是美化图表的几个选项:
- 添加标题和轴标签:使图表意图更明确。
- 为不同类别设置颜色:突出显示“RENT”类别。
- 调整X轴刻度标签旋转角度:避免重叠。
- 为Y轴添加网格线:便于读取数值。
- 修改图例标题:使其更规范(如首字母大写)。
# 美化堆叠柱状图
ax = stack_data.plot(kind='bar', stacked=True, color=['#1f77b4', '#ff7f0e', '#2ca02c'])
# 设置标题和标签
ax.set_title('贷款总额构成(按信用等级与房屋所有权)')
ax.set_xlabel('信用等级 (Grade)')
ax.set_ylabel('贷款总额 (Loan Amount)')



# 调整X轴标签
ax.set_xticklabels(ax.get_xticklabels(), rotation=0)
# 添加网格线
ax.yaxis.grid(True, linestyle='--', alpha=0.7)
# 修改图例标题
ax.legend(title='房屋所有权', loc='upper left')
plt.tight_layout()
plt.show()
创建百分比堆叠柱状图


为了进行更直接的跨类别比较,我们可以创建百分比堆叠柱状图。在这种图表中,每个柱子的高度相同(100%),直观显示了各部分在组内的占比。
创建百分比堆叠柱状图需要进行数据标准化处理。我们可以借助大语言模型(LLM)来生成相关代码。

# 计算每个信用等级下各类别的百分比
percentage_data = stack_data.div(stack_data.sum(axis=1), axis=0) * 100
# 创建百分比堆叠柱状图
ax = percentage_data.plot(kind='bar', stacked=True, color=['#1f77b4', '#ff7f0e', '#2ca02c'])
ax.set_title('贷款总额构成百分比(按信用等级)')
ax.set_xlabel('信用等级 (Grade)')
ax.set_ylabel('构成比例 (%)')
ax.set_xticklabels(ax.get_xticklabels(), rotation=0)
ax.yaxis.grid(True, linestyle='--', alpha=0.7)
# 将图例移到图表外部
ax.legend(title='房屋所有权', bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
plt.show()

从生成的百分比堆叠图中,你可能会注意到租房者(RENT)的比例在A、B等级中相对稳定,但在C和E等级中有所增加。这可以为你的客户提供关于不同等级贷款客户可能拥有的抵押品类型的洞察。
保存图表
最后,将制作好的图表保存为图片文件,以便插入到报告中。
# 保存图表为PNG格式
plt.savefig('stacked_bar_chart.png', dpi=300, bbox_inches='tight')

课程总结
本节课中我们一起学习了堆叠柱状图的创建与应用。
- 我们了解到,在
plot方法中设置参数stacked=True即可创建堆叠柱状图而非分组柱状图。当我们的目标是比较类别内部的构成而非跨类别比较时,这种图表非常有用。 - 我们完成了从数据分组、聚合到绘制和美化堆叠柱状图的完整流程。
- 我们还借助大语言模型创建了百分比堆叠柱状图,这使得跨不同类别的比较变得更加容易。
现在,通过对柱状图的深入学习,你已经掌握了在Python中创建美观且功能强大的可视化图表所需的大部分工具。然而,我们还需要掌握散点图、箱线图和直方图,它们各自都有独特的选项和用途。请跟随我进入下一个视频,学习如何创建散点图。
051:使用Matplotlib绘制散点图 📊
在本节课中,我们将学习如何使用Matplotlib库创建高度定制化的散点图,以探索数据集中特征之间的关系。我们将从基础绘图开始,逐步添加标题、坐标轴标签,并学习如何调整标记样式、透明度以及设置坐标轴范围。最后,我们还会学习如何在图表中添加参考线来突出显示特定数据部分。
创建基础散点图
上一节我们介绍了数据分析的背景,本节中我们来看看如何创建散点图。假设你已经研究了数据集中多个特征之间的相关性,并发现年收入与总信用额度之间存在中等程度的正相关关系(皮尔逊相关系数为0.55)。为了帮助客户理解其客户的收入分布如何影响应提供的信用额度,散点图是一个合适的图表类型,因为它可以可视化两个数值特征之间的关系。
以下是创建基础散点图的步骤:
- 导入必要的模块并读取数据。
- 使用
plt.scatter()函数,并传入两个参数:df['annual_income']和df['total_credit_limit']。 - 调用
plt.show()来显示图表。


import matplotlib.pyplot as plt
import pandas as pd
# 假设df是包含数据的DataFrame
plt.scatter(df['annual_income'], df['total_credit_limit'])
plt.show()

执行上述代码后,你将看到一个基础散点图,它展示了年收入与总信用额度之间的关系。
增强图表可读性

基础图表通常需要增强可读性。我们可以添加标题和坐标轴标签,让图表传达的信息更清晰。
以下是增强图表可读性的方法:

- 使用
plt.title()添加图表标题。 - 使用
plt.xlabel()和plt.ylabel()添加X轴和Y轴标签。
plt.scatter(df['annual_income'], df['total_credit_limit'])
plt.title('年收入 vs. 总信用额度')
plt.xlabel('年收入')
plt.ylabel('总信用额度')
plt.show()
自定义散点标记


对于像本例这样包含超过3000个数据点的密集图表,我们可以通过调整标记的透明度和样式来改善可视化效果。

以下是自定义散点标记的选项:
- 透明度 (
alpha):设置为0.5可以让你更清楚地看到数据点更密集的区域。 - 标记样式 (
marker):默认是圆形 (‘o’)。你可以使用‘^’表示三角形,‘.’表示点,或者‘8’表示八边形(仅用于示例,可能不清晰)。
# 使用三角形标记并设置透明度
plt.scatter(df['annual_income'], df['total_credit_limit'], alpha=0.5, marker='^')
plt.title('年收入 vs. 总信用额度 (三角形标记)')
plt.xlabel('年收入')
plt.ylabel('总信用额度')
plt.show()
调整坐标轴范围(缩放)


观察图表,你会发现大部分数据点集中在左下角,只有少数异常值分布在远处。为了更清晰地观察主要数据集群,我们可以调整坐标轴的范围。



使用 plt.xlim() 和 plt.ylim() 函数可以设置X轴和Y轴的显示范围,这相当于对图表的特定区域进行缩放。
重要提示:在设置范围时,务必注意数据的实际单位。例如,如果X轴标签显示为 1e6(科学计数法,表示1,000,000),那么设置 plt.xlim(0, 0.5) 实际上是在查看0到0.5美元之间的数据,这会导致图表空白。正确的做法是理解数据单位后设置合适的范围。
# 假设我们想查看年收入在0到50万美元之间的数据
plt.scatter(df['annual_income'], df['total_credit_limit'], alpha=0.5)
plt.xlim(0, 500000) # 设置X轴范围
plt.title('年收入 vs. 总信用额度 (缩放视图)')
plt.xlabel('年收入')
plt.ylabel('总信用额度')
plt.show()

添加参考线


假设我们特别关注收入分布中前5%的客户。我们可以在散点图上添加一条垂直参考线,直观地将这部分客户与其他客户区分开来。
以下是添加垂直参考线的步骤:
- 计算数据集中年收入列的95%分位数,这个值代表了前5%收入的起始点。
- 使用
plt.axvline()函数在计算出的值处绘制一条垂直线。 - 可以通过参数(如
color=’black’,linestyle=’—‘)自定义线条的样式。
# 计算年收入的前5%分界点
top_5_percent_income = df['annual_income'].quantile(0.95)
plt.scatter(df['annual_income'], df['total_credit_limit'], alpha=0.5)
plt.axvline(x=top_5_percent_income, color='black', linestyle='--', label='前5%收入分界线')
plt.title('年收入 vs. 总信用额度 (含前5%分界线)')
plt.xlabel('年收入')
plt.ylabel('总信用额度')
plt.legend()
plt.show()
补充:如果你想添加一条水平参考线,可以使用 plt.axhline() 函数。

总结
本节课中我们一起学习了如何使用Matplotlib创建和定制散点图。我们首先使用 plt.scatter() 函数创建了基础图表,然后通过添加标题和坐标轴标签增强了可读性。接着,我们探索了如何通过 alpha 参数控制标记透明度,以及通过 marker 参数改变标记样式。为了聚焦于主要数据,我们学习了使用 plt.xlim() 和 plt.ylim() 来调整坐标轴范围。最后,我们使用 plt.axvline() 在图表中添加了垂直参考线来突出显示特定数据分区(对应的水平线函数是 plt.axhline())。
由于散点图涉及大量的定制化和数据操作,创建高质量的散点图通常需要编写多行代码,但最终的成果是值得的。
052:方法链式调用 🔗

在本节课中,我们将要学习一个在Python数据分析中非常常见且高效的编程技巧——方法链式调用。我们将通过类比数学运算和分解代码步骤,来理解如何将多个操作串联起来,以及这种方式的优缺点。
在之前的几节视频中,你看到了一些涉及连续调用多个方法的长代码行。

随着你继续使用Python,你会经常看到这种被称为“方法链式调用”的策略。
为了理解链式调用,我们先来看一个数学表达式,你会如何计算它?
(5 + 3) * 2 - 4 / 2

你需要完成四个运算。你必须先解决加法运算,然后才能进行其他操作。所以,5加3等于8。你简化了这个表达式,现在可以继续乘法运算:8乘以2等于16。同样,你又解决了一个复杂度层级,现在可以减去4得到12,再除以2得到最终结果6。
在代码中,这种将多个操作串联起来的过程,其中每个操作都依赖于前一个操作的结果,就称为方法链式调用。之所以称为“链式”,是因为你将操作像链条中的环节一样连接起来,每一环都依赖于前一环。

上一节我们介绍了链式调用的基本概念,本节中我们来看看一个具体的代码示例。
让我们一起来分解这行你在之前关于堆叠条形图的视频中看到的代码。当你阅读和理解这行代码时,请从左到右思考,并尝试关注数据类型。
df.groupby(['grade', 'home_ownership'])['loan_amnt'].sum().unstack().plot(kind='bar', stacked=True)
这行代码的全部目的是获取一些数据,对其执行一系列命令,并最终得到某种结果——在本例中是一个可视化图表。你从最左边的数据类型(一个数据框df)开始,以最右边命令的输出(一个图表plot)结束。
这行代码包含四个步骤,每一步都需要在进入下一步之前完成。
以下是每个步骤的详细分解:
第一步:按指定列分组
输入是数据框df和要分组的列名列表[‘grade‘, ‘home_ownership‘]。
输出是一个GroupBy对象,其结构类似于按grade和home_ownership分组后的数据框。例如,有5个等级和3种房屋所有权类别,总共形成15个组。
第二步:选择特定列
输入是上一步的GroupBy对象。
输出是一个GroupBy Series,即仅包含loan_amnt列并按那两个列分组的数据。此时你仍然看不到这个数据结构,直到你对其进行聚合。
第三步:对每个组进行聚合计算
输入是上一步的GroupBy Series。
输出是一个Series。这个Series有15行,并使用一个多级索引(MultiIndex)——由一对值作为索引。对于每个多级索引值,你都有该组所有贷款的总金额。
第四步:重塑数据格式
使用.unstack()方法将数据转换为行和列的形式,而不是多级索引。
输入是上一步带有多级索引的求和Series。
输出是转换为行列表格形式的求和结果。
第五步:创建可视化图表
输入是上一步的Series。
输出是一个可以显示的堆叠条形图。
每一步都接收上一步的数据并对其进行进一步转换。
上一节我们分解了链式调用的步骤,本节中我们来看看实现同一目标的另一种写法。
你也可以使用变量来分步编写这段代码:
grouped_data = df.groupby(['grade', 'home_ownership'])
grouped_loan_amount = grouped_data['loan_amnt']
sum_of_loans = grouped_loan_amount.sum()
unstacked_sums = sum_of_loans.unstack()
unstacked_sums.plot(kind='bar', stacked=True)
如果你需要为后续步骤保存这些中间结果,所有这些变量都可能有用。例如,你可能想计算每个组的贷款金额的中位数和标准差。


但并非每次都需要保存这些中间步骤。
我们可以将方法链式调用比作乘坐特快列车。在这种情况下,从数据框df直达图表plot。你买票(写代码),在数据框站上车,直接到达目的地——图表站。如果你只是想尽快得到图表,这很棒。但这种方法灵活性较低,因为如果你后来意识到想在中间站下车(使用中间结果),你将无法做到。
而使用变量的方法更像是每站都停的慢车。它更灵活,但耗时更长。你可以在任何需要的站点下车,例如,如果你想计算每个组贷款金额的中位数和标准差。但如果你不需要在任何地方停留,方法链式调用可以快速完成任务。
链式方法起初可能难以阅读,但你用得越多,就越能理解它们。它们可以使你的编码快速高效,尤其是在你不需要存储中间结果的情况下。
本节课中我们一起学习了方法链式调用。我们通过类比数学运算理解了其核心思想,即像链条一样连接依赖的操作。我们分解了一个实际代码示例,了解了每一步的数据转换过程。最后,我们对比了链式调用(特快列车)与分步变量赋值(慢车)的优缺点:前者高效直接,后者灵活可控。
掌握这一技巧将帮助你编写更简洁、更高效的数据分析代码。


接下来,请完成本课的练习作业和实践实验室。
完成后,欢迎进入下一课,学习使用流行的Python库Seaborn创建更美观的可视化图表和分布图。
053:Python数据分析(第3课)|Python for Data Analytics
课程编号:P53 - Seaborn可视化 📊
在本节课中,我们将要学习一个强大的数据可视化工具——Seaborn。我们将了解它的主要优势,并通过与Matplotlib的对比,掌握如何使用Seaborn快速创建美观且信息丰富的图表。
概述
到目前为止,你已经接触了多种图表,并学习了如何使用Matplotlib为这些图表进行自定义设置。现在,你需要学习另一个数据可视化工具:Seaborn。Seaborn是一个可以导入到代码中的可视化工具,它与Matplotlib配合良好。它的主要优势在于提升视觉吸引力、简化数据分组与汇总操作,以及提供Matplotlib中没有的额外图表类型。
Seaborn的优势
上一节我们介绍了Seaborn的基本概念,本节中我们来看看它的具体优势。Seaborn在以下两个方面特别出色:
- 提升视觉吸引力:Seaborn的默认样式比Matplotlib更美观。
- 简化数据操作:它内置了数据分组和汇总功能,无需手动预处理。
- 提供额外图表类型:它包含一些Matplotlib中没有的、更高级的图表。


对比:Matplotlib vs. Seaborn
为了直观感受Seaborn的强大,让我们比较一下在Matplotlib和Seaborn中创建分组条形图的差异。
首先,在一个新的笔记本中导入所有必要的模块:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns # Seaborn的常用昵称
import numpy as np
然后,读取数据并筛选出我们感兴趣的三个州的数据:
df = pd.read_csv('your_data.csv')
filtered_df = df[df['state'].isin(['CA', 'NY', 'TX'])]
使用Matplotlib创建分组条形图,需要大量数据操作:
# 需要手动分组、聚合和调整数据格式
grouped = filtered_df.groupby(['state', 'grade'])['loan_amnt'].mean().unstack()
grouped.plot(kind='bar')
plt.show()


这种方法有两个令人困扰的地方:图表不够美观,并且需要大量繁琐的数据操作才能生成这种常见的图表。

使用Seaborn创建相同的图表则简单得多:
sns.barplot(data=filtered_df, x='state', y='loan_amnt')
plt.show()
代码 sns.barplot(data=filtered_df, x='state', y='loan_amnt') 直接使用原始数据框,Seaborn会自动计算每个州的平均贷款金额并绘制条形图,无需预先分组。
添加分组维度(Hue参数)
上面的图表展示了各州的平均贷款额。如果我们还想按贷款等级(grade)进一步细分,该怎么办呢?在Seaborn中,这非常简单。



以下是使用hue参数添加分组的方法:
sns.barplot(data=filtered_df, x='state', y='loan_amnt', hue='grade')
plt.title('Average Loan Amount by State and Grade')
plt.xlabel('State')
plt.ylabel('Average Loan Amount')
plt.legend(title='Grade', bbox_to_anchor=(1.05, 1), loc='upper left') # 将图例移到图表外
plt.show()
参数 hue='grade' 告诉Seaborn使用颜色来区分不同的贷款等级。这样,我们就得到了一个带有误差条和标签的、外观精美的分组条形图。这就是Seaborn的力量:以极少的努力获得非常美观的图表。
结合Matplotlib进行自定义
由于Seaborn构建在Matplotlib之上,因此可以完美地结合两者的命令。你可以像上面例子中那样,在Seaborn绘图后,继续使用Matplotlib的plt.title()、plt.xlabel()、plt.ylabel()等函数来添加或修改图表元素。



快速尝试其他度量和图表
Seaborn的设置也使得快速尝试其他度量指标变得容易。例如,如果你想可视化利率而不是贷款金额,只需更改y参数:


sns.barplot(data=filtered_df, x='state', y='int_rate', hue='grade')
plt.show()
默认情况下,barplot函数绘制的是均值(np.mean)。但你可以使用其他估计量(estimator)。
以下是更改估计量的方法:
# 使用最大值作为估计量
sns.barplot(data=filtered_df, x='state', y='int_rate', hue='grade', estimator=np.max)
# 使用数据点数量作为估计量
sns.barplot(data=filtered_df, x='state', y='int_rate', hue='grade', estimator=len)
你可以使用np.max、np.std(标准差)或len(计数)等。选择哪种估计量取决于你希望向客户传达什么信息。
Seaborn的核心能力总结
本节课中我们一起学习了Seaborn的核心能力,让我们来总结一下:


- 提供额外的绘图函数:如
barplot、lineplot、regplot等。 - 自动数据汇总:无需手动进行
groupby和汇总步骤,默认使用np.mean。 - 灵活的估计量:可以通过
estimator参数轻松切换为np.max、np.size、np.std等。 - 美观的默认样式:快速生成具有专业外观的图表。
总而言之,Seaborn的核心价值在于:它能让你在快速创建美观图表的同时,省去将数据精细处理成合适格式的麻烦。在接下来的视频中,你将学习如何进一步自定义图表的外观。

总结:本节课我们介绍了数据可视化库Seaborn。我们学习了它的主要优势,并通过实例对比了其与Matplotlib在创建分组条形图时的差异。我们掌握了使用barplot函数和hue参数来创建分组图表,以及如何结合Matplotlib命令进行自定义和切换不同的数据估计量。Seaborn是一个能极大提升数据分析效率和图表美观度的强大工具。
054:Python数据分析 - P54 主题与调色板 🎨
在本节课中,我们将学习如何使用Seaborn库来美化数据可视化图表。我们将重点掌握两个核心工具:主题和调色板。通过它们,你可以轻松地改变图表的默认样式和颜色方案,从而创建出更具视觉吸引力和专业感的图表。
概述
上一节我们介绍了如何创建基础的柱状图。本节中,我们来看看如何通过调整主题和调色板来提升图表的视觉效果。我们将使用一个关于各州贷款平均利率的图表作为示例,并逐步对其进行美化。
设置主题
在样式和颜色方面,Seaborn比Matplotlib提供了更多开箱即用的选项。你用于样式化的两个主要工具是主题和调色板。
首先,你可以使用Seaborn的 set_theme 函数。这个函数只需调用一次,之后创建的所有图表都会应用这个主题设置。你仍然可以修改图表的其他方面,本质上你只是选择了一套不同的默认样式。

假设你已经导入了必要的模块并将数据读取到了名为 df 的DataFrame中。同时,你已经基于之前的视频内容,创建了一个展示“贷款金额最高州”的“各信用等级平均利率”图表。



为了提升其视觉吸引力以便纳入报告,第一步就是设置主题。


import seaborn as sns
sns.set_theme()
调用 set_theme() 后,再创建与之前相同的图表,你会发现它的外观已经改变了。每个柱状图现在都有了白色边框,整个图表背景颜色更深,坐标轴线(spines)变为白色或不可见。这是一个非常棒的主题。
请注意,如果你在新的代码单元中再次创建同一个图表,这个主题设置依然有效。
调整样式
set_theme 函数有一个名为 style 的参数,允许你为图表选择更合适的样式。
如果你想将主题重置回Matplotlib的基础样式,可以将 style 参数设置为 'white'。对于像分组柱状图这样信息密集的图表,'white' 样式是一个很好的选择。
sns.set_theme(style='white')
使用调色板
你也可以改变图表中的颜色方案,这是Seaborn最酷的功能之一。目前,你的图表使用的是包含多种不同颜色的分类调色板。

但是,一个像之前用过的从绿色到红色的渐变调色板,能更好地强调这张图表中的洞察。



你需要在绘图函数中添加一个名为 palette 的参数。这个参数的值应该是一个颜色调色板的名称。Seaborn提供了大量可用的调色板,但你需要查询它们的名称。


例如,在“实用Python数据科学”网站上列出了可用的调色板。你有诸如 'Blues' 或 'Blues_r'(反向)等选项。



现在,尝试将 'blues' 调色板添加到你的代码中。


# 示例代码,假设绘图函数是 barplot
sns.barplot(x='grade', y='int_rate', hue='addr_state', data=df, palette='blues')
运行后你可能会遇到一个错误,得到一个空白图表和 ValueError: 'blues' is not a valid palette name 的提示。

让我们向大语言模型(LLM)咨询一下。我认为 'blues' 是一个有效的调色板名称。

大语言模型会告诉你,这个错误很可能是因为大小写敏感问题。正确的调色板名称是 'Blues',首字母B需要大写。
所以,让我们将 'blues' 改为 'Blues':
sns.barplot(x='grade', y='int_rate', hue='addr_state', data=df, palette='Blues')


现在图表看起来很棒了!请记住,计算机通常对大小写很敏感。如果你遇到错误,可以随时向LLM寻求调试帮助。
'Blues' 看起来不错,但作为一个顺序调色板,它不如一个包含从绿色到红色多种颜色的调色板那样能突出关键洞察。
要获得之前那种从绿到红的效果,你可以使用 'RdYlGn_r' 调色板(Red-Yellow-Green反向)。
sns.barplot(x='grade', y='int_rate', hue='addr_state', data=df, palette='RdYlGn_r')


其他选项包括,如果你需要制作色盲友好的图表,可以使用从紫色到黄色的 'plasma' 调色板,或者从蓝色到橙色的 'icefire' 调色板。
我们暂时坚持使用 'RdYlGn_r' 调色板。现在,这个图表就可以分享给你的客户了。他们可以利用它来理解在这三个贷款平均金额最高的州中,利率是如何变化的。
总结
本节课中我们一起学习了如何使用Seaborn美化图表。
- 我们首先介绍了
sns.set_theme()函数,用于改变图表的默认样式。 - 接着,我们探讨了如何使用
style参数选择样式,其中style='white'可以将图表恢复为默认的Matplotlib外观。 - 最后,我们重点学习了调色板的使用。通过
palette参数,并选择如'Blues'、'RdYlGn_r'等选项,我们可以显著提升图表的美学效果。
使用调色板可以避免为图表手动选择颜色的麻烦。创建如此具有视觉吸引力的图表可以带来很多乐趣,Seaborn非常适合进行各种实验。

请跟随我进入下一个视频,学习如何从箱线图开始,创建视觉冲击力强的分布图。
055:使用Seaborn绘制箱线图 📊
在本节课中,我们将学习如何使用Seaborn库创建箱线图。箱线图是探索性数据分析中一种强大的工具,它能直观地展示数据的分布情况,包括中位数、四分位数和异常值。与Matplotlib相比,Seaborn使创建箱线图变得更加简单。
概述与数据准备
上一节我们介绍了数据可视化的重要性。本节中,我们来看看如何使用Seaborn绘制箱线图来探索数据分布。
我们使用的数据集包含个人特征(如职业和贷款历史)以及贷款特征(如贷款金额和利率)。在开始之前,我们已经导入了必要的模块并将数据读取到了名为df的DataFrame中。


绘制基础箱线图



Seaborn的sns.boxplot()函数使得创建箱线图非常容易。以下是创建一个基础箱线图的步骤。
首先,假设我们想查看数据集中所有贷款的利率分布。我们可以使用sns.boxplot()函数,并指定数据源和要绘制的变量。
以下是绘制利率水平箱线图的代码:
sns.boxplot(data=df, x='interest_rate')
plt.show()








生成的图表显示了利率的偏态分布,中位数利率约为12%。这个分布图有助于我们理解这些贷款的典型利率水平。
调整箱线图方向与添加标签
箱线图可以是水平或垂直的,这主要取决于个人偏好和展示需求。
如果将变量赋值给y参数,则会得到一个垂直的箱线图。在解读上,两者没有本质区别。
sns.boxplot(data=df, y='interest_rate')
为了提升图表的可读性,我们通常需要添加标题和轴标签。
plt.title('Distribution of Loan Interest Rates')
plt.ylabel('Interest Rate (%)')







自定义图表样式:移除边框
在单个垂直箱线图中,X轴通常没有具体含义,移除不必要的边框可以使图表更简洁,提高“数据-墨水比”。
Seaborn提供了sns.despine()函数来轻松移除图表边框。默认情况下,它会移除顶部和右侧的边框。
sns.despine()
如果想移除底部边框,可以设置参数bottom=True。这里的True表示“同意移除”。
sns.despine(bottom=True)
应用后,图表会变得更加清晰,去除了不必要的边界。
绘制分组箱线图
箱线图的一个强大功能是可以按另一个变量进行分组,以比较不同类别间的分布差异。
例如,我们可以按贷款等级来分段查看利率分布,只需在boxplot函数中同时指定x和y参数。
sns.boxplot(data=df, x='grade', y='interest_rate')







从图中可以清晰地看到,利率随着贷款等级下降而显著上升。A级贷款的利率在个位数,而E、F、G级贷款的利率则在20%左右。这种图表可以帮助客户理解不同风险等级贷款的盈利情况。
由于此时X轴(贷款等级)包含重要信息,我们应该恢复底部边框。
sns.despine(bottom=False) # 或直接不设置bottom参数
进一步美化:添加网格与调色板
为了使一系列图表风格统一,便于客户阅读,我们可以添加Y轴网格线。
plt.grid(axis='y', alpha=0.5)
我们还可以为不同组别分配颜色。为了保持与之前图表的一致性,可以使用相同的调色板。
sns.boxplot(data=df, x='grade', y='interest_rate', palette='RdYlGn_r')



注意:你可能会看到一个关于
palette参数的警告。这不是错误,而是模块开发者的提示,表明未来版本中某些用法可能会改变。在当前版本,如果同时使用x和palette参数,可能会收到警告。你可以尝试使用hue参数来代替x进行分组,但这样可能会使图例仅靠颜色区分,降低可读性。因此,根据你的Seaborn版本,可以选择保留x参数。



调整图表尺寸


当图表中包含大量信息时,增大图表尺寸可以提升可读性。我们可以在创建图表之前使用plt.figure()来设置画布大小。
plt.figure(figsize=(8, 6)) # 宽度和高度,单位为英寸
sns.boxplot(data=df, x='grade', y='interest_rate')
默认的图形尺寸约为6.4 x 4.8英寸(约16 x 12厘米)。将尺寸设置为8 x 6英寸是一个不错的增大选择。







总结 📝
本节课中我们一起学习了如何使用Seaborn创建和定制箱线图。
以下是本课的核心要点总结:
- 创建箱线图:使用
sns.boxplot(data=df, x='column')或sns.boxplot(data=df, y='column')来创建水平或垂直箱线图。 - 分组比较:通过同时设置
x和y参数,可以按另一个变量(如grade)分段查看分布。 - 简化边框:使用
sns.despine()可以移除图表的顶部和右侧边框,使用bottom=True等参数可以移除其他边框。 - 调整尺寸:在绘图前使用
plt.figure(figsize=(width, height))可以调整图表的整体大小,尺寸单位为英寸。


箱线图是可视化数据分布的重要工具之一。在接下来的课程中,我们将学习如何在Seaborn中创建直方图,这是另一种分析数据分布的强大方法。
056:Python数据分析(第3课)|直方图绘制教程
在本节课中,我们将学习如何使用Seaborn库绘制直方图,以可视化数据特征的分布情况。直方图是数据分析中常用的图表类型,能够帮助我们快速识别数据中的模式和异常。
🎯 概述:直方图的基本概念
直方图是一种用于展示数据分布的图表类型。它通过将数据分成多个区间(称为“箱”或“bin”),并统计每个区间内数据点的数量,从而形成一系列柱状图。直方图特别适用于观察数据的集中趋势、离散程度以及异常值。
在数据分析中,直方图常用于探索性数据分析(EDA),帮助分析师理解数据的整体特征。例如,在贷款数据中,直方图可以揭示贷款金额的常见区间和频率分布。


📈 绘制基础直方图

上一节我们介绍了直方图的基本概念,本节中我们来看看如何使用Seaborn绘制一个基础的直方图。Seaborn库提供了简洁的API,能够生成美观的图表,并且可以与Matplotlib结合使用进行进一步的自定义。

假设我们已经导入了必要的模块并读取了数据,数据存储在变量df中。我们想要可视化“贷款金额”这一特征的分布情况。
以下是绘制基础直方图的步骤:
- 导入Seaborn和Matplotlib库。
- 使用
sns.histplot()函数,并指定数据框和要绘制的列。 - 调用
plt.show()显示图表。
对应的代码如下:
import seaborn as sns
import matplotlib.pyplot as plt
# 假设df是包含数据的数据框
sns.histplot(data=df, x='loan_amount')
plt.show()

执行上述代码后,你将得到一个展示贷款金额分布的直方图。从图中可以观察到,频率的峰值出现在一些整数值上,例如10,000、20,000、25,000等。这种模式值得进一步研究,以帮助客户理解不同金额贷款背后的心理因素和市场需求。

🎨 自定义直方图外观
基础图表已经能够展示数据分布,但为了提升可读性和专业性,我们通常需要添加标题、坐标轴标签和网格线,并调整颜色。
以下是自定义直方图外观的步骤:
- 使用
plt.title()添加图表标题。 - 使用
plt.xlabel()和plt.ylabel()设置坐标轴标签(本例中可以移除Y轴标签,因为它通常不言自明)。 - 使用
plt.grid(True)添加网格线。 - 在
sns.histplot()中使用color参数更改柱子的颜色。
对应的代码如下:
sns.histplot(data=df, x='loan_amount', color='rosybrown')
plt.title('贷款金额分布直方图')
plt.xlabel('贷款金额')
plt.ylabel('频率')
plt.grid(True)
# 移除Y轴标签,因为“频率”通常不需要特别标注
plt.gca().set_ylabel('')
plt.show()


通过这些调整,图表变得更加清晰易懂,便于向客户展示关键信息。


⚙️ 调整箱体(Bins)参数
为了更清晰地显示数据中的峰值(例如5,000处的峰值),我们可以调整直方图的箱体(bins)参数。箱体决定了数据被分成的区间数量和宽度。
以下是调整箱体参数的两种方法:
- 设置箱体数量:使用
bins参数,例如bins=30,将数据分成30个等宽的区间。 - 设置箱体宽度:使用
binwidth参数,例如binwidth=5000,指定每个箱体的宽度为5000美元。注意:binwidth参数会覆盖bins参数,两者只需使用一个。
对应的代码如下:
# 方法一:设置箱体数量
sns.histplot(data=df, x='loan_amount', bins=30, color='rosybrown')
plt.title('贷款金额分布 (30个箱体)')
plt.xlabel('贷款金额')
plt.grid(True)
plt.show()
# 方法二:设置箱体宽度
sns.histplot(data=df, x='loan_amount', binwidth=5000, color='rosybrown')
plt.title('贷款金额分布 (箱体宽度: $5,000)')
plt.xlabel('贷款金额')
plt.grid(True)
plt.show()

设置箱体宽度后,图表的可解释性更强,因为每个箱体代表一个明确的金额范围。例如,客户可以轻松看出5,000到10,000美元范围内的贷款数量大约是20,000到25,000美元范围的两倍。


🔧 解决主题样式导致的显示问题
在使用Seaborn的某些主题样式时,你可能会遇到坐标轴刻度线不显示的问题。这是一个由主题设置引起的常见视觉问题,并非代码错误。
解决方法是使用Seaborn的set_style()函数来调整主题组件。要显示刻度线,可以运行以下代码:
sns.set_style("ticks")
运行这行代码后,再重新绘制图表,X轴和Y轴的刻度线就会正常显示。这个例子说明,作为数据分析师,除了会使用工具,还需要具备一定的库知识来解决问题。与AI协作是过程,但理解底层原理同样重要。

📊 添加核密度估计(KDE)曲线


除了观察频率分布,我们有时还想了解数据的概率密度分布。这时可以在直方图上叠加一条核密度估计(Kernel Density Estimate, KDE)曲线。
KDE曲线通过平滑技术估计数据的概率密度函数,帮助我们洞察整个分布范围内的相对概率。
添加KDE曲线非常简单,只需在sns.histplot()函数中设置参数kde=True即可。
对应的代码如下:
sns.histplot(data=df, x='loan_amount', binwidth=5000, color='rosybrown', kde=True)
plt.title('贷款金额分布与密度曲线')
plt.xlabel('贷款金额')
plt.grid(True)
sns.set_style("ticks")
plt.show()
现在,直方图上多了一条平滑的曲线,它展示了贷款金额的概率密度估计,为数据分布提供了另一个视角。
📝 本节总结
本节课中我们一起学习了如何使用Seaborn绘制和自定义直方图:
- 核心函数:使用
sns.histplot()可以快速绘制直方图。通过x或y参数可以指定绘制垂直或水平方向的直方图。 - 关键参数:
bins:用于设置箱体的数量。binwidth:用于设置每个箱体的宽度(会覆盖bins参数)。kde:设置为True时,会在直方图上叠加核密度估计曲线。
- 自定义与调试:我们学习了如何添加标题、标签、网格和更改颜色。同时也了解到,图表的一些显示问题(如刻度线不显示)可能源于Seaborn的主题设置,可以使用
sns.set_style()进行调整。

直方图是数据可视化中最核心的图表类型之一。掌握了柱状图、散点图和直方图,你已经能够完成绝大部分的数据可视化工作。在接下来的课程中,我们将探索Seaborn库中其他更多样化的图表类型。
057:其他图表类型
在本节课中,我们将要学习Seaborn库中除柱状图和分布图之外的其他几种强大的图表类型。我们将重点介绍热力图、小提琴图和回归图,了解它们的用途、基本代码结构以及如何解读其结果。
🔥 热力图
上一节我们介绍了基础的分布图表,本节中我们来看看如何用热力图直观地展示数据间的相关性。
热力图非常适合用于可视化相关系数矩阵,它能将枯燥的数字表格转化为色彩丰富的图形,使正负相关关系一目了然。



以下是创建热力图的核心步骤:
- 计算相关系数矩阵:使用Pandas DataFrame的
.corr()方法。corr_matrix = df.corr() - 创建自定义色彩映射:使用
sns.diverging_palette()定义色彩。 - 设置图形尺寸:使用
plt.figure(figsize=(...))。 - 绘制热力图:使用
sns.heatmap()函数,并传入相关系数矩阵和色彩映射。 - 添加标题和刻度标签:使用
plt.title(),plt.xticks(),plt.yticks()进行美化。 - 显示图形:使用
plt.show()。
运行代码后,你将得到一个展示不同特征间相关性的热力图。与纯数字表格相比,热力图能清晰显示:负相关用渐深的蓝色表示,正相关用红色表示。例如,你可能会发现“利率”和“总债务限额”之间存在最强的负相关关系。
这种可视化结果可以直接分享给项目相关方,帮助他们理解特征间的关系,从而识别预测“已付利息”的机会,或筛选出最有利可图的贷款。你也可以据此决定后续需要绘制哪些散点图进行深入分析。

🎻 小提琴图
了解了展示相关性的热力图后,我们再来看看另一种展示数据分布的图表——小提琴图。它结合了箱形图和核密度估计图的优点。
小提琴图类似于箱形图,可以展示数据分布,但它还能额外揭示数据在何处更为密集。每个“小提琴”内部都包含了一个箱形图。
以下是绘制小提琴图的关键代码结构:
sns.violinplot(x='grade', y='loan_amnt', data=df, palette='RdYlGn')
通过观察生成的小提琴图,你可以比较不同贷款等级(A到G)的贷款金额分布。例如,虽然A到D级贷款的中位数金额相似,但随着等级变差,数据的“主体”逐渐上移。A级贷款中位数约为12500,且呈明显的右偏(正偏)分布;而D级贷款的偏度较小,中位数约为15000;E级贷款分布更对称;F级贷款则呈现左偏(负偏)分布。
总之,不同等级贷款的集中趋势、变异程度和偏度都存在差异。


📈 回归图
最后,我们来探讨一种能直观展示变量间关系并拟合趋势线的图表——回归图。它特别适合用于初步探索两个连续变量之间的线性关系。
观察以下代码,你认为它会生成什么样的图形?一个实用技巧是将代码复制到大型语言模型(LLM)中,让它简洁地解释代码功能。LLM可能会告诉你,这段代码使用Seaborn库创建了一个回归图,用于可视化“已付利息”和“贷款金额”之间的关系,并添加了特定的注释。


运行代码后,你会得到一个散点图,并叠加了一条自动生成的最佳拟合线。这条线是由 sns.regplot() 函数自动计算的。
图中显示了一个较强的正相关关系,这与之前热力图中观察到的结果一致(两者的相关系数约为0.71)。你还可以看到数据在某些贷款金额(如35000和40000)周围形成了聚集。
这种图表可以帮助相关方理解“已付利息”与“贷款金额”之间的关系。同时需要注意,贷款金额只能解释已付利息约71%的变异性。例如,在25000美元的贷款中,有些贷款的已付利息为0(可能是新贷款),而大部分则聚集在1000美元左右。因此,要更准确地估计不同贷款的盈利性,还需要考虑利率、贷款期限等其他特征。
✅ 课程总结

本节课中我们一起学习了Seaborn库中三种高级图表:
- 热力图:用于直观展示特征间的相关性矩阵。
- 小提琴图:结合箱形图与密度图,深入展示数据分布形态。
- 回归图:在散点图基础上自动拟合趋势线,揭示变量间关系。
以上仅是Seaborn众多强大绘图功能中的三个例子。你已在本课程中探索了从箱形图、直方图到色彩映射、主题设置等多种图表和定制方法。
接下来,你将通过练习作业和实践实验室来巩固本课的绘图技能。完成后,请跟随进入下一节课,我们将学习如何同时绘制多个图表。下节课见!
058:Python数据分析 第3课 - 组合图表 📊
概述
在本节课中,我们将要学习如何将多个图表组合在一起,无论是叠加在同一坐标系中还是并排展示。我们将探索如何结合使用 Seaborn 和 Matplotlib 来创建互补的图表组合,例如在直方图上叠加地毯图,或在箱线图上叠加带状图,以及如何在同一坐标系中叠加多个直方图以比较分布。
导入模块与数据准备
首先,在一个新的笔记本中导入必要的模块:Pandas、Matplotlib、Seaborn 和 NumPy。
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
上一节我们介绍了如何创建美观的可视化图表,本节中我们来看看如何将它们组合起来。
叠加互补图表:直方图与地毯图


回想一下之前创建的展示贷款金额特征分布的直方图。直方图的一个局限性在于它聚合了箱内的数据,因此我们无法看到单个数据点的具体值。


直方图是一种聚合图,它与一种能展示所有单个数据点的非聚合图互补性很好。地毯图就是这样一个选项。
以下是创建叠加了地毯图的直方图的步骤:
- 首先,使用 Seaborn 的
histplot函数创建基础直方图。 - 然后,在同一个坐标系中,使用 Seaborn 的
rugplot函数叠加地毯图。地毯图会在指定的轴(通常是直方图底部)上显示所有单个数据点。
这样,你就能同时获得分布的整体形状和单个数据点位置的信息。
# 假设 df 是你的数据框,其中包含 ‘loan_amount’ 列
sns.histplot(data=df, x='loan_amount')
sns.rugplot(data=df, x='loan_amount')
plt.show()


你可以为地毯图的数据点指定颜色。如果不确定哪种颜色与直方图颜色搭配更协调,可以尝试向大型语言模型寻求建议。例如,它可能会建议使用“中海绿色”。


sns.histplot(data=df, x='loan_amount')
sns.rugplot(data=df, x='loan_amount', color='mediumseagreen')
plt.show()

另一种组合:箱线图与带状图
类似的效果也可以用于箱线图,方法是结合使用带状图。

以下是使用之前视频中按贷款等级分段的贷款金额箱线图的一个简要示例。不同的点代表单个数值,就像地毯图中的刻度线一样。

这种组合图让你在观察聚合的箱线图时,也能看到单个数据点的分布情况。例如,从下图中可以明显看出,A到D等级的数据观测值更多,而E到G等级的观测值较少。
# 假设已有一个按‘grade’分组的箱线图
sns.boxplot(data=df, x='grade', y='loan_amount')
sns.stripplot(data=df, x='grade', y='loan_amount', color='black', alpha=0.5)
plt.show()

在同一坐标系中叠加多个分布
你可以将许多不同类型的图表叠加在一起。例如,你可能希望在同一坐标系中绘制多个直方图来比较分布。
假设你想比较A等级和D等级贷款的金额分布。
以下是具体步骤:
- 首先,将数据过滤成两个独立的数据框。
- 然后,重复使用直方图代码,为第一个数据框(A等级)创建直方图。
- 接着,叠加第二个直方图,这次使用第二个数据框(D等级)。你可以保持所有参数相同,但为了区分,可以将第二个直方图的颜色改为默认的蓝色。
# 过滤数据
df_A = df[df['grade'] == 'A']
df_D = df[df['grade'] == 'D']



# 叠加绘制两个直方图
sns.histplot(data=df_A, x='loan_amount', color='orange', label='Grade A')
sns.histplot(data=df_D, x='loan_amount', color='blue', alpha=0.5, label='Grade D')
plt.legend()
plt.show()


通过观察叠加后的图表,可以看出D级贷款的分布偏斜程度较小。并且,在大部分区间内,A级贷款似乎更常见,只有在20,000到30,000的少数几个箱中,D级贷款的数量超过了A级。

注意:在叠加多个图表时,需要注意坐标轴范围、标题、标签等设置的一致性,否则可能会使图表难以比较。例如,如果两个直方图的Y轴范围不同,比较就会变得困难。


总结
本节课中我们一起学习了组合图表的技术。
你看到了如何创建地毯图并将其叠加到现有的直方图上。地毯图是一种非聚合图,它能让你洞察单个数值在直方图所展示的聚合分布中的具体位置。
你也学习了如何将带状图与箱线图结合以达到类似的效果。

最后,你学会了如何在同一图表上叠加多个直方图以比较不同的分布。这种叠加效果只需在同一图形中创建两个图表即可实现。
你可以使用 Seaborn 和 Matplotlib 将两个、三个甚至更多图表叠加在一起,但要注意保持克制,避免让观众感到信息过载。
在下一个视频中,你将学习如何将许多单独的图表组合到同一个图形或图像中。
059:Matplotlib子图 📊

在本节课中,我们将要学习如何使用Matplotlib库创建子图。当单个图表不足以展示数据时,子图功能允许我们在一个图像中并排排列多个图表,这对于按不同特征(例如,客户拥有的不同信贷额度数量)进行数据分段分析非常有用。
概述
通常,一个图表并不够用。例如,当你需要根据一个具有多个可能值的特征进行数据分段时,你可能希望为每个值创建单独的图表。为了实现这一点,你可以使用Matplotlib的subplot函数。它非常快速且灵活。
为了更好地理解潜在客户群中不同分段的盈利能力,你正在研究客户拥有的未结信贷额度数量。信贷额度允许你在一定限额内反复借款。信用卡是最常见的信贷额度类型,但其他类型包括房屋净值信贷额度或商业信贷额度。你感兴趣的是根据贷款等级和未结信贷额度来分段分析已支付的利息。
关键在于,信贷额度有许多不同的可能值。因此,你需要创建大量图表。你将希望结合Matplotlib和Seaborn的优势来完成此操作。首先,你需要使用Matplotlib创建一个空的子图网格,然后用美观的Seaborn图表填充它。
回顾一下,你已经导入了模块并将数据加载到df变量中。现在,让我们查看一下“未结信贷额度”这一特征。直观地看一下它的分布情况。
尽管这个特征是数值型的,你仍然可以使用value_counts方法来理解不同值的频率。运行此代码单元后,你会发现存在许多不同的可能值。

记住,你可以使用sort_index方法将这些值从1排序到最大值。结果显示,大多数客户拥有5到15条信贷额度。

现在,你可以在每个单独的图表中,按等级分段绘制已支付利息的分布情况。为了在一个图像中创建多个图表,你可以使用Matplotlib的subplot函数。
创建子图网格
首先,手动设置图形大小。图形就像画布,你需要确保画布足够大,能够绘制所有这些单独的图表。
假设你想创建三个图表,分别对应前三个信贷额度数量。你希望如何排列它们?一种选择是一行三个图表。
从plt.figure()开始。然后,你需要指定figsize参数,即图形的高度和宽度。记住,这些值的单位是英寸。对于一个图表,通常5x5英寸是一个不错的尺寸,你可以根据需要调整。由于你只有一行,宽度可以是15英寸(即3个图表乘以5英寸),高度保持为5英寸。
接下来,你将使用plt.subplot()函数,它接受三个参数:行数、列数以及你当前正在创建的图表序号。这里只有一行,三列,并且你正在创建第一个图表。
现在,你可以过滤你的数据框。例如,过滤出df[‘open_credit_lines’] == 1的数据。然后,你可以使用这个过滤后的数据框作为第一个参数来创建Seaborn条形图。记住,总是从数据框开始。设置x=‘grade’,y=‘paid_interest’,对于调色板,你可以使用之前用过的‘red_yellow_green’反转色板来映射到不同的等级。
你可以复制这段代码,并基本上重复相同的操作。你只需要改变两处:你现在正在创建第二个子图,并且需要将过滤条件改为df[‘open_credit_lines’] == 2。再次复制代码,现在创建第三个图表,对应df[‘open_credit_lines’] == 3。
运行此代码单元,你将得到这三个并排排列的条形图,它们都在同一个图形中。
如果你想将它们一起保存,可以使用plt.savefig(‘credit_lines_plots.png’)。现在,你实际上已经将这三个图表放在了同一个图形中,这非常方便。
核心概念与代码
以下是创建子图的核心步骤和代码示例:
- 导入必要的库并加载数据:
import matplotlib.pyplot as plt import seaborn as sns import pandas as pd # 假设df是你的数据框 df = pd.read_csv(‘your_data.csv’)


- 设置图形(画布)大小:
plt.figure(figsize=(15, 5)) # 宽度15英寸,高度5英寸

-
创建第一个子图并绘图:
plt.subplot(1, 3, 1) # 1行,3列,第1个图 filtered_df = df[df[‘open_credit_lines’] == 1] sns.barplot(data=filtered_df, x=‘grade’, y=‘paid_interest’, palette=‘red_yellow_green_r’) -
创建第二个子图:
plt.subplot(1, 3, 2) # 1行,3列,第2个图 filtered_df = df[df[‘open_credit_lines’] == 2] sns.barplot(data=filtered_df, x=‘grade’, y=‘paid_interest’, palette=‘red_yellow_green_r’) -
创建第三个子图并保存图形:
plt.subplot(1, 3, 3) # 1行,3列,第3个图 filtered_df = df[df[‘open_credit_lines’] == 3] sns.barplot(data=filtered_df, x=‘grade’, y=‘paid_interest’, palette=‘red_yellow_green_r’) plt.savefig(‘credit_lines_plots.png’) plt.show()
总结与进阶
回顾一下,当你想要在一个图形中组合多个图表,尤其是这些图表相似时,子图非常有用。你需要使用figsize参数显式创建作为画布的图形,指定整个图形的宽度和高度。你看到每个图表大约5x5英寸效果很好,但也可以尝试其他尺寸。
然后,你了解到需要使用带有三个参数的Matplotlib subplot函数:行数、列数和当前正在创建的图表序号。在创建图表之前调用此函数,会将其定位在图像中的正确位置。例如,plt.subplot(2, 3, 4)会将下一个图表定位为第二行的第一个图表(假设每行有三个图表)。
调用plt.subplot函数后,你可以像往常一样创建图表。你可以结合使用Seaborn和Matplotlib的函数。请注意,还有一个单独的subplots(复数)函数,它提供了更多创建子图的选项。如果你愿意,可以通过你的LLM(大语言模型)来研究那个函数。
你可能已经注意到本视频演示中的一些重复代码。子图可以像你刚才看到的那样单独创建,但当与循环结合使用时,它们会更加强大。在下一个视频中,跟随我看看如何用几行代码创建数十个图表。

本节课中,我们一起学习了Matplotlib子图的创建方法,包括如何设置图形大小、使用subplot函数定位图表,以及结合Seaborn绘制美观的分段分析图。这为高效地进行多维度数据可视化提供了强大的工具。
060:Python数据分析 第3课 - 使用循环绘制子图 📊
概述
在本节课中,我们将学习如何使用循环来高效地创建多个子图。通过将重复的绘图代码转换为循环结构,可以显著减少代码量,提高效率,并使代码更易于维护。我们将从手动创建三个子图开始,逐步将其重构为使用for循环,并最终扩展至创建九个子图。
从手动绘图到循环
与Python中的大多数任务一样,创建子图有多种方法。Matplotlib允许你编写循环来快速生成数十个子图,这可以节省大量复制粘贴代码的时间。
承接之前的内容,假设你已经将数据读入变量Df,并基于信用等级和已开通信用额度线,手动创建了三个用于展示已支付利息分布的子图。在创建这些图形时,你可能会注意到代码的重复。
如果你发现自己像这里一样复制粘贴代码,通常可以使用循环来替代。
让我们开始将这段代码转换为使用循环。首先,保持图形尺寸不变。

现在,你只需要一个循环来遍历数字1、2和3,这对应着你正在调查的信用额度线数量。


以下是初始的手动绘图代码示例:


# 假设的初始手动绘图代码(三个子图)
plt.figure(figsize=(15, 5))
plt.subplot(1, 3, 1)
# 绘制信用额度线为1的图表...
plt.subplot(1, 3, 2)
# 绘制信用额度线为2的图表...
plt.subplot(1, 3, 3)
# 绘制信用额度线为3的图表...
理解循环与range函数
你可以使用range函数来生成需要遍历的数字序列。range可以接受一个参数,即结束值,这将创建一个从0到该值(不包含)的范围。或者,你可以添加两个值:起始值和结束值。
需要记住的是,结束值不包含在范围内,范围只到结束值 - 1。
因此,你可以使用range(1, 4)来获取从1到3的范围。所以,循环可以写为:for i in range(1, 4):。


现在,回顾上一视频中的绘图代码,对于每个子图,哪些值发生了变化?

识别变化点并构建循环
变化的只有两个值:你正在创建的子图索引,以及用于筛选数据的“已开通信用额度线”的数值。
因此,在循环内部,你可以复制绘图代码,并在任何该值发生变化的地方,用循环变量i来替代。
以下是转换后的循环代码示例:
plt.figure(figsize=(15, 5))
for i in range(1, 4):
plt.subplot(1, 3, i)
# 使用变量 i 筛选数据框,只包含信用额度线数为 i 的行
# df_filtered = Df[Df['open_credit_lines'] == i]
# 然后绘制条形图...
这段代码的运行逻辑是:for循环将为i等于1、2和3各运行一次。每次循环都会选择相应的子图位置,并筛选数据框以仅包含具有i条信用额度线的行,然后绘制出与之前完全相同的图形。
编写这段代码后,你应该看到什么?输出与之前完全相同,但你将代码从10行减少到了5行。
扩展循环以绘制更多子图
现在,你可以用这个循环绘制大量图表。它对任何有效的信用额度线数值都适用。


例如,你可能想绘制信用额度线从1到9的分布图。你需要确保图形尺寸更大,比如15x15以容纳9个子图。然后,复制粘贴之前的代码。

你需要改变什么?需要改变i的范围和子图的布局维度。
以下是绘制九个子图的代码调整:
plt.figure(figsize=(15, 15))
for i in range(1, 10):
plt.subplot(3, 3, i) # 3行3列布局
# 筛选和绘图代码...
plt.subplot(3, 3, i)这行代码给出了每行三个、每列三个的子图布局。运行这个单元格,你将得到这九个漂亮的图表。
增强循环功能
你还可以在循环中添加更多功能。例如,你可以使用i作为每个子图的标题,这增加了必要的标签。


此外,如果你使用plt.savefig(),比如以“nine_graphs”为文件名,现在这九个图表就会被一起保存下来。

以下是增强后的代码示例:
plt.figure(figsize=(15, 15))
for i in range(1, 10):
plt.subplot(3, 3, i)
# 筛选和绘图代码...
plt.title(f‘Credit Lines: {i}’) # 添加标题
plt.tight_layout()
plt.savefig(‘nine_graphs.png’)
总结
在本视频中,你学习了可以使用for循环来遍历和创建子图。你使用了一个从1开始、到感兴趣的最后数字加1结束的range循环。因此,你使用代码range(1, 10)绘制了信用额度线1到9的图表。

每当你注意到自己在复制粘贴代码时,这通常是一个信号,表明你可以使用像循环这样的控制结构来提高代码的效率和可读性。
Matplotlib的subplot函数对于一次性创建多个图形非常强大。在接下来的视频中,我们将学习Seaborn库中另一个用于创建组合图形的关键功能:pairplot。
核心概念公式/代码总结:
- 循环结构:
for i in range(start, end): - 子图定位:
plt.subplot(n_rows, n_cols, index) - 数据筛选(示例):
df_filtered = df[df[‘column_name’] == i]
061:Python数据分析(第3课)|Python for Data Analytics
课程编号:P61 - Seaborn配对图 📊
在本节课中,我们将要学习如何使用Seaborn库中的pairplot函数,来快速创建基于数据特征的多个图表,以探索特征间的关系。
探索性数据分析的收尾工作
上一节我们介绍了数据可视化的多种工具。本节中我们来看看如何为你的探索性数据分析创建一个附录,其中包含多个分布图,以便客户能自行寻找洞察。

你可以使用Seaborn的pairplot工具来快速创建大量图表。首先,需要导入必要的模块并将数据加载到变量中。


以下是导入模块和加载数据的示例代码:
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
# 假设数据已加载到变量 df 中
# df = pd.read_csv('your_data.csv')
使用Seaborn的Pairplot
pairplot对于探索特征之间的关系非常有用。假设你想查看数据集中预测贷款盈利性的几个关键特征:贷款金额、年收入、利率和已付利息。
以下是操作步骤:
- 首先,选择你感兴趣的列子集。
- 然后,使用
sns.pairplot函数,并传入筛选后的数据框。 - 调用
plt.show(),你将得到展示所有特征之间关系的散点图,以及对角线上每个特征的直方图。
例如,你之前见过贷款金额的直方图,现在你还可以看到它与年收入、利率和已付利息的关系。
为图表添加标题
你可以使用plt.suptitle为整个图形添加标题,而不仅仅是单个坐标轴。这是“supertitle”的简写。
例如,添加标题“贷款金额、年收入、利率和已付利息的配对图”。你可能需要使用y参数将这个总标题调整到比图中所有子图稍高的位置,值设为1或略高即可。
以下是添加总标题的代码示例:
plt.suptitle('Pairplot of Loan Amount, Annual Income, Interest Rate, and Paid Interest', y=1.02)
自定义与保存图表

由于pairplot包含多种图表类型和多个子图,你无法像平常自定义单个图表那样(如颜色、线条样式等)进行统一设置。但你始终可以与你的LLM(大语言模型)协作,探索更多格式化选项。
为了完成你的探索并创建附录,你可以使用plt.savefig并指定文件名来保存图表。
以下是保存图表的代码示例:
plt.savefig('Pairplot.png')
现在,你拥有了所有这些组合在一起的图表。

课程总结
本节课中我们一起学习了如何使用sns.pairplot在一个数据框上创建一组图表,包括特征间的散点图以及每个特征的单独直方图。我们还看到了使用plt.suptitle为整个图形添加标题的选项,并探讨了如何与LLM协作来自定义配对图的外观。
Python可视化部分总结
至此,Python数据可视化部分的学习告一段落。你已经学会了创建美观且功能强大的可视化所需的所有核心工具,从Pandas到Matplotlib,再到Seaborn。这三个库构成了Python数据可视化的支柱,你很少需要寻找其他工具。
接下来,你将完成本模块的评分作业和实验。完成后,请跟随我进入本课程的下一模块,该模块将全部关于推断统计学,包括置信区间、假设检验和一种新技术——线性回归。期待在那里与你相见!
062:推断统计学简介 📊
在本课程中,我们将学习如何利用Python中的强大统计技术,从数据中做出预测并得出有意义的结论。我们将探索置信区间、假设检验以及线性回归等核心概念,最终目标是能够应用这些推断统计方法来分析数据并构建预测模型。
模块4:推断统计学
欢迎来到模块4:推断统计学。
在本模块中,你将学习如何利用Python中的强大统计技术,从数据中做出预测并得出有意义的结论。
第一课:置信区间与假设检验
上一节我们介绍了本模块的整体目标,本节中我们来看看第一课的具体内容。
在第一课中,你将使用一个真实的钻石数据集,探索均值的置信区间和假设检验。你将重温标准误差和P值的概念,并学习如何用一行代码计算置信区间。
以下是第一课你将进行的主要操作:
- 执行单样本和双样本假设检验。
- 探索从不同分布中模拟数千个数据点的技术。
第二课:简单线性回归
在掌握了假设检验之后,我们将进入第二课,学习一种强大的预测工具。
第二课的重点是简单线性回归。你将了解什么是线性回归,以及它为何对数据中的关系建模非常有用。
以下是第二课的核心学习目标:
- 学习如何为模型选择最强的预测因子。
- 训练模型、解释结果,并利用模型进行预测。

第三课:多元线性回归
上一节我们介绍了只有一个预测因子的简单线性回归,本节中我们将扩展建模能力,纳入多个特征。
在第三课中,你将通过纳入多个特征作为预测因子来扩展建模能力。你将学习如何将分类数据整合到模型中,以及如何迭代优化模型以提高准确性。
预备知识要求 😊
除了线性回归,如果你学习过《数据分析应用统计学》课程,那么你应该对本模块中的统计概念有所了解。
不记得每个术语和计算也没关系,但如果“置信区间”和“假设检验”这些术语对你来说是全新的,你应该确保在继续之前回头学习那门课程。
本模块将简要回顾该课程中涵盖的关键概念,但不会深入教授。
总结

本节课中,我们一起学习了推断统计学模块的总体框架。我们了解到,通过本模块的学习,你将能够掌握置信区间、假设检验以及简单和多元线性回归。最终,你将具备应用推断统计方法在Python中分析数据和构建预测模型的能力。
063:置信区间 📊
在本节课中,我们将要学习推断统计中的一个核心概念——置信区间。我们将了解其定义、计算所需的关键要素,并学习如何使用Python的scipy库来计算数据集的均值置信区间。
推断统计是数据分析师进行严谨分析的基础。置信区间提供了一个范围,用于估计特定的总体参数(如均值或比例)。该区间根据样本数据计算得出,并以一定的置信水平预期包含真实的总体值。
理解置信区间
上一节我们介绍了置信区间的基本概念,本节中我们来看看其具体含义。
置信区间是从样本数据计算出的一个范围,用于估计总体参数。例如,在95%的置信水平下,如果你重复多次从总体中抽样并计算置信区间,那么你预期有95%的区间会包含真实的总体均值。

计算置信区间需要四个关键值:
- 样本统计量:你感兴趣的统计量,例如样本均值。
- 样本大小:样本中包含的观测数量。
- 样本标准差:衡量样本数据的离散程度。
- 置信水平:例如0.95对应95%的置信区间。

样本标准差和样本大小用于计算标准误,它衡量的是样本统计量(如均值)的抽样变异性。
提示:如果这些统计概念对你来说是新的,建议回顾之前的课程《数据分析应用统计》,该课程详细讲解了推断统计的细微差别。本模块仅对每个概念进行简要回顾。即使你对某些术语感到模糊也不必担心,我们将一起完成计算步骤。
项目实战:估算钻石价格 💎
假设你是一名在线珠宝零售商的数据分析师,任务是帮助公司为新收购的钻石定价。你将使用历史销售数据集来理解和预测钻石价格的分布。
钻石价格基于四个核心特征(4C标准)进行评估:
- 切工:指钻石的切割质量。切工良好的钻石对称且反光好,外观闪耀。
- 颜色:指钻石的颜色。钻石越清澈,颜色等级越高。偏黄的钻石价值较低。
- 净度:指钻石表面或内部的瑕疵数量。越清澈的钻石价值越高。
- 克拉:用于宝石的重量单位。一克拉的圆形钻石大约有一颗绿豆大小。“克拉”一词实际上来源于角豆树的种子,历史上曾用于称量宝石。
你的首要任务是估算客户(零售商)所售钻石的平均价格。
第一步:导入模块与加载数据
首先,导入所有需要的模块。scipy模块通常用于推断统计,它提供了pandas和numpy之外的功能。
import pandas as pd
import numpy as np
import scipy.stats as stats
接着,加载存储在diamonds.csv文件中的数据。
df = pd.read_csv('diamonds.csv')
注意:这行代码仅在CSV文件与你的笔记本文件位于同一文件夹时才有效。本课程的实验环境中已配置好,你无需进行文件管理,但了解其工作原理是有益的。

查看数据的前几行和基本描述:
df.head()
df.describe()
数据集中有近4000行数据,这是进行准确总体估计的绝佳数据量。钻石的平均价格约为4000美元,最大的钻石约5克拉(相当大),猜测那可能是价值18000美元的钻石。
第二步:数据可视化与观察
使用seaborn绘制价格分布直方图:
import seaborn as sns
sns.histplot(df['price'])
价格分布是右偏的。这符合常理,更昂贵的钻石应该更稀有。请记住,即使总体分布是偏态的,样本均值的抽样分布也预期是正态的,因此在此处使用置信区间仍然是合适的。
第三步:计算置信区间
现在,开始计算钻石平均价格的置信区间。首先,声明计算所需的关键变量。


以下是计算步骤:
- 计算样本大小、样本均值和样本标准差。
- 设定置信水平为0.95(95%)。
- 计算标准误,公式为:
样本标准差 / sqrt(样本大小)。 - 使用
scipy.stats.norm.interval函数计算置信区间。

# 1. 声明关键变量
n = df['price'].count() # 样本大小
x_bar = df['price'].mean() # 样本均值
s = df['price'].std() # 样本标准差
conf_level = 0.95 # 置信水平
# 2. 计算标准误
sem = s / np.sqrt(n)
# 3. 计算置信区间
interval = stats.norm.interval(confidence=conf_level, loc=x_bar, scale=sem)
# 4. 格式化输出结果
print(f"以 {conf_level*100}% 的置信度,真实钻石平均价格介于 ${interval[0]:.2f} 和 ${interval[1]:.2f} 之间。")
运行代码后,你将得到一个区间,例如(3899, 3966)。由于样本量很大,标准误很小(约17美元),这使得估计范围非常窄,结果精确。
说明:我们使用了
norm.interval函数(基于正态分布)。虽然也可以使用t分布,但由于样本量很大,两种分布的结果几乎相同。函数参数中,loc代表位置(即样本均值x_bar),scale代表尺度(即标准误sem)。
总结与回顾 🎯
本节课中我们一起学习了如何用Python计算置信区间。


我们来总结一下关键步骤:
- 首先,计算核心描述性统计量:样本大小
n、样本均值x_bar和样本标准差s。 - 接着,使用公式
sem = s / np.sqrt(n)计算标准误。 - 最后,利用
scipy.stats模块中的stats.norm.interval()函数,传入confidence(置信水平)、loc(样本均值)和scale(标准误)参数,即可得到置信区间。

根据计算结果,你可以相当有信心地认为,真实的钻石平均价格在3900美元左右。置信区间的概念可能正在你脑海中变得清晰。如果对某些概念还有些生疏,不必过于担心,在接下来的实践练习中你将有机会进行复习。
现在,让我们跟随课程进入下一个视频,学习如何在Python中进行单样本t检验。
064:单样本t检验 🧪

在本节课中,我们将学习如何使用Python进行单样本t检验。这是一种假设检验方法,用于判断一个样本的平均值是否与某个已知的理论值存在显著差异。
上一节我们介绍了置信区间,本节中我们来看看假设检验。假设检验用于根据样本数据,推断关于更大总体的某个假设是否有足够证据支持。
假设检验步骤回顾
以下是进行假设检验的基本步骤:
-
定义假设:
- 零假设 (H₀):代表现状或基线。例如,高级切工钻石的平均价格等于或低于4500美元。
- 备择假设 (H₁):代表你想要检验的条件。例如,高级切工钻石的平均价格高于4500美元。
-
选择显著性水平 (α):这是置信水平的补数(1 - 置信度)。它代表你拒绝零假设的容易程度。高置信度意味着较低的α值,使得更难找到证据拒绝零假设。α = 0.05 是一个常用值。
-
执行检验并计算P值:P值是在零假设为真的前提下,观察到当前样本数据或更极端数据的概率。
- 如果 P值 < α,则可以拒绝零假设。
- 如果 P值 ≥ α,则无法拒绝零假设。
实战:检验钻石价格
假设我们正在为一家在线珠宝零售商做分析,我们想检验“高级切工钻石的平均价格是否高于4500美元”。这是一个单样本t检验问题,因为我们是将一个样本(高级切工钻石)与一个假设值(4500美元)进行比较,而不是比较两个样本。
首先,我们导入必要的库并加载数据。
import pandas as pd
import scipy.stats as stats
# 假设数据已加载到变量 df 中
# df = pd.read_csv('diamonds.csv')

接着,我们查看钻石切工的类型,以便准确筛选“Premium”等级的数据。

print(df['cut'].unique())
输出显示有五个等级,其中“Premium”是大写的。现在,我们可以先查看样本中Premium钻石的平均价格。
avg_price_by_cut = df.groupby('cut')['price'].mean()
print(avg_price_by_cut)
我们发现Premium切工钻石的样本平均价格是4584美元。那么,这个价格是否显著高于4500美元呢?让我们通过检验来确认。
以下是执行单样本t检验的完整代码:
# 1. 定义显著性水平
alpha = 0.05
# 2. 执行单样本t检验
# 参数:样本数据(筛选Premium切工的钻石价格),零假设下的总体均值(popmean)
test_results = stats.ttest_1samp(df[df['cut'] == 'Premium']['price'], popmean=4500)
# 3. 输出检验结果(包含统计量、P值和自由度)
print("T检验结果:", test_results)
# 4. 根据P值做出决策
p_value = test_results.pvalue # 或 test_results[1]
if p_value > alpha:
print(f"无法拒绝零假设 (P值 = {p_value:.3f})")
else:
print(f"拒绝零假设 (P值 = {p_value:.3f})")
运行代码后,我们得到了一个P值(例如0.023)。由于这个P值小于我们设定的α(0.05),因此我们拒绝零假设。这意味着我们有显著的统计证据表明,高级切工钻石的平均价格高于4500美元。

核心函数与概念
在本例中,我们使用了 scipy.stats.ttest_1samp 函数来执行单样本t检验。
- 第一个参数是你的样本数据(一个数组或序列)。
popmean参数是零假设中假定的总体均值。- 函数返回一个对象,其
.pvalue属性(或索引[1])就是我们需要用于决策的P值。
决策逻辑可以用以下公式表示:
如果 P值 < α,则拒绝 H₀;否则,无法拒绝 H₀。


本节课中我们一起学习了单样本t检验。我们回顾了假设检验的步骤,并使用Python的SciPy库对一个具体的商业问题(钻石价格检验)进行了分析。通过计算P值并与显著性水平比较,我们能够对关于总体均值的假设做出统计推断。
现在你已经掌握了在Python中进行单样本t检验的方法,接下来可以准备学习双样本检验了,你会发现两者有很多相似之处。
065:Python数据分析 - P65 双样本t检验 📊
在本节课中,我们将学习如何在Python中执行双样本t检验。我们将直接比较两个组,而不是将一个组与假设值进行比较。具体来说,我们将分析不同切割等级的钻石的平均价格是否存在显著差异。
概述
假设检验中,我们经常需要直接比较两个组。本节将介绍如何在Python中进行双样本t检验。我们将以钻石数据集为例,比较“良好”和“非常好”两种切割等级的钻石的平均价格,以帮助在线零售商制定定价和营销策略。


数据准备与可视化

首先,我们需要导入必要的模块并将数据加载到变量df中。为了直观展示数据,我们将按切割等级分组,选择价格列,计算平均值,排序结果,并使用条形图进行可视化。
以下是数据准备和可视化的步骤:

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from scipy import stats
# 假设数据已加载到变量df中
# df = pd.read_csv('diamonds.csv')
# 按切割等级分组并计算平均价格
avg_price_by_cut = df.groupby('cut')['price'].mean().sort_values()
# 绘制条形图
avg_price_by_cut.plot(kind='bar')
plt.show()
运行上述代码后,我们可能会发现一个有趣的现象:“一般”切割等级的钻石平均价格高于“理想”切割等级。此外,“良好”和“非常好”切割等级的钻石价格看起来非常接近。
为了进一步探索,我们可以使用箱线图查看基于切割等级的价格分布。Seaborn库可以轻松实现这一点。



# 设置切割等级的显示顺序
cut_order = ['Fair', 'Good', 'Very Good', 'Premium', 'Ideal']

# 绘制箱线图
sns.boxplot(data=df, x='price', y='cut', order=cut_order, palette='Blues_r')
plt.show()
从箱线图中,我们可以看到“良好”和“非常好”切割等级的钻石中位数不同,且“非常好”切割等级的钻石具有更大的四分位距,表明其价格变异性可能更高。然而,从图中无法明确判断这两个类别的平均价格是否存在显著差异。
执行双样本t检验
为了检验“良好”和“非常好”切割等级的钻石平均价格是否存在显著差异,我们将使用scipy.stats模块中的ttest_ind函数进行双样本t检验。我们假设这两个样本是独立的,即数据集中“非常好”切割的钻石与“良好”切割的钻石没有关联。
以下是执行双样本t检验的步骤:
首先,从数据框中筛选出“非常好”和“良好”切割等级的钻石价格数据:
# 筛选数据
very_good_prices = df[df['cut'] == 'Very Good']['price']
good_prices = df[df['cut'] == 'Good']['price']



接下来,使用ttest_ind函数进行检验。与单样本t检验不同,这里不需要指定popmean参数,因为我们的目标是直接比较两个组的均值。

# 执行双样本t检验
test_results = stats.ttest_ind(very_good_prices, good_prices)

# 输出检验结果
print(test_results)
检验结果将包含t统计量和p值。我们可以通过test_results.pvalue访问p值。

结果解读

假设我们设定的显著性水平为0.05。我们可以编写一个简单的if语句来解读检验结果:

alpha = 0.05
if test_results.pvalue < alpha:
print("拒绝原假设:两个组的平均价格存在显著差异。")
else:
print("未能拒绝原假设:两个组的平均价格没有显著差异。")
如果p值小于0.05,我们拒绝原假设,认为两个组的平均价格存在显著差异;否则,我们未能拒绝原假设。
在我们的例子中,p值为0.41,大于0.05,因此我们未能拒绝原假设。这意味着“良好”和“非常好”切割等级的钻石平均价格没有显著差异。这一结论可以帮助客户为这两种切割等级的钻石制定相似的定价和营销策略。


总结
本节课中,我们一起学习了如何在Python中执行双样本t检验。我们首先通过数据可视化初步探索了数据,然后使用scipy.stats.ttest_ind函数比较了两个独立样本的均值。最后,我们根据p值解读了检验结果,并得出了统计结论。
通过掌握单样本和双样本t检验,你现在能够使用Python进行基本的假设检验,并编写代码帮助解读结果。在数据有限的情况下,我们还可以通过模拟样本来进行检验,这将在下一节课中介绍。
066:Python数据分析 - P66 均匀分布模拟 📊
在本节课中,我们将要学习如何使用模拟(Simulation)来解决数据分析中的实际问题。模拟是一种强大的工具,尤其当数据收集存在限制时,它可以帮助我们通过生成随机样本来探索数据在现实世界中的可能行为。
上一节我们介绍了推断统计学的基础知识,本节中我们来看看如何利用模拟来应对数据稀缺的挑战。
概述:为什么需要模拟?🤔
在现实场景中,由于时间、成本或物流限制,收集大型数据集通常很困难。例如,你合作的一家在线珠宝零售商想要测试一个新的定价策略。直接采访大量客户或从实验中收集足够数据来做出精确估计往往不切实际。对于珠宝这类高价值、低交易量的商品尤其如此。


模拟可以帮助我们克服这些限制。我们无需完全依赖有限的数据,而是可以通过估计数据的参数(如均值和标准差)来近似其潜在分布。然后,利用这些参数生成随机样本,模拟基于我们对数据行为假设的各种可能场景。

开始模拟:生成均匀分布折扣 💎
假设你正在与珠宝零售商合作,评估新定价策略的潜在影响。你的任务是开发一个模拟,在固定范围内(例如钻石折扣从0%到10%)生成随机折扣价格。零售商计划将此模拟作为评估对客户购买习惯影响的第一步。
我们将在同一个Jupyter Notebook中继续。首先,导入必要的模块并开始对潜在折扣进行建模。
以下是建模步骤:
- 定义样本大小:我们计划生成一个包含1000个折扣的样本。
n = 1000 - 生成均匀分布样本:使用NumPy的
random.uniform函数,在0到0.1(即0%到10%)之间生成随机数。sample = np.random.uniform(low=0, high=0.1, size=n) - 计算样本统计量:计算生成样本的均值(
x_bar)和标准差(s)。x_bar = sample.mean() s = sample.std() - 可视化分布:使用Seaborn的
histplot函数绘制样本的直方图,以观察其分布。sns.histplot(sample) plt.show()


运行代码后,你会得到一个均值约为0.05、标准差约为0.029的样本,其直方图大致呈均匀分布。由于np.random每次产生随机输出,重新运行单元格会得到略有不同的结果,这体现了自然随机变异。
构建置信区间 📐
接下来,我们可以基于模拟数据为均值构建一个置信区间。我们将复用之前课程中的置信区间代码。
以下是构建95%置信区间的步骤:
- 设置置信水平:例如,
confidence = 0.95。 - 计算标准误差:公式为
s / np.sqrt(n)。 - 计算置信区间上下限:使用
scipy.stats.norm.ppf函数找到临界z值,然后计算区间。import scipy.stats as st z_critical = st.norm.ppf((1 + confidence) / 2) margin_of_error = z_critical * (s / np.sqrt(n)) confidence_interval = (x_bar - margin_of_error, x_bar + margin_of_error)

以95%的置信度运行,得到的区间可能类似于(0.0487, 0.0524)。我们知道这个均匀分布的真实总体均值是0.05。这个置信区间成功捕获了该真实值。


重复模拟以验证理论 🔁
根据理论,95%的置信区间应包含真实总体均值。我们可以通过多次重复模拟来验证这一点。你可以请求大语言模型(LLM)协助编写代码,运行模拟100次,并统计有多少个置信区间包含了0.05。
以下是LLM可能提供的代码框架:


contain_true_mean = 0
num_simulations = 100



for _ in range(num_simulations):
# 1. 生成新样本
sample = np.random.uniform(low=0, high=0.1, size=n)
x_bar = sample.mean()
s = sample.std()
# 2. 计算置信区间
z_critical = st.norm.ppf((1 + confidence) / 2)
margin_of_error = z_critical * (s / np.sqrt(n))
ci_low = x_bar - margin_of_error
ci_high = x_bar + margin_of_error
# 3. 检查是否包含0.05
if ci_low <= 0.05 <= ci_high:
contain_true_mean += 1

print(f"{contain_true_mean}个区间包含了真实均值0.05。")
print(f"{num_simulations - contain_true_mean}个区间没有包含真实均值0.05。")
运行这段代码,你可能会得到类似“93个区间包含0.07,7个不包含”的结果。这与95%置信区间的预期行为基本吻合。
总结与应用 🎯
本节课中我们一起学习了如何使用模拟解决数据分析中的实际问题。
我们主要完成了以下工作:
- 使用
np.random.uniform函数从均匀分布中生成了大随机样本。 - 通过
low、high和size参数指定了模拟的条件。 - 基于生成的随机样本,在代码中构建了置信区间。
- 利用大语言模型辅助编写代码,重复了多次模拟以验证置信区间的统计特性。

你可以将这份模拟演示提交给珠宝零售商的客户,帮助他们理解折扣可能如何分配给客户,以及如果向客户推出此类折扣实验,他们应该为哪些不同场景做好准备。例如,零售商可能担心理解对收入的最大潜在影响,如果许多折扣集中在较高端,他们可以使用你的模拟作为起点,来了解达到此阈值的可能性。


模拟虽然强大,但其有效性完全取决于所做假设的合理性。在下一节视频中,我们将学习如何在Python中从正态分布进行抽样。
067:正态分布模拟 📊
在本节课中,我们将学习如何使用Python从正态分布中生成随机样本,并利用这些样本来模拟现实世界中的商业场景,例如竞争对手的定价策略。我们将通过一个珠宝零售商的案例,演示如何基于历史数据模拟竞争对手的钻石价格分布。
概述
上一节我们介绍了如何从均匀分布中进行抽样。本节中,我们来看看如何从正态分布中生成随机样本。正态分布是一种常见的概率分布,适用于描述许多自然和社会现象,例如价格波动、测试成绩等。我们将使用NumPy库中的random.normal函数来生成这些样本,并计算置信区间以评估模拟结果的可靠性。
正态分布模拟步骤
以下是模拟正态分布样本并计算置信区间的具体步骤。
1. 设定参数
首先,我们需要设定正态分布的参数。根据历史数据,我们得知竞争对手的钻石价格大致围绕一个均值波动,且标准差已知。


- 均值(Mean):$3932
- 标准差(Standard Deviation):$750
- 样本大小(Sample Size):100
- 置信水平(Confidence Level):95%
2. 生成随机样本

使用NumPy的random.normal函数从正态分布中生成随机样本。该函数需要三个主要参数:loc(均值)、scale(标准差)和size(样本大小)。
import numpy as np

mean_price = 3932
std_dev = 750
sample_size = 100
sample = np.random.normal(loc=mean_price, scale=std_dev, size=sample_size)
3. 计算置信区间
接下来,我们计算每个样本的置信区间。置信区间表示我们对总体参数(如均值)的估计范围。对于正态分布,我们可以使用以下公式计算95%的置信区间:
[
\text{置信区间} = \bar{x} \pm z \times \frac{\sigma}{\sqrt{n}}
]
其中,(\bar{x}) 是样本均值,(z) 是标准正态分布的临界值(对于95%的置信水平,(z \approx 1.96)),(\sigma) 是标准差,(n) 是样本大小。
confidence_level = 0.95
z_value = 1.96 # 对应95%的置信水平
sample_mean = np.mean(sample)
margin_of_error = z_value * (std_dev / np.sqrt(sample_size))
confidence_interval = (sample_mean - margin_of_error, sample_mean + margin_of_error)

4. 重复模拟


为了获得更可靠的结果,我们可以重复上述过程多次,例如1000次,并统计有多少次置信区间包含了真实的均值。
num_simulations = 1000
contains_mean = 0
for _ in range(num_simulations):
sample = np.random.normal(loc=mean_price, scale=std_dev, size=sample_size)
sample_mean = np.mean(sample)
margin_of_error = z_value * (std_dev / np.sqrt(sample_size))
confidence_interval = (sample_mean - margin_of_error, sample_mean + margin_of_error)
if confidence_interval[0] <= mean_price <= confidence_interval[1]:
contains_mean += 1
print(f"包含真实均值的区间数量: {contains_mean}")
print(f"不包含真实均值的区间数量: {num_simulations - contains_mean}")


5. 结果分析
运行上述代码后,我们得到了包含真实均值的区间数量和不包含真实均值的区间数量。在95%的置信水平下,我们期望大约有95%的区间包含真实均值。例如,如果模拟1000次,大约有950个区间包含真实均值。
总结
本节课中,我们一起学习了如何使用Python从正态分布中生成随机样本,并利用这些样本模拟竞争对手的定价策略。我们通过设定参数、生成样本、计算置信区间以及重复模拟来评估结果的可靠性。正态分布模拟是数据分析中常用的技术,能够帮助我们更好地理解现实世界中的不确定性。
接下来,我们将完成本课的练习作业和实践实验室,探索伦敦的房价数据。完成后,请加入下一节课,学习一种全新的推断技术——线性回归。
期待与您在下一节课再见!😊
068:线性回归基础 📊

概述
在本节课中,我们将要学习线性回归的基础知识。这是一种强大的推断方法,用于建模特征之间的关系。我们将从理解线性回归的核心概念开始,逐步学习如何构建和使用线性回归模型进行预测。
从置信区间与假设检验到线性回归
上一节我们介绍了置信区间和假设检验。本节中,我们来看看如何扩展你的推断工具箱,学习线性回归。
线性回归是一种强大的推断方法,用于建模特征之间的关系。考虑以下场景:你在一家在线珠宝零售商担任数据分析师,公司要求你为新收购的钻石定价。每天有成千上万的钻石需要定价,而合格的专家并不总是有空来确定最准确的价格。零售商希望开发一个更具成本效益的钻石定价模型。他们要求你根据钻石的特征(如大小、切工和净度)预测合理的市场价格。然后,专家将使用你的预测价格作为起点,更快地完成最终定价。

对于这个任务,置信区间或假设检验都不合适。你需要预测单个钻石的新价格,而不仅仅是对所有钻石的某些特征进行推断。当然,你知道更大的钻石更有价值,但具体价值多少?切工和净度哪个更重要?你的计划是从一个简单的模型开始,只使用一个因素来预测钻石价格,然后再添加更多因素。
什么是线性回归?📈
线性回归使你能够量化数据中的关系,最适合非常线性的关系。使用回归,你不仅能说“更大的钻石与更高的价格相关”,还能说“一克拉的增加对应着价格增加10000美元”。
线性回归涉及两个步骤:训练和预测。
首先,训练是分析你现有的数据,以量化两个特征(如克拉和价格)之间的关系。你希望创建一条线来建模这种关系,使用形式为 y = Mx + B 的方程。你可能在高中数学课上见过这个方程,它被称为斜截式。M和B在数学中被称为系数。线性回归背后的统计方法将根据你的数据,确定最适合数据的M和B的值。
例如,你可能在寻找方程:price = m * carat + b。这个方程量化了价格和克拉之间的关系。假设你运行线性回归,发现最适合数据的方程是 price = $10000 * carat + $2000。
从训练到预测
现在你已经建立了模型。下一步是预测,使用这个训练好的模型,根据输入X来预测y。在这个例子中,意味着根据输入的克拉来预测价格。
想象你刚刚收到一颗新钻石,你的工作是根据其克拉给出合适的价格。如果你知道钻石是0.5克拉,你可以将其代入你的方程:10000 * 0.5 = 5000,再加上2000,最终价格为7000美元。
线性回归与相关性的区别

线性回归听起来可能很像相关性,相关性也能量化两个特征之间的关系。它们确实是相关的技术。然而,相关性只能量化关系的强度和方向。例如,钻石克拉和价格之间的相关性是0.92。使用这个统计量,你可以得出结论:钻石的克拉解释了其价格变异的92%,另外8%由其他因素(如切工、颜色和净度)控制。然而,你无法准确说出价格随克拉增加而上涨的具体金额。
线性回归更进一步,它生成最佳拟合线的方程,使你能够预测新价格。使用线性回归,你可以得出结论:“一克拉的增加导致价格增加10000美元”,或者“一颗半克拉的钻石估计价值7000美元”。然而,相关性通常在回归分析开始时使用,以识别最具预测性的特征。如果你使用一个自变量,选择与结果变量相关性最强的那个,以开发最准确的线性回归模型。
理解变量:自变量与因变量
到目前为止,你已将输入(如克拉)称为特征,将输出(如价格)称为结果。因此,你可能将这个问题描述为使用特征(克拉)来预测结果(价格)。在线性回归术语中,特征和结果通常都称为变量。变量本质上是特征的另一个术语。
自变量对应于你的输入。它是你认为导致结果的特征,并绘制在x轴上。在这个例子中,它是克拉。因变量是你试图预测的结果,这里是钻石的价格。价格的值取决于自变量克拉。

当你在数据中试图确定哪个变量是哪个时,请考虑因果关系。钻石价格标签的改变不会神奇地使钻石变大,但钻石的克拉直接影响其价格。因此,克拉是自变量,价格是因变量。
构建回归模型的步骤
要构建回归模型并使用它进行预测,请遵循以下步骤。
以下是构建线性回归模型的四个关键步骤:
- 识别因变量:这是你最终想要预测的变量。
- 探索数据关系:识别模型中最好的自变量。计算自变量和因变量之间的相关性。散点图也有助于识别模型的最佳变量。Seaborn的
pairplot函数可以帮助你一眼识别强相关的配对。你也可以运用直觉,判断哪个变量可能对你的结果影响最大。你不必检查每一个相关性。 - 选择一个变量:通常,与结果相关性最强的自变量是你的最佳选择,用它来开发你的第一个模型。
- 训练模型:使用统计软件模块来训练你的模型,找到最佳拟合线方程
y = Mx + B中的系数M和B。

一旦你训练好模型,就可以使用 y = Mx + B 方程来预测新的结果。这个回归方程指定了最佳拟合线,它量化了单个自变量和因变量之间的关系。在后面的课程中,你将学习如何向模型添加更多自变量以提高其预测能力。
线性回归的适用范围与总结
请记住,线性回归只能建模线性关系,这意味着自变量的变化会导致因变量的恒定变化。这就是为什么相关性对于建立线性回归模型如此有用,因为它也衡量线性关系的强度和方向。当然,也有方法可以建模非线性关系,但即使不完美,线性模型仍然可以很有效。
线性回归将你的推断工具箱提升到了一个新的水平,使你能够对数据中的新观察结果进行预测。在下一个视频中,你将看到如何在Python代码中开发线性回归模型。
总结

本节课中,我们一起学习了线性回归的基础知识。我们了解了线性回归如何通过 y = Mx + B 这样的方程来量化变量之间的关系,并用于预测。我们区分了线性回归与相关性,明确了自变量与因变量的概念,并掌握了构建一个简单线性回归模型的基本步骤。线性回归是数据分析中一个强大且基础的工具,为后续学习更复杂的模型奠定了基础。
069:自变量选择 🎯
在本节课中,我们将学习如何为线性回归模型选择最佳的自变量。我们将通过分析钻石数据集,使用可视化和统计方法来确定哪个特征最能预测钻石价格。
概述
上一节我们介绍了线性回归模型的训练和预测过程。本节中,我们将利用Python代码,为钻石定价问题选择最合适的自变量。我们的目标是预测新钻石的价格,因此需要找到与价格关联性最强的特征。
加载数据与模块
首先,我们需要加载必要的Python模块并读取数据。
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import scipy.stats as stats
df = pd.read_csv('diamonds.csv')


以下是数据预览,用于识别所有数值型列作为潜在的自变量。
df.head()
识别数值型特征
目前,我们只关注数值型数据。分类数据的处理方法将在后续课程中介绍。
创建一个包含所有数值型列的列表,包括价格列。
numeric_columns = ['carat', 'depth', 'table', 'x', 'y', 'z', 'price']

价格是我们的因变量,但为了分析各特征与价格的关系,我们需要将其包含在分析中。
可视化特征关系
使用散点图矩阵初步观察各特征与价格的关系。
sns.pairplot(df[numeric_columns])
plt.show()
从散点图矩阵中,我们可以观察到以下情况:
depth和table与价格的关系不明显。carat、x、y和z似乎与价格存在正相关关系,即随着这些值的增加,价格也倾向于增加。
量化相关性
为了更精确地评估,我们计算相关系数矩阵。
correlation_matrix = df[numeric_columns].corr()
print(correlation_matrix)
相关系数矩阵是对称的。我们重点关注矩阵最后一行(价格行)的数值。
x、y、z与价格有较强的相关性。carat(克拉重量)与价格的相关性最强,相关系数约为0.92。

这意味着,钻石的克拉重量可以解释其价格约92%的变异性。
深入分析最佳特征

为了更详细地观察carat与price的关系,我们绘制散点图。

plt.figure(figsize=(10, 6))
plt.scatter(df['carat'], df['price'], alpha=0.5, marker='.', color='rosybrown')
plt.xlabel('Carat')
plt.ylabel('Price')
plt.title('Relationship between Carat and Price')
plt.show()
从散点图可以清晰看出,随着克拉重量的增加,价格显著上升。
现在思考一个问题:这种关系是线性的还是非线性的?
实际上,这种关系更接近非线性。一条曲线会比一条直线更好地拟合这些数据点。尽管如此,由于两者之间的线性相关性很强,线性回归模型仍然可以提供一个相当准确的初步预测。当然,我们未来也可以使用更复杂的方法来提升模型精度。


总结
本节课中,我们一起学习了如何为简单线性回归模型选择自变量。
- 我们结合使用了可视化方法(散点图矩阵)和统计方法(相关系数矩阵)来评估各个自变量。
- 我们确定了
carat是与钻石价格相关性最强的特征,因此将其选为构建模型的最佳自变量。 - 我们还了解到,即使关系呈现一定的非线性,强线性相关性也使得线性回归成为一个良好的建模起点。
在下一讲中,我们将运行回归模型并解读初步结果。
070:Python数据分析(第3课)|模型训练 🎯

在本节课中,我们将学习如何使用Python的statsmodels库来训练一个线性回归模型。我们将以预测钻石价格为例,使用克拉重量作为第一个自变量,逐步完成模型的构建与训练过程。
概述 📋
上一节我们确定了线性回归模型的因变量(价格)和自变量(克拉重量)。本节中,我们将开始模型的训练。训练过程的核心是找到数据的最佳拟合直线方程,即确定斜率(M)和截距(B)。
模型训练的核心概念
线性回归模型的目标是找到一条直线,使其最接近地拟合数据点。这条直线的方程通常表示为:

y = Mx + B
其中:
- y 是因变量(我们想要预测的值,例如钻石价格)。
- x 是自变量(用于预测的特征,例如克拉重量)。
- M 是直线的斜率,表示x每增加1个单位,y的平均变化量。
- B 是截距,表示当x为0时y的值。
模型训练就是利用历史数据计算出最合适的M和B值的过程。
为什么需要截距(B)?
截距项为模型提供了灵活性。假设我们有一组数据,其最佳拟合线可能不经过原点(0,0)。如果强制模型没有截距(即B=0),拟合线就必须穿过原点,这通常会严重降低模型对数据的拟合精度。因此,保留截距项对于获得准确的预测模型至关重要。
训练步骤详解

以下是使用statsmodels库训练线性回归模型的具体步骤。

1. 导入必要的库
首先,需要导入用于统计建模的statsmodels库。
import statsmodels.api as sm
statsmodels.api常被简写为sm。
2. 准备变量
接下来,需要设置因变量Y和自变量X。
- Y(因变量):直接使用数据框中的价格列。
- X(自变量):不能仅仅使用克拉重量列。
statsmodels通过为X数据框中的每一列计算一个系数来工作。为了确保模型能同时计算出斜率(M)和截距(B)的系数,我们需要为截距添加一个常数列。

Y = df['price']
X = df['carat']
X = sm.add_constant(X) # 添加常数列以计算截距
执行sm.add_constant(X)后,X数据框将包含两列:一列是值全为1的const(常数项),另一列是carat。这样,模型就能分别为它们估计系数(对应B和M)。
3. 创建并拟合模型
现在,可以使用普通最小二乘法(OLS)来创建和训练模型。
model = sm.OLS(Y, X) # 创建OLS模型,注意先Y后X的顺序
results = model.fit() # 拟合模型,计算系数
重要提示:sm.OLS()函数的参数顺序必须是(Y, X),即先因变量后自变量。如果顺序颠倒,将导致模型错误,因为输入的意义被反转了。model.fit()方法执行实际的训练过程,利用数据计算出最佳的M和B值。


4. 查看模型结果
训练完成后,可以查看模型的详细摘要。
print(results.summary())
直接打印results对象只会得到一个包装器信息。调用.summary()方法会输出一个包含大量信息的表格,如R平方值、系数(const和carat对应的值)等,这些是评估模型性能的关键指标。
步骤回顾总结
本节课中我们一起学习了线性回归模型的训练流程:
- 准备数据:将因变量Y定义为价格列,将自变量X定义为克拉重量列,并使用
sm.add_constant()为其添加常数列。 - 创建模型:使用
sm.OLS(Y, X)函数创建一个普通最小二乘回归模型对象。 - 训练模型:调用
model.fit()方法,让模型基于数据计算出最佳拟合直线的斜率(M)和截距(B)。 - 查看结果:通过
results.summary()输出训练结果的详细摘要,其中包含了模型的核心参数。


做得很好!你已经成功创建并拟合了你的第一个回归模型。在下一节课中,我们将学习如何解读结果摘要中的关键输出,例如R平方和系数,以评估模型的有效性。
071:回归模型输出解读
在本节课中,我们将学习如何解读线性回归模型的输出结果。理解这些输出是评估模型有效性和理解变量间关系的关键。
🎯 模型输出概述
训练完线性回归模型后,需要解读其输出。这些信息有助于评估自变量对因变量行为的建模效果。
以下是上一视频中用于预测钻石价格的回归模型输出截图,该模型使用克拉数作为预测变量。

你并不需要关注所有信息,注意力应集中在几个关键点上。
🔑 关键输出指标解读
上一节我们介绍了回归模型输出的存在,本节中我们来看看需要关注的具体指标。
以下是需要关注的三个核心部分:

- R平方值
- 系数(包括常量和自变量系数)的 P值
- 系数本身的 数值
📈 1. R平方值
R平方衡量的是因变量的变异中,可由自变量预测的比例。
本质上,R平方告诉你克拉数预测价格的可靠程度。如果我只告诉你一颗钻石的克拉数,你能多准确地预测其价格?
R平方值通常在0到1之间。值越高,说明自变量对因变量变异的解释能力越强。虽然存在一些细微差别,但通常是越高越好。
本例中的R平方值为 0.849,这个值相当高。
你可以将此结果解释为:克拉数解释了价格变异的 84.9%。
🧪 2. 系数的P值
在继续解读之前,先看看与每个系数相关的P值。它们告诉你系数是否具有统计显著性。
解读这些P值的方法与其他假设检验相同。
- 零假设:回归系数等于0。记住,斜率和截距都是系数。所以,默认状态是系数对因变量没有影响。
- 备择假设:回归系数不等于0。你试图为这个结果寻找证据,因为你想证明自变量确实会影响因变量。
因此,如果你的数据提供了足够的证据来拒绝零假设,你就找到了模型中一个重要的特征。
与任何假设检验一样,你需要选择一个你认可的置信水平。95%的置信度(α = 0.05)是常见的标准。
- 如果一个系数的P值 高于 α,意味着该自变量不能很好地预测因变量。你就不应继续用它进行解读和预测。
- 如果P值 低于 0.05,那么你可以拒绝零假设,得出结论认为该自变量能很好地预测因变量。
在本例中,两个系数的P值都接近0,远低于0.05,因此它们具有统计显著性。这个模型能有效预测钻石价格。
➕ 3. 系数值
既然已经验证了统计显著性,现在可以看看系数的值了:常量是 2256,克拉数的系数是 7756。
你可以用这些值来构建最佳拟合线的方程。记住,这正是线性回归的最终目的。
该方程如下:
price = 7756 × carat + 2256
因此:
- 一颗1克拉的钻石价格约为
7756 × 1 + 2256 = 10012美元。 - 一颗2克拉的钻石价格约为
7756 × 2 + 2256 = 17768美元。
无需手动计算,稍后你将看到如何使用 statsmodels 一次性预测许多钻石的价格。

🤖 利用大语言模型辅助解读

顺便提一下,大语言模型非常擅长从这些复杂的模型摘要中提取关键信息。你可以使用像ChatGPT这样的应用来帮助你分析结果。
事实上,我们可以使用一个具有强大推理能力的开源模型。记住,你可能可以使用更新的模型。
注意:务必确保你没有向大语言模型分享任何私有或专有的模型结果。


你可以通过赋予模型角色和任务来使用它。例如,可以使用如下提示词:
“你是一位擅长用简单方式解释复杂概念的专家统计学家。我是一位正在开发线性回归模型以根据钻石克拉数预测其价格的同事。请帮我解读训练模型的结果,指出最重要的部分,而不是以同等详细程度解释输出的每个部分。”
然后,截取结果图并粘贴进去。




模型首先解释了模型的R平方,指出该模型仅用克拉数就解释了约85%的钻石价格变异,并说明这对于单一变量来说是非常高的解释力。
它同时强调,克拉数是关键预测变量,系数约为7756。这意味着每增加一克拉,模型预测价格将增加约7756美元。P值极小,表明该系数具有统计显著性。
它还强调了称为 F统计量 的指标及其关联的P值。该P值也非常小,并指出这证实了模型整体上是显著的。
它也提到了其他一些诊断统计量,但强调主要结论是:克拉数对价格具有很强的预测能力。
当你开始向回归模型中添加更多变量,并以高度严谨的态度分析输出时,大语言模型可以成为解读过程中极佳的思考伙伴。
✅ 总结

做得很棒!你刚刚解读了Python中线性回归模型的结果。


你使用了 R平方值、P值 和 系数 来对你的模型做出有意义的结论。





请跟随我进入本课的最后一个视频,学习如何使用你的模型进行预测。
072:Python数据分析(第3课)|预测分析 🎯
概述
在本节课中,我们将学习如何使用线性回归模型进行预测分析。我们将从理解预测的基本概念开始,逐步学习如何用代码实现单个值和多个值的预测,并讨论模型预测结果的合理性评估。
预测分析的基本概念
上一节我们介绍了如何解读R平方和系数,本节中我们来看看如何利用这些结果进行预测。
预测的本质是使用拟合好的线性回归模型,为新的输入值(例如钻石克拉数)估算对应的输出值(例如钻石价格)。在散点图上,这相当于在最佳拟合线上找到对应X坐标的Y坐标值。


例如,要预测一颗1.5克拉钻石的价格,我们首先在X轴上找到1.5的位置,垂直向上找到最佳拟合线(红色线)的交点,再从该交点水平向左读取Y轴上的价格值,估算价格约为9000美元。






代码实现:单值预测


我们已经完成了数据导入、加载以及使用克拉数预测价格的线性回归模型拟合。
模型系数可用于构建最佳拟合线的方程:y = mx + b 或 价格 = m * 克拉数 + b。系数存储在 results.params 中(params 代表参数)。
以下是获取并使用系数进行预测的步骤:
- 访问模型系数:
results.params是一个Pandas Series对象,可以通过索引访问其值。results.params[‘Carat’]给出斜率m。results.params[‘const’]给出截距b。






- 进行预测:给定一个新的克拉值(例如1.5),将其赋值给变量
carat,然后使用方程计算预测价格。
模型预测这颗1.5克拉的钻石价值约为9378美元。carat = 1.5 price = results.params[‘Carat’] * carat + results.params[‘const’]
代码实现:多值预测
为了同时预测多个值,我们可以对整个序列进行向量化运算。
首先,我们可以使用模拟方法生成一些新的钻石克拉数据来测试模型。以下是生成随机样本的方法:
import numpy as np
carrots = np.random.uniform(low=0, high=5, size=20)
这段代码使用均匀分布,在0到5之间(原始数据的克拉范围)生成20个随机值,模拟20颗钻石的克拉数。carrots 变量是一个NumPy数组。



现在,将相同的预测方程应用于整个 carrots 数组,而不是单个值:
prices = results.params[‘Carat’] * carrots + results.params[‘const’]
print(prices)
输出结果是每颗钻石的估计价格。

评估预测结果的合理性
观察这些预测价格,判断它们是否合理至关重要。
例如,第一颗2.35克拉钻石的预测价格为15973美元,这看起来合理,因为2.3克拉的钻石确实很大。然而,我们也看到了一个约为-1500美元的负值预测,这对应一颗0.09克拉的钻石。显然,钻石不可能有负价格。

回顾最佳拟合线图,可以发现大部分数据点集中在0.5到2.5克拉之间。模型在这个数据密集区域预测效果最好。对于克拉数达到3的钻石,实际价格分布非常分散,模型的预测效果不佳。
了解模型的局限性后,我们可以调整模拟范围,使其只生成0.5到2.5克拉之间的钻石数据。这样,我们就在模型表现最好的范围内进行预测和应用。

总结与后续步骤
本节课中我们一起学习了如何利用线性回归模型预测新数据点。
以下是核心要点总结:
- 使用
results.params[‘Carat’]和results.params[‘const’]访问计算出的m和b值。 - 对于单个新值(如1.5克拉),使用方程
m * carat + b进行预测。 - 通过将公式中的单个值替换为一个序列(Series/Array),可以一次性预测多个值,得到一个预测价格的NumPy数组。
- 必须了解模型预期的输出类型,审查其输出结果,并判断这些结果是否合乎逻辑。
在本课程中,你已经深入学习了线性回归:它的概念原理、如何训练模型以及如何使用Python代码进行预测。
接下来,你将完成本课的练习作业和实验。在实验环节,你将开发一个新模型来预测伦敦的房价。完成作业和实验后,我们将在下一课中见面,学习如何开发包含多个变量的线性回归模型。


073:多元线性回归 📊
在本节课中,我们将要学习如何将线性回归模型从单一自变量扩展到多个自变量,即多元线性回归。我们将探讨为何使用多个变量能提升模型的预测能力,并通过一个预测大学毕业时间的实例来理解其应用。
概述
线性回归是建模两个变量之间关系的优秀技术。你也可以将模型扩展到单个自变量之外,创建多元线性回归模型。
上一节我们介绍了简单线性回归,它作为起点和推断分析很有用。你可以选择一个强预测因子来建立一个好的基线模型。例如,在上节课中我们看到,克拉数预测了钻石价格约85%的变异性。

然而,对于许多问题,使用多个自变量可以显著提高模型的预测能力。你难道不想做得比85%更好吗?
设计多元回归模型
本节中,我们来看看如何为实际问题选择自变量。考虑预测大学生的毕业时间。一个人可能提前毕业,可能在传统的四年制时间点之前,也可能按时在四年毕业,或者可能需要更多学期,比如长达六年(这是分析中常见的截止点)。
许多大学有兴趣了解哪些因素能预测一个人的毕业时间。识别可能花费更长时间毕业的学生有助于提供早期支持,而识别可能提前毕业的学生则有助于课程容量规划。

你认为可以使用一个人的哪些变量来帮助预测其毕业时间?有很多选择,但可能会想到的几个是:高中GPA、第一年GPA、大学专业以及年龄、性别和家庭支持等个人属性。
评估自变量
以下是评估自变量与因变量关系的一些思考:
- 考虑高中GPA:随着高中GPA的提高,你预计毕业时间会如何变化?平均而言,它应该下降,因为学生更有可能在课程学习中取得成功。这个变量似乎很大程度上捕捉了学生的学术能力。
- 考虑自变量年龄:年龄如何影响一个人的毕业时间?更高的年龄可能预示着更长的毕业时间,因为年龄较大的学生通常需要平衡工作、家庭和学校的多重责任。这种关系似乎更多是关于个人的生活状况,而非学术能力。
这两个变量都可以帮助你预测毕业时间,而且它们似乎捕捉了个人可能花费更多或更少时间毕业的不同根本原因:学术能力与个人状况。
组合变量的力量
想象你创建了一个使用高中GPA预测毕业时间的简单线性回归模型。该模型的R平方可能在0.2左右,因此它解释了毕业时间约20%的变异性。你也可以创建一个使用年龄的简单线性回归模型,其R平方可能为0.1,解释了约10%的变异性。
或者,你可以创建一个多元线性回归模型,将毕业时间预测为高中GPA和年龄的函数。你希望新模型中的R平方值发生什么变化?当结合这两个变量时,你希望看到R平方值高于0.2。如果这两个变量确实衡量了影响毕业时间的两个不同根本原因,那么当同时考虑这两个因素时,你的模型将具有更强的预测能力来解释毕业时间。
你可以进一步扩展这个模型,以包含更多变量,如第一年GPA,甚至是分类变量如性别。通常,你会希望使用最能可靠预测因变量的变量组合。高中GPA和年龄相互补充得很好,因为它们有助于更完整地构建影响毕业时间的不同因素图景。
将第一年GPA添加到此模型中可能不会带来巨大改进,因为它可能解释了与高中GPA相同的部分毕业时间变异,但你仍然应该尝试。试验不同的变量组合,甚至可能是重叠的变量,以找出最有效的方法。

总结
本节课中我们一起学习了如何创建包含多个自变量的线性回归模型。这种技术称为多元线性回归。与简单线性回归模型一样,你需要选择与因变量强相关的自变量。运用你的直觉来评估每个自变量为何可能显著影响因变量。直觉是一个有用的指导,但你最终需要使用模型摘要来评估模型的强度。请记住,分析的最佳方法是将你的直觉与数据驱动的见解结合起来。

现在你已经了解了如何设计多元线性回归模型,请跟随我到下一个视频,看看代码的实际应用。
074:多元线性回归模型训练 🚀
在本节课中,我们将学习如何将简单的线性回归模型扩展为多元线性回归模型。我们将使用多个自变量来预测钻石价格,并通过代码实现这一过程。
概述
你已经了解了如何使用线性回归模型。之前,我们开发了一个仅根据钻石克拉数预测其价格的模型。该模型的R平方值约为0.85,表明克拉数可以解释价格约85%的变异性。然而,这个模型的准确度仍有提升空间。客户反馈需要更精确的模型。我们手头还有其他潜在的自变量,如尺寸(X, Y, Z)、切工和颜色,这些特征可能从不同方面影响价格,从而帮助我们提高模型的准确性。
本节我们将从添加钻石的长度(X)这一特征开始,构建一个多元回归模型。
从简单回归到多元回归
上一节我们介绍了如何使用单一变量(克拉数)进行预测。本节中,我们来看看如何将模型扩展为包含多个预测变量。
假设我们想在模型中添加钻石的尺寸。其中,X代表钻石面朝上时的长度。现在,我们的模型将估计三个系数,而不再是两个。模型公式将从 价格 = m * 克拉数 + B 变为包含多个变量的形式。
让我们使用M1和M2作为系数符号,模型公式可能类似于:
价格 = M1 * 克拉数 + M2 * X + B
你的模型将计算M1、M2和B的值。
代码实现步骤
以下是构建多元线性回归模型的具体步骤。我们将基于之前的简单线性回归代码进行修改。
首先,回顾一下之前的步骤:你已经导入了必要的模块,加载了数据,并拟合了仅使用克拉数预测价格的线性回归模型。
-
修改预测变量列表:在简单线性回归中,
X只包含“克拉数”一列。现在,我们需要将其改为一个预测变量列表。# 定义预测变量列表 predictors = ['carat', 'x'] X = df[predictors]这段代码将选择数据框中‘carat’和‘x’这两列作为自变量。
-
添加常数项:与简单回归一样,我们需要使用
sm.add_constant为模型添加截距项。X = sm.add_constant(X)现在,你的自变量数据框
X将包含三列:常数项、克拉数和X。 -
拟合模型与查看结果:使用
sm.OLS拟合模型并打印摘要,代码与之前相同。model = sm.OLS(y, X) results = model.fit() print(results.summary())statsmodels会为列表中的每一个自变量(包括常数项)生成一个系数。
模型结果分析
运行上述代码后,你的回归模型得到了小幅改进,R平方值提升了约0.5个百分点。这表明,在克拉数的基础上增加X特征,确实能稍微更好地预测钻石价格。
查看三个系数的P值,它们都具有统计显著性。
- 克拉数的系数现在约为 10130(以科学计数法显示),高于之前的简单模型。
- X的系数为 -127。
- 截距项的系数也下降至 -1738。
在下一节视频中,你将学习如何更深入地解释这些系数的含义。
使用模型进行预测
你可以使用与之前相同的逻辑来预测新钻石的价格,只需在公式中加入新的变量。
例如,查看索引为2107的钻石。它的克拉数为1.5,X为7.13毫米,真实价格为8580美元。
以下是预测其价格的步骤:
- 保存特征值。
carat_value = 1.5 x_value = 7.13 - 根据模型结果获取系数。
M1 = results.params['carat'] M2 = results.params['x'] B = results.params['const'] - 更新价格预测公式。
运行此代码,你得到的预测价格约为9605美元。predicted_price = M1 * carat_value + M2 * x_value + B
尝试添加更多变量
根据R平方值,模型仅略有改善。你可以尝试将更多变量(如Y和Z)添加到预测变量列表中,然后再次运行相同的代码。
以下是需要更新的代码部分:
predictors = ['carat', 'x', 'y', 'z'] # 将y和z加入列表
X = df[predictors]
X = sm.add_constant(X)
# ... 后续拟合和摘要代码不变
运行后,你会发现R平方值仅提高了0.1%,改善微乎其微。尽管这些新变量的系数P值仍接近0,具有显著性,但对于之前例子中的那颗钻石,预测价格变为约9521美元,准确度并未提升。
请不要气馁。构建回归模型是一个迭代过程,需要通过大量实验才能找到真正提升模型准确性的方法。
总结

本节课中,我们一起学习了如何创建多元线性回归模型。
- 核心方法:创建多元线性回归模型的代码与创建简单模型几乎相同。唯一区别在于,你需要创建一个预测变量列表,而不是使用单个变量。
predictors = [‘carat‘, ‘x‘, ‘y‘] # 示例列表 X = df[predictors] X = sm.add_constant(X) - 结果解读:在模型结果摘要中,每个自变量都会有一个P值和一个系数。你可以使用P值来判断,在模型存在其他变量的情况下,该变量是否仍是显著的预测因子。
- 进行预测:然后,你可以使用包含多个自变量及其对应系数的方程来预测新值。

解读多元线性回归模型需要考虑变量在模型中的上下文关系。 在接下来的视频中,我们将学习如何进行负责任的、细致的模型解读。
075:Python数据分析(第3课)|多元回归结果解读 📊
在本节课中,我们将学习如何解读多元线性回归模型的结果。我们将重点关注R平方值、P值、系数的含义,并探讨多重共线性这一常见问题及其影响。
多元回归模型解读概述 📈
上一节我们介绍了如何构建多元线性回归模型。本节中,我们来看看如何解读模型输出结果。
向模型添加更多变量时,解读需要更加谨慎。在之前的视频中,我们构建了一个多元线性回归模型,基于克拉重量(carat)、X、Y和Z尺寸预测钻石价格,得到了如下结果摘要。
R平方值为0.854,相比仅使用克拉重量的简单模型仅有轻微提升。P值接近0表明每个预测变量都是显著的。
解读多元线性回归模型时,必须在模型的整体背景下得出结论。例如,此处的R平方值反映了整个模型的预测能力,而不仅仅是克拉重量一个变量。模型可以使用这些变量解释约85.4%的价格变动,但无法得出每个变量对解释力各自贡献多少的结论。
P值和系数应在模型背景下考虑。

系数与P值的解读 🔍
以下是解读模型系数和P值的关键点:
克拉重量(carat)的解读
对于克拉重量,其接近0的P值表明它与价格存在非零关系。更具体地说,如果所有其他变量(X、Y、Z)保持不变,克拉重量的变化仍会影响钻石价格。因此,如果两颗钻石尺寸相同,重量(克拉)更高的那颗价格会更贵。
克拉重量的系数表明,在其他所有变量保持不变的情况下,重量每增加1克拉,钻石价格预计增加10230美元。
模型的系数有助于理解各变量对价格影响的大小,但难以解释其影响价格的原因。
多重共线性现象 🔄
例如,在早期视频中调查数据集关系时,我们看到了X轴为x尺寸、Y轴为价格的类似图表。你看到的是正相关还是负相关关系?这是正相关关系,因为x增加,价格也上升。
然而,模型为x计算出了一个负系数。模型计算表明,x每增加一个单位,价格下降884美元。这个系数与我们对x和价格关系的直觉不匹配。
这种不匹配的发生,是因为克拉重量和x都与因变量价格高度相关,并且彼此之间也高度相关。这种现象称为多重共线性。当克拉重量和x一同变动时,模型很难厘清究竟是哪一个在推动价格上涨。因此,模型使用两个变量共同捕捉对因变量的整体影响。
在实践中,这可能表现为一个变量具有正系数,而另一个具有负系数。
多重共线性的定义与影响 ⚠️
当两个或更多自变量彼此高度相关,并且也与因变量高度相关时,就会发生多重共线性。例如,考虑钻石数据集中的克拉重量和X尺寸,它们高度相关。钻石越重,通常尺寸也越大。
当两个变量高度相关时,模型很难确定究竟是哪个变量在驱动因变量(价格)的变化。这颗钻石更贵是因为它更重,还是因为它更大?
多重共线性很常见,因为经常会遇到许多变量在解释内容上存在重叠的数据集。例如,钻石数据集包含许多衡量钻石重量或尺寸的指标,包括克拉重量、台面、X、Y、Z等,这些指标都彼此相关。
它通常不会影响模型的整体预测能力,但会使理解每个自变量的个体影响变得更加困难。因此,在解读系数和P值时,多重共线性很重要。如果是在预测新的数据点,则影响不大。
识别与处理多重共线性 🛠️

在回归结果表中,如果statsmodels怀疑模型中存在多重共线性,通常会给出警告,但多重共线性也可能在没有此警告的情况下发生。
以下是处理多重共线性的方法:
处理选项
一种选择是移除高度相关的自变量,只保留其中一个。也可以采用更复杂的解决方案,例如创建这些多个变量的组合特征。这些解决方案超出了本课程的范围,但需要知道的是,你有很多选项来解决这个问题。
总结与下一步 🎯
本节课中,我们一起学习了如何解读多元回归模型的结果。我们理解了R平方值、P值和系数的含义,并深入探讨了多重共线性现象及其对模型解释的影响。

当多元线性回归模型未能显著提升R平方值时,可以尝试添加分类变量。请跟随我到下一个视频,学习将分类变量纳入回归模型的关键技术。
076:分类数据编码 📊
在本节课中,我们将学习如何将分类变量(如文本类别)转换为数值形式,以便将其纳入线性回归模型进行分析。分类变量是数据分析中常见的数据类型,但统计模型通常只接受数值输入。我们将通过一个钻石数据集的实例,详细介绍编码过程。
概述
线性回归模型要求所有预测变量都是数值型的。然而,数据集中的分类变量(例如钻石的颜色、产品的品牌)包含的是非数值信息。为了在模型中使用这些变量,我们必须对它们进行“编码”,即将其转换为数值格式。本节将介绍使用Pandas库的get_dummies函数进行“独热编码”的方法。
分类变量编码的必要性
上一节我们介绍了多元线性回归模型。本节中我们来看看如何处理分类变量。
你可以将分类变量加入模型以提高其性能。但是,这些变量需要一些额外的预处理步骤。你一直在使用的用于创建线性回归模型的statsmodels库的OLS函数不接受非数值变量。因此,为了将分类变量用作预测变量,你需要将其转换为数字。

实例:钻石颜色编码
让我们通过使用钻石数据集中的“颜色”特征来逐步讲解一个例子。该特征包含从D到J的值。D代表无色钻石,这是最佳等级,钻石从D到J颜色逐渐变黄。
在你的数据中,可能有10颗钻石具有这些颜色值。将这些类别编码为数值最直接的方法是使用一个名为get_dummies的Pandas函数。该函数将创建新列,每个类别对应一列。如果钻石不是该颜色,则在该列中分配0;如果是该颜色,则分配1。
因此,对于第一行,你会在“颜色_H”列中得到1,在其他所有列中得到0。最后一个复杂之处是,请注意没有“颜色_D”列。因此,第二行只有0。
这种省略一个可能类别的技术可以去除冗余信息。如果你知道一颗钻石不是任何其他颜色,你就不需要说它是颜色D。如果你知道一颗钻石是任何其他颜色,你就知道它不是颜色D。你必须完成此步骤以避免模型拟合时出现问题。
在模型中加入颜色变量
假设在本笔记本中,你已经导入了模块,将数据读入变量df,并基于之前的变量开发了一个预测钻石价格的多元线性回归模型。现在,你希望根据客户的要求进一步提高其准确性。


“颜色”似乎是一个有用的潜在自变量,因为它可能比像X、Y和Z这样的变量提供更多的附加预测能力,而这些变量可能与“克拉”重量冗余。你已经看到,此数据集中的独特颜色是从D到J,以字母表示。




一个好的做法是使用Seaborn库的条形图来显示颜色和价格之间的关系。在X轴上,你有钻石的颜色;在Y轴上,有其平均价格。你可以忽略之前见过的未来警告。
仅看此图,在没有其他信息的情况下,颜色D和E的钻石价格似乎非常相似。然后价格开始上涨,一直增加到J。根据你对颜色的了解,这似乎不正确。为什么完美的无色钻石会比偏黄的钻石价值更低?你需要进一步调查。
要将颜色变量添加到回归模型中,首先将其添加到预测变量列表中。然后,你需要使用pd.get_dummies函数。
以下是使用get_dummies函数的关键步骤:

- 指定要编码的列:使用
columns参数列出你想要转换为虚拟变量的列名。 - 删除第一列以避免冗余:设置
drop_first=True参数。这是必要步骤,可以防止“虚拟变量陷阱”。 - 确保输出为数值类型:设置
dtype=int参数,确保输出是整数(0或1)而不是布尔值。

核心的编码公式如下:
encoded_predictors = pd.get_dummies(df[predictors], columns=[‘color’], drop_first=True, dtype=int)
第一个钻石是颜色E,因为该列的值为1。第二个也是E,第五个是J。请注意,没有D列,因为第一个类别被删除了。因此,颜色为D的钻石的每一列都将是0。
处理布尔值输出与模型拟合
注意,这些值最初都是布尔类型。下一步你应该尝试拟合模型。但运行模型时,你会得到错误。事实证明,statsmodels的OLS只适用于数值数据。这正是你最初处理虚拟变量的原因。



让我们向大语言模型寻求此任务的帮助。对于这行代码,如何获得虚拟变量的数值输出而不是布尔值?它提供了多个选项。

大语言模型给了你几个选择。首先,它告诉您可以在pd.get_dummies函数中指定dtype=int。让我们使用第一个选项。
进行更改并再次运行该代码,你现在有了数字,这正是你需要的。作为人类阅读起来也更容易一些。


总结
本节课中我们一起学习了分类数据编码的核心方法。
总结一下,你使用pd.get_dummies函数对分类数据进行编码。你使用了三个关键参数来使数据适合回归分析:
columns参数指定你想要编码的列。drop_first=True参数用于删除冗余数据。请记住,此步骤是必要的。- 最后,
dtype=int参数确保在结果数据框中得到数字而不是布尔值。

现在你已经设置好了分类数据,完成了将其添加到回归模型所需的大部分工作。请跟随下一节视频来训练你的新模型。
077:类别数据建模 📊
在本节课中,我们将学习如何将编码后的类别数据(哑变量)作为预测因子纳入线性回归模型,并解释模型结果。我们将使用钻石数据集,重点关注颜色这一类别变量。
概述
上一节我们介绍了如何使用 pd.get_dummies 将类别变量(如钻石颜色)转换为哑变量。本节中,我们将把这些哑变量加入线性回归模型,进行训练与测试数据分割,并深入解读模型系数。
构建模型

在将颜色编码为哑变量后,数据框现在包含了“克拉”和代表各个颜色等级的哑变量列。现在可以构建线性回归模型。
为了评估模型在新数据上的表现,通常需要将数据分割为训练集和测试集。
以下是数据分割步骤:

- 设定测试集大小:例如,预留1000颗钻石的数据作为测试集。
- 分割特征数据 (X):
X_test:数据框的前1000行。X_train:数据框从第1000行开始到末尾的所有行。
- 分割目标数据 (Y,即价格):
y_test:价格列的前1000个值。y_train:价格列从第1000个值开始到末尾的所有值。
关键点:必须确保 X 和 y 的行是对齐的,即 X_test 和 y_test 对应同一批钻石,X_train 和 y_train 对应另一批钻石。
# 假设 df 是包含特征(包括哑变量)的数据框,y 是价格列
X_test = df.iloc[:1000] # 前1000行作为测试特征
X_train = df.iloc[1000:] # 第1000行之后作为训练特征
y_test = y.iloc[:1000] # 前1000个价格作为测试目标
y_train = y.iloc[1000:] # 第1000个价格之后作为训练目标
分割后,X_test 和 y_test 的长度都应是1000,X_train 和 y_train 的长度应大致相同(约53000)。
训练模型与评估
使用与之前相同的代码拟合模型,只需将数据替换为训练集。
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(X_train, y_train) # 使用训练数据拟合模型
查看模型的 R² 值,发现相比仅使用“克拉”作为特征的模型,新模型的解释力提升了约1.5%。检查每个系数的 P 值,它们都显示为显著,因此可以继续解读系数。
解读模型系数
模型的系数揭示了有趣的信息。
- 克拉系数:现在约为 8000美元/克拉(在其他条件不变的情况下)。这意味着,在控制颜色等因素后,每增加一克拉,钻石价格平均上涨约8000美元。



- 颜色哑变量系数:解读这些系数需要特别注意。每个颜色的系数是相对于被丢弃(Dropped) 的基准类别而言的。在创建哑变量时,我们设置了
drop_first=True,因此颜色“D”被作为基准类别,没有出现在特征中。
以下是颜色系数的解读方式:
- 系数为负值,意味着该颜色等级的钻石平均价格低于基准类别(D色)钻石。
- 例如:
- E色钻石的系数约为 -94美元。这意味着,在克拉数相同的情况下,E色钻石的平均价格比D色钻石低约94美元。
- I色钻石的系数约为 -1054美元。这意味着,在克拉数相同的情况下,I色钻石的平均价格比D色钻石低约1054美元。
发现数据中的洞察
这个结果帮助我们解释了一个最初看似矛盾的数据模式。
回顾之前颜色与价格的条形图,I色和J色钻石的平均价格似乎更高,这容易让人误以为颜色越黄(等级越低)越值钱。
然而,回归分析结合另一个事实(颜色越黄,钻石克拉数往往越大)揭示了真相:

- 颜色等级较低(如I、J色)的钻石,其平均克拉数更大。
- 克拉数是价格的主要驱动因素。
- 因此,I、J色钻石的平均价格更高,主要是因为它们的克拉数更大,而非颜色本身。
对于两颗克拉数完全相同的钻石,一颗是D色,一颗是J色,D色钻石的价值会更高。回归模型通过控制变量(克拉数),帮助我们剥离了颜色对价格的直接影响,从而发现了这一深层关系。
总结
本节课中我们一起学习了:

- 训练-测试分割:我们使用切片操作将数据分割为训练集和测试集,这是一种评估模型泛化能力的标准做法。
- 模型训练:我们使用包含类别哑变量的特征训练了线性回归模型,并观察到模型性能的提升。
- 系数解读:我们学会了如何解读哑变量的系数——它们总是相对于被丢弃的基准类别而言的。在本例中,所有颜色系数均为负,表明在控制克拉数后,D色钻石是最昂贵的。
- 数据洞察:模型结果帮助我们纠正了一个初步的误解,揭示了“低颜色等级钻石价格更高”的现象主要是由其更大的尺寸(克拉数)驱动的,而非颜色本身。
通过引入类别变量,我们不仅改进了模型,还获得了对数据更深刻、有时是反直觉的理解。在下一节中,我们将使用这个改进后的模型来预测新钻石的价格。
078:多元回归预测 📊
在本节课中,我们将学习如何使用训练好的多元线性回归模型,对新的数据点进行预测。我们将从单个数据点的预测开始,然后扩展到对整个测试数据集进行批量预测,并讨论预测过程中需要注意的关键事项。
模型预测概述
上一节我们介绍了如何构建一个使用克拉重量和颜色来预测钻石价格的多元线性回归模型。本节中,我们来看看如何使用这个训练好的模型进行实际预测。
一旦你开发出一个改进的模型,就可以用它来预测新数据点的因变量。
让我们从上次停止的地方继续。你已经导入了必要的模块,读取了数据,并使用克拉重量和颜色作为自变量,以钻石价格为因变量,建立了一个线性回归模型。你使用 pd.get_dummies() 对颜色变量进行了编码,并预留了1000行数据存储在变量 X_test 中用于测试。
预测单个钻石价格
现在,你可以使用 results.predict() 方法来预测一颗新钻石的价格。
以下是具体步骤:

首先,查看 X_test 变量中的第一颗钻石。使用 X_test.iloc[0] 将其保存到一个新变量 diamond_1 中并查看。
diamond_1 = X_test.iloc[0]
print(diamond_1)
你能看出这是一颗什么样的钻石吗?

这是一颗0.23克拉、E色的钻石。它非常小,颜色很纯净,但并非最纯净的等级。
接着,使用模型对这颗钻石进行预测:
predicted_price = results.predict(diamond_1)
print(predicted_price)
你得到的预测价格是负364美元。这是一个非常低的价格。请记住,这个模型在处理非常小的钻石时表现有些挣扎。因此,尽管整体上这是一个优秀的模型,但对于像这样的小钻石,其价格会被低估。
为了验证,查看 y_test.iloc[0] 中这颗钻石的真实价格:
actual_price = y_test.iloc[0]
print(actual_price)
真实价格是326美元。因此,对于价值数万美元的钻石而言,模型的预测误差大约为600美元。这个误差不算大,但对于这颗特定的钻石来说,是一个相当显著的误差。你将在接下来的视频中进一步评估模型的准确性。
批量预测多个钻石价格
你也可以一次性为所有1000颗测试钻石预测价格。
以下是具体操作:
predicted = results.predict(X_test)
就这样简单。现在,让我们查看一下 predicted 变量。
你期望它是什么类型的数据?它是一个 Series 对象,即一列预测出的价格值。
如果你抽样查看10行数据,可以看到模型预测出的各种价格:
print(predicted.sample(10))
在这里,你可以看到一颗钻石的预测价格大约在4000美元左右,另一颗大约在3600美元,同时你还会看到几个负的预测值,很可能又是针对非常小的钻石。
你还可以使用 predicted.describe() 来了解更多关于这个序列的信息:
print(predicted.describe())
如预期所示,共有1000个值,平均价格约为3100美元,预测出的最高钻石价格大约在7600美元左右。
预测方法总结与关键点
回顾一下,你可以使用 model.predict() 来预测单个自变量集合(如 X_test 数据框中的一行)对应的因变量。或者,你也可以对整个数据框(如整个 X_test)使用 model.predict() 进行批量预测,之后你将得到一个包含每颗钻石预测价格的序列。
请记住,使这一切正常工作的关键是,你的 X_test 数据框的格式必须与用于训练模型的数据(在本例中是 X_train)完全一致。



如果不一致,当你进行预测时,可能会得到一些意想不到的结果,或者 statsmodels 可能会生成错误。

你在前面已经看到,你的模型对于某些值的预测效果并不理想。在下一个视频中,我们将一起探索在创建多元线性回归模型后,如何评估其性能。
本节课总结
在本节课中,我们一起学习了如何使用训练好的多元线性回归模型进行预测。我们掌握了如何对单个数据点进行预测,也学会了如何对整个测试集进行批量预测。最重要的是,我们理解了确保预测数据格式与训练数据格式一致是获得准确预测结果的关键。在下一课,我们将深入探讨如何评估模型的整体性能。
079:多元线性回归模型评估 📊
在本节课中,我们将学习如何评估一个已构建的多元线性回归模型。我们将超越简单的R平方值,探索通过比较预测值与实际值、可视化分析以及计算误差指标来全面理解模型性能的方法。
概述
上一节我们介绍了如何构建多元线性回归模型。本节中,我们来看看如何评估这个模型的性能。评估不仅限于解读结果摘要,还需要使用其他工具来理解模型的预测效果。
模型评估的核心方法

评估模型时,需要考虑R平方以外的指标。一个常见的技术是将模型的预测值与实际值进行比较,这样可以观察模型与现实情况的偏差。
以下是评估模型的主要步骤:
- 比较预测值与实际值:通过可视化或计算相关性来评估。
- 计算残差:理解每个预测的误差大小。
- 计算误差指标:如平均绝对误差,量化模型的整体误差水平。
1. 可视化预测值与实际值

对于多元线性回归,由于涉及多个自变量,无法简单地通过自变量与因变量的散点图来评估模型拟合度。当变量达到3个、4个、5个或更多时,我们就进入了超维空间。
因此,一个有效的方法是绘制预测值与实际值的散点图。
代码示例:创建散点图
# 假设 model 是已训练好的模型,X_test 和 y_test 是测试集
y_pred = model.predict(X_test)
y_actual = y_test
# 使用 seaborn 绘制带回归线的散点图
import seaborn as sns
sns.regplot(x=y_pred, y=y_actual, line_kws={'color': 'black'})
在这个散点图中,X轴是预测价格,Y轴是实际价格。在理想情况下,预测值与实际值应呈完美正相关,即所有点都应落在 y = x 这条直线上。

代码示例:添加理想参考线
import matplotlib.pyplot as plt
# 在现有图形上添加 y=x 的红色虚线
plt.plot([y_actual.min(), y_actual.max()], [y_actual.min(), y_actual.max()], 'r--')
plt.show()
通过观察散点图,我们可以判断预测值与实际值的线性关系以及是否存在系统性偏差(例如,模型是否持续高估或低估某些价格区间的钻石)。

2. 计算多重相关系数


除了可视化,我们还可以量化预测值与实际值的相关性,这个指标称为多重R。

公式与代码
多重R是预测值与实际值之间的相关系数,其值在0到1之间,值越高表示模型的预测能力越强。
multiple_r = y_pred.corr(y_actual)
print(f"多重R (预测值与实际值的相关系数): {multiple_r}")
如果得到的值接近0.93,则表明尽管可能存在非线性关系,但预测值与实际值高度相关。
3. 计算残差与平均绝对误差
残差是模型评估的关键概念,它表示实际值与预测值之间的差异。
公式
残差 = 实际值 - 预测值
- 如果实际价格为1000美元,模型预测为1100美元,则残差为
1000 - 1100 = -100美元(负值表示模型高估)。 - 如果实际价格为1000美元,模型预测为900美元,则残差为
1000 - 900 = +100美元(正值表示模型低估)。




可以将残差理解为模型需要调整其预测以使其正确的量。
代码示例:计算残差与MAE
# 计算残差
residuals = y_actual - y_pred
# 计算平均绝对误差
import numpy as np
mae = np.mean(np.abs(residuals))
print(f"平均绝对误差为: {mae} 美元")
平均绝对误差是所有残差绝对值的平均值。它的单位与原始数据相同(本例中为美元),因此非常易于解释。例如,MAE为992美元意味着模型的预测平均偏离实际价格约992美元。这个误差是否可接受,取决于具体的业务场景和需求。
总结
本节课中我们一起学习了多元线性回归模型的评估方法。我们首先通过绘制预测值与实际值的散点图并进行比较来直观评估模型。然后,我们计算了多重R来量化预测的准确性。最后,我们深入计算了残差和平均绝对误差,以理解模型预测误差的大小和分布。

评估模型的残差、绘制残差图并计算误差指标,能为你提供更多关于模型是否足够有用的洞察。在接下来的课程中,我们将学习如何与大型语言模型协作,以进一步改进模型。
080:使用LLM迭代模型 🚀
在本节课中,我们将学习如何利用大型语言模型(LLM)作为思考伙伴,来迭代和改进线性回归模型。我们将通过一个预测钻石价格的多元线性回归模型案例,演示如何向LLM提供上下文、获取改进建议、实施代码修改并评估结果。
概述
开发线性回归模型时,你可以随时向LLM寻求输入,以迭代和改进模型。本节将使用ChatGPT-4作为示例,展示如何通过提供数据集和模型摘要等上下文信息,获取具体的模型优化建议,并实施这些建议来提升模型性能。
向LLM提供上下文并获取建议
上一节我们介绍了线性回归模型的基础。本节中,我们来看看如何向LLM描述问题以获取改进建议。
首先,需要向模型清晰说明你正在解决的问题。就像与同事协作一样,提供足够的背景信息。

以下是提供给LLM的提示示例:
“我创建了一个多元线性回归模型,使用克拉重量和颜色来预测钻石价格。数据集是钻石数据。我使用
pd.get_dummies对颜色进行了编码。这是回归摘要表的截图。请提供三个改进模型的简单建议,并解释每个建议背后的理由。”
请注意,此提示意图是同时向模型提供数据集和摘要表的截图。因此,你需要先截图摘要表,并上传数据集文件。

模型给出了三个建议:
- 包含交互项:建议添加克拉重量与颜色的交互项,因为价格与克拉的关系可能取决于钻石颜色。
- 检查多重共线性:建议检查预测变量之间是否存在高度相关性。
- 考虑变换或非线性关系:指出克拉与价格的关系可能不是严格的线性关系,可以尝试添加多项式项(如克拉的平方)或对数变换来捕捉潜在的非线性。
最后一个建议尤其值得关注,因为从残差图和预测值与实际值的关系图中,你已经观察到似乎存在某种非线性关系。因此,可以尝试为克拉变量添加一个多项式项,例如克拉的平方。

根据LLM建议修改模型代码
在获得了初步建议后,下一步是根据建议修改模型。这里我们聚焦于实施“添加克拉平方项”的建议。


你可以向LLM提出后续提示,请求具体的代码修改帮助:
“以下是我的模型代码。请帮我修改它,在模型中包含
carat_squared(克拉的平方),而不仅仅是carat。同时,请提供用于创建X和Y以及拟合模型的代码。”

LLM推荐的修改相对直接:在数据框中新建一个carat_squared列,然后照常运行回归。你可以复制提供的代码并尝试实现。


观察新的回归摘要表,R平方值从之前的0.864略微提升到0.867,改善幅度有限。你可能因此产生疑问:克拉和克拉平方项似乎都基于同一个变量,它们是否会解释重叠的信息?
你可以直接向LLM提问:“在X数据框中同时包含carat和carat_squared是否可以?”
LLM的回答是肯定的:同时包含原始变量及其平方项是完全可接受的,且通常是必要的。这允许模型同时解释克拉与价格之间的线性和非线性关系。
分析改进效果并寻求进一步解释
由于模型改进效果不显著,我们需要深入分析原因,并寻求LLM的进一步指导。
你可以继续追问:“这种方法没有显著改善我的模型,你能帮忙解释一下原因吗?因为R平方只提高了零点几个百分点。”

LLM基本同意你的观察,即平方项只捕捉了价格方差中很小的一部分额外信息。它随后给出了一些可能的原因:
以下是LLM分析的可能原因:
- 非线性关系可能很微弱或有限,因此
carat_squared项可能不是捕捉该行为的最佳方式。 - 克拉本身已经是一个强预测因子,其变形可能无法提供额外价值。
- 模型可能通过纳入其他尚未包含的预测变量(如切工、净度等)获得更大收益。


最后,LLM给出了一些进一步分析的建议,包括检查残差、进行更多特征工程,或探索线性回归之外的非线性模型。
为了进一步调查,你可以将之前模型的预测值与实际值关系图截图分享给LLM,并请求解读。

基于这张图,LLM可能会建议对数据进行变换。从图中看,预测值先是迅速增加,然后趋于平缓,与实际值的分布有所不同。
LLM返回了几种建议的变换方案:
以下是LLM建议的数据变换方法:
- 对因变量(价格)进行对数变换:
log(price)。 - 对自变量(克拉)进行对数变换:
log(carat)。 - 其他建议,包括尝试更高阶的多项式项。
LLM解释了下一步操作:首先对价格和/或克拉应用对数变换,并愿意帮助你实现这些变换。
对数函数 y = log(x) 的图像在x值较小时y增长迅速,在x值较大时y增长趋于平缓。这与预测价格的分布有相似之处。因此,LLM建议同时添加价格和克拉的对数项。

实施对数变换并评估结果


现在,让我们请求LLM提供实施对数变换的具体代码。

提示:“修改这段代码,使其包含log(price)和log(carat),但不包含carat_squared。”

修改看起来相对简单。核心是用np.log()函数分别处理价格和克拉列,而不是创建carat_squared列。
虽然对数变换在理解上可能有挑战,但我们可以先继续实施,看其是否有效。以下是修改后的代码关键部分:

import numpy as np
# 假设 df 是包含‘price’和‘carat’列的数据框
df[‘log_price‘] = np.log(df[‘price‘])
df[‘log_carat‘] = np.log(df[‘carat‘])
# 然后使用这些新列作为特征和目标变量进行回归

这次变换产生了显著影响。R平方值达到了0.945,相比之前提升了近10个百分点,这是一个巨大的改进。
快速绘制预测值与实际值的关系图,可以看到两者之间的关系变得更加线性。但请注意,这里的预测值和实际值都是针对log(price)的,即数值6、7、8、9代表的是价格的对数值,而非原始线性价格。
此时,模型引入了新的变换,增加了复杂性,可能会影响模型的可解释性。虽然指标显示模型在改进,但由于复杂度增加,我们需要更谨慎。
总结
本节课中,我们一起学习了如何将LLM作为思考伙伴,贯穿线性回归模型开发的迭代过程。

我们从向LLM提供清晰的上下文开始,获取了改进模型的初步建议。随后,我们根据建议实施了代码修改(如添加多项式项、进行对数变换),并持续与LLM互动,分析改进效果、寻求原因解释和进一步优化方向。
关键收获是:LLM能够提供有价值的思路和具体的代码帮助,但最终对模型变换的理解、结果的评估以及是否采用这些复杂方法,仍需结合领域知识、与同事讨论或进一步研究来做出明智决策。
现在你已经体验了从变量选择到评估的端到端建模流程,下一节课我们将回顾这些步骤如何整合在一起,形成完整的数据分析工作流。
081:线性回归全流程 📊
在本节课中,我们将系统性地回顾构建多元线性回归模型的完整流程。我们将从模型构建的两个主要步骤——训练与预测——出发,梳理从数据准备、模型建立、评估到最终应用的每一个环节。
概述
线性回归分析包含两个核心阶段:训练(构建模型)与预测(使用模型进行预测)。此外,模型评估也是不可或缺的一步。本节将带您纵览线性回归的端到端工作流程。
模型训练流程
上一节我们介绍了线性回归的基本概念,本节中我们来看看构建一个模型的具体步骤。
以下是训练线性回归模型的典型步骤:

- 选择因变量:首先,确定您希望预测的目标特征,即因变量(Y)。
- 探索特征与因变量的关系:通过散点图和相关系数,检查数据集中其他特征与因变量之间的关系。识别出与因变量强相关的特征,作为备选的自变量(X)。
- 划分数据集:将数据分为训练集和测试集。通常,预留一小部分数据(例如10%或20%)作为测试集,用于后续的模型评估。其余数据用于训练模型。
- 建立初始简单线性回归模型:从一个自变量开始建模,通常选择与因变量相关性最强的那个。使用
statsmodels库运行回归分析并评估其拟合度。 - 进入迭代建模过程:此时,您已经建立了第一个模型,接下来将进入一个迭代优化流程。

模型评估与迭代
在建立了初始模型后,我们需要评估其表现,并据此进行优化。
以下是评估模型并指导下一步行动的关键方法:
- 评估模型拟合优度:使用 R平方(R-squared)来衡量模型的预测能力。通常,R平方值越高越好。其公式可表示为模型解释的方差占总方差的比例。
- 检查系数显著性:检查各自变量系数的 P值,以判断每个特征对预测的贡献是否显著。如果显著,则可以进一步解释该特征的影响。
- 使用其他评估指标:可以绘制预测值与实际值的对比图,并计算多重R(预测值与实际值之间的相关系数)。此外,计算残差(实际值与预测值之差),并进而计算平均绝对误差等指标。这些指标有助于指导后续优化或向利益相关方汇报。
- 优化模型:为了获得更高的R平方和更低的平均绝对误差,可以向模型中添加更多特征,构建多元线性回归模型。应选择一组能够提供额外预测力的、多样化的自变量,同时需注意可能存在的多重共线性问题(即变量间的解释能力重叠)。
模型预测与应用
当您对模型的R平方和解释能力感到满意后,就可以用它来预测新数据了。
您已经学习了如何使用 statsmodels 来预测单个值或一系列值。预测的基本形式是利用回归方程:
Y_pred = β0 + β1*X1 + β2*X2 + ... + βn*Xn


总结与展望
本节课中,我们一起系统回顾了线性回归从数据准备、模型训练、评估优化到最终预测的全流程。线性回归是一种功能强大的技术。
您可以通过接下来的阅读材料,了解更多关于线性变换和交互特征的知识,这些高级技巧能让您对数据中更复杂的关系进行建模。
接下来,您将完成本模块的计分作业和计分实验。在计分实验中,您将运用本模块学到的推断方法来预测车辆的碳排放量。
完成后,请跟随我进入本课程的最后一个模块:时间序列分析。
082:时间序列与预测简介 📊
在本节课中,我们将要学习时间序列数据分析的基础知识。时间序列数据与横截面数据不同,它需要独特的技术和方法。我们将使用Python中的pandas、matplotlib、Seaborn和statsmodels等工具,但分析思路将截然不同。通过本模块的学习,你将掌握分析和可视化时间序列数据的关键技术,并能够对未来进行预测。
模块5:时间序列与预测简介 📈
上一节我们介绍了本课程的整体结构,本节中我们来看看模块5的具体内容。时间序列数据在许多领域都有广泛应用,例如股票市场和气象数据。掌握时间序列分析技术,能够帮助我们理解数据中的趋势和季节性变化。
时间序列数据的独特性
与横截面数据相比,时间序列数据具有时间维度,这使得分析方法有所不同。尽管我们仍然会使用熟悉的工具,如pandas、matplotlib、Seaborn和statsmodels,但处理数据的思路将发生显著变化。
以下是本模块的三个核心课程安排:
-
第一课:Python中的日期时间类型与折线图
你将学习如何在Python中处理datetime类型,组织时间序列数据,并使用格式良好的单线图和多线图进行数据可视化。 -
第二课:时间序列的描述性统计
本节重点介绍时间序列分析的描述性统计方法。你将学习编写移动平均和百分比变化等强大技术,探索数据分段,并掌握数据重塑和重采样技术。 -
第三课:使用线性回归进行时间序列预测
在最后一课中,你将应用线性回归进行时间序列预测。学习如何对数据中的趋势和季节性进行建模,并评估你的时间序列模型的效果。
学习目标与实践数据
通过本模块的学习,你将能够自信地处理、可视化和预测时间序列数据。我们将使用真实的股票市场和气象数据作为实践案例,帮助你深入理解趋势和季节性,并尝试预测时间序列的未来走势。


总结
本节课中我们一起学习了Python数据分析第三课的模块5——时间序列与预测的简介。我们了解了时间序列数据的独特性,预览了本模块将涵盖的三个核心课程:日期时间处理与可视化、描述性统计分析以及线性回归预测。掌握这些技术后,你将具备分析和预测时间序列数据的能力。
接下来,请跟随我进入第一课,开始探索日期时间类型和折线图。我们课堂上见。
083:Python数据分析(第3课)|Python for Data Analytics
课程编号:P83 - 日期时间处理 📅

在本节课中,我们将要学习如何在Python和pandas中处理日期和时间数据。日期数据在数据分析中非常常见,例如分析股票价格趋势、用户行为日志等。我们将学习如何将文本格式的日期转换为专门的datetime类型,并利用其属性进行高效分析。
日期的重要性与数据类型

我们生活中总有重要的日期。例如,2016年11月2日,我挚爱的家乡棒球队芝加哥小熊队赢得了世界大赛冠军,那次胜利终结了长达108年的冠军荒。日期对我们而言是特殊的,在代码中,它们也需要一种特殊的数据类型。
你已经接触过许多数据类型,例如数字和字符串在Python中的表示方式,以及pandas如何通过Series和DataFrame在行和列中存储数据。在Python和pandas中,日期拥有其专属的数据类型:datetime类型。
数据分析场景:股票价格趋势
假设你正在为一家财务规划机构工作,被要求分析一段时间内的股票价格趋势。你正在研究新冠疫情前后科技股和零售股的趋势。该机构希望根据你的分析,为客户建议哪些股票最能抵御此类灾难性事件。
你正在处理一个新的数据集,其特征包括:date(日期)、ticker(公司股票代码)、开盘价、最高价、最低价、收盘价、调整后收盘价、交易量以及股票所属板块。你尤其关注调整后收盘价,它是经过特定财务情况调整后的当日收盘价。
CSV文件中的日期以“年月日”格式存储,这是行业标准。这种格式允许日期按历史顺序排序。你还会注意到数据中并非包含所有日期,周末和美国银行假日未被包含。

数据导入与初步观察
首先,在一个新的notebook中导入必要的模块,然后将数据从stock_prices.csv读入变量df。你的notebook文件stock_price_analysis和stock_prices.csv文件需存放在同一目录下。
记住,在Coursera环境中你无需进行文件管理,但像这样导入数据的前提是你的文件存储在一起。
查看前五行数据。数据包含date、ticker(股票名称)、开盘价等特征。每一行代表某只股票在特定一天的观测记录。数据似乎已按某种方式排序,因为这五行数据都是AAPL(苹果公司)。使用pd.unique()查看数据中所有股票代码(即公司)的列表。



你得到了苹果、亚马逊、谷歌、网飞和特斯拉,以及一些你可能不太熟悉的公司,例如埃克森美孚的股票代码。股票代码是按字母顺序排序的,这解释了为什么使用df.head()时只看到了苹果股票。
使用df.dtypes检查数据框的数据类型。看起来date列是object类型。你之前学过,object本质上意味着文本。所以目前你的日期是以文本形式存储的,这并不理想。
如果你通过选择列然后选择该列的第一个值来选取第一个日期,你会得到一个字符串。因为它不是一个特殊的日期类型,你无法直接获取年份等信息,只会得到一个错误。
将字符串转换为日期时间
你可以使用pd.to_datetime()函数将datetime列从字符串转换为datetime类型。在你想转换为datetime的值上调用此函数。
你可以在数据框的第一个日期(即2014年1月2日)上操作,也可以选择整个列,在一次操作中将所有日期更改为datetime。
但有一个问题:如果直接运行该代码,你会得到一个新的Series,但这个命令实际上并没有修改你原始的数据框。df[‘date’][0]的类型仍然是字符串。你需要将这个结果保存回date列,用新的datetime覆盖旧的字符串。

现在,如果你再次查看df.dtypes,你的date列是datetime64类型。很好,这里的ns代表纳秒。你只存储日期,不存储时间,但这种日期类型可以精确到纳秒级存储时间。
日期时间操作与属性访问
现在,因为这些值是datetime类型,你可以对它们进行很酷的日期相关操作。例如,你可以查找星期几,在本例中是3。那么,这是星期几呢?你可以询问你的LLM:“如果df[‘date’][0].weekday()的输出是3,那么是星期几?”
它会告诉你,星期一对应0,星期日对应6。所以,如果代码返回3,则对应星期四。
你也可以使用属性直接访问日期的不同部分。例如,.year只获取年份,.quarter给你季度(一年中的第一季度是1),.day获取日,等等。
还有一点需要注意:当你尝试在像整个date列这样的Series上访问.day属性时,会发生什么?你会得到一个错误:“Series object has no attribute day”。这很奇怪,因为你知道日期是datetime类型。

你可以询问你的LLM:“如果我遇到这种类型的错误,如何修复?date列中的值是datetime类型。”然后粘贴错误信息。它会告诉你,你试图直接在Series上访问.day属性,这行不通。相反,你需要使用.dt访问器来访问日期时间属性。所以看起来你需要在访问.day属性之前添加这个.dt。

尝试一下代码,看起来它起作用了。你没有得到错误,并且天数符合你的预期。你看到第二天、第三天、第六天、第七天、第八天,一直到月底的第30天。
核心概念总结
快速回顾一下,你可以使用pd.to_datetime()将字符串或字符串系列转换为特殊的datetime格式。然后,你可以使用像.weekday()这样的方法和像.month、.day、.year甚至.quarter这样的属性来获取每个日期的信息。

如果你试图访问整个Series(如数据框中的列)的属性,你需要在中间使用.dt访问器,就像你在代码行df[‘date’].dt.day中所做的那样。
一旦你将日期转换为正确的datetime类型,你就可以将它们用作数据框的索引,以替换默认的整数索引。

课程总结
本节课中,我们一起学习了日期时间处理的基础知识。我们了解了为什么日期需要特殊的数据类型,并通过一个股票价格分析的实例,实践了如何将文本格式的日期转换为pandas的datetime类型。我们学习了使用pd.to_datetime()进行转换,以及如何使用.dt访问器和相关属性(如.year、.month、.day)来提取日期信息。掌握这些技能是进行时间序列分析的重要第一步。
084:日期时间索引应用 📅

在本节课中,我们将学习如何利用日期数据的自然顺序来组织数据,具体来说,是将数据框的索引设置为日期时间列,从而创建时间序列数据。我们将通过实际操作,掌握设置索引、基于日期选择数据以及进行时间切片的方法。
上一节我们介绍了如何创建和操作日期时间数据,本节中我们来看看如何将这些日期时间数据设置为数据框的索引,以充分利用其内在的时间顺序。
具体而言,你可能希望将数据框的索引设置为你刚刚创建的日期时间列。快速回顾一下,你已经导入了所有必要的模块,并将股票危机数据读取到了一个名为 df 的数据框中。
你的首要任务是分析苹果公司股票随时间变化的趋势,以了解该股票在疫情期间受到的影响。目前,你的数据使用的是数值索引,但为了创建真正的时间序列,你需要将索引设置为日期。
以下是具体步骤:


首先,从数据框中筛选出仅包含苹果公司股票价格的数据。
apple_stocks = df[df[‘ticker’] == ‘AAPL’]
使用 value_counts 方法确认筛选结果正确。
apple_stocks[‘ticker’].value_counts()
很好,数据全部是苹果公司的,并且包含了2726天的股票数据。
现在,将 date 列设置为索引。
apple_stocks.set_index(‘date’, inplace=True)
set_index 方法以列名作为参数,这里我们选择 date 列。之前学过,默认情况下 set_index 会创建一个新的数据框。如果你想改变这一默认行为,可以使用命名参数 inplace=True。这个参数允许 set_index 直接修改原始数据框,而不是先创建一个修改后的副本。
现在查看 apple_stocks 的头部,新的索引就是这些日期时间,并且 date 列已从数据框的列中移除。这非常有用,因为现在你可以基于这些日期来选择特定的数据或对数据框进行切片。
例如,如果你想获取2020年2月3日(疫情开始显著影响市场前的第一个星期一)的数据作为基准,可以这样做:
apple_stocks.loc[‘2020-02-03’]
你可以使用 datetime 对象,但使用字符串更简短。如果可行,不必害怕“偷懒”。记住,.loc 允许你基于自定义索引选择行。这个命令会给出该日期的所有信息:当然是苹果股票,调整后的收盘价略低于77美元。
你现在也可以使用这些日期来切片数据。例如,如果你想选择一个月的数据来观察疫情发展期间的影响,可以从之前的数据开始,但现在使用切片操作符 :。
feb_2020_data = apple_stocks.loc[‘2020-02-01’:‘2020-02-28’]
2020年是闰年,所以没有2月29日。查看结果,这是一个数据框。请注意,这个切片包含了最后一个值(2月28日)。

现在,你可以检查苹果股票价格在2020年2月整个月内的表现。你可以使用 seaborn 的 lineplot,然后选择 adjusted_close 列来查看趋势图。哇,二月下旬有一个相当大的跌幅。另外,你可能还想调整X轴刻度的旋转角度,这样图表看起来会更清晰。我们将在下一个视频中进一步完善这个图表。
为了总结刚刚学到的工具,你看到了 set_index 方法可以用来将日期时间设置为索引,从而创建时间序列。set_index 以列名作为参数。默认情况下,这个方法会创建一个全新的数据框,而不是修改旧的。inplace=True 这个命名参数覆盖了默认行为,意味着 set_index 方法将直接修改数据框,而不是先创建副本。许多 pandas 方法都有可选的 inplace 命名参数,你可以随时向你的LLM查询你正在使用的命令是否有此选项。
你还使用了 .loc 来基于日期时间索引选择行。你可以用单个日期选择单行,也可以使用冒号 : 对数据框进行切片,以选择两个日期之间的范围。使用 .loc 进行切片时,会包含你选择的第一个和最后一个索引。
现在你正在使用日期时间作为索引,这意味着你正在处理一个真正的时间序列。请跟随我进入下一个视频,学习如何在Python中可视化时间序列数据,我们下个视频见。

本节课中我们一起学习了如何将日期时间列设置为数据框的索引,从而创建时间序列。我们掌握了使用 set_index 方法(配合 inplace=True 参数)直接修改数据框,以及使用 .loc 通过日期字符串或日期范围来选择和切片数据的技巧。这些是进行时间序列分析的基础步骤。
085:Python数据分析(第3课)|折线图绘制
在本节课中,我们将学习如何使用Python绘制折线图,以可视化时间序列数据。我们将从基础图表开始,逐步调整其外观,并学习如何在同一图表中绘制多个数据序列。

概述

在之前的模块中,你已经学习了如何进行大量的横截面分析。那么,对于时间序列数据,你的选择是什么?你可以从可视化开始。
数据准备与基础绘图
首先,我们回顾一下基本步骤:导入必要的模块,并将数据集读取到变量DF中。
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# 假设DF是已读取的包含股票数据的DataFrame
接着,我们创建一个子数据集来专注于苹果公司的股票数据。我们将索引设置为日期时间格式,以创建时间序列。最后,我们绘制调整后收盘价的折线图。
# 创建苹果股票的子数据集
apple_df = DF[DF[‘symbol‘] == ‘AAPL‘].copy()
# 将日期列设置为索引
apple_df.set_index(‘date‘, inplace=True)
# 确保索引是datetime类型
apple_df.index = pd.to_datetime(apple_df.index)
# 绘制2020年2月的调整后收盘价折线图
feb_2020_data = apple_df[‘2020-02‘]
sns.lineplot(data=feb_2020_data)
plt.title(‘Adjusted Close Price for Apple Stocks in February 2020‘)
plt.show()


调整图表外观

现在我们已经有了一个基础的折线图,接下来可以调整它的外观。添加Y轴标签和标题,并使用更大的字体以提高可读性。
sns.lineplot(data=feb_2020_data)
plt.ylabel(‘Adjusted Close Price ($)‘)
plt.title(‘Apple Stock Price: February 2020‘, fontsize=14)
plt.show()
X轴上的值显然是日期,因此可以暂时不添加X轴标题。我们将在下一个视频中学习如何进一步格式化坐标轴。
我们也可以调整线条的外观,使用sns.lineplot的参数,如线条样式、颜色、线宽等。由于我们想重点关注新冠疫情消息爆发的二月,可以使用红色和虚线样式。
sns.lineplot(data=feb_2020_data, color=‘red‘, linestyle=‘--‘, linewidth=2)
plt.ylabel(‘Adjusted Close Price ($)‘)
plt.title(‘Apple Stock Price: February 2020‘, fontsize=14)
plt.show()
在同一图表中绘制多个序列

创建了美观的图表后,你可能希望在同一图表上绘制多个序列。目前我们只关注2020年2月,但通过加入一月和三月的序列,可以为分析提供更多背景信息。
以下是添加这些线条到同一图表的步骤。首先,选择一月份的数据。

# 选择2020年1月的数据(包含边界日期)
jan_2020_data = apple_df[‘2020-01-01‘:‘2020-01-31‘]
然后,复制之前图表的代码,将标题改为“January through February 2020”,并添加另一个sns.lineplot调用来绘制一月的数据。
# 绘制二月数据
sns.lineplot(data=feb_2020_data, color=‘red‘, linestyle=‘--‘, linewidth=2, label=‘February‘)
# 绘制一月数据
sns.lineplot(data=jan_2020_data, color=‘black‘, linewidth=2, label=‘January‘)
plt.ylabel(‘Adjusted Close Price ($)‘)
plt.title(‘Apple Stock Price: January through February 2020‘, fontsize=14)
plt.legend()
plt.show()

这个图表有什么问题?它的行为符合预期,因为你调用的是序列,X轴是日期,而这些日期并不匹配。但如果我们能更直接地比较每个月的行为,岂不是更好?这意味着X轴需要有相同的值。
调整后收盘价是Y值。那么X值应该设置为什么?我们可以使用索引中的“日”。记住,索引是一个时间序列,所以我们可以取过滤后的数据框的索引的“日”部分。

# 获取每个数据点的月份中的日期
x_vals_feb = feb_2020_data.index.day
x_vals_jan = jan_2020_data.index.day
现在,更新两个序列的X值。也许一月的线可以用实心黑线表示。

sns.lineplot(x=x_vals_feb, y=feb_2020_data.values, color=‘red‘, linestyle=‘--‘, linewidth=2, label=‘February‘)
sns.lineplot(x=x_vals_jan, y=jan_2020_data.values, color=‘black‘, linewidth=2, label=‘January‘)


plt.xlabel(‘Day of Month‘)
plt.ylabel(‘Adjusted Close Price ($)‘)
plt.title(‘Apple Stock Price: January and February 2020‘, fontsize=14)
plt.legend()
plt.show()
接下来,我们可以添加三月份的序列。选择数据,并使用深灰色线条。
# 选择2020年3月的数据
mar_2020_data = apple_df[‘2020-03‘]
x_vals_mar = mar_2020_data.index.day
sns.lineplot(x=x_vals_feb, y=feb_2020_data.values, color=‘red‘, linestyle=‘--‘, linewidth=2, label=‘February‘)
sns.lineplot(x=x_vals_jan, y=jan_2020_data.values, color=‘black‘, linewidth=2, label=‘January‘)
sns.lineplot(x=x_vals_mar, y=mar_2020_data.values, color=‘darkgray‘, linewidth=2, label=‘March‘)
plt.xlabel(‘Day of Month‘)
plt.ylabel(‘Adjusted Close Price ($)‘)
plt.title(‘Apple Stock Price: Q1 2020‘, fontsize=14)
plt.legend()
plt.show()
再次强调,我们想在分析中突出二月,所以其他线条可以用更柔和的颜色绘制。最后,更新图表标题。从图中可以看出,二月出现了急剧下跌,但与2020年三月相比,这算不了什么。也许我们应该调整图表颜色来反映这一点。

最后,仅凭观察此图,你的客户将无法分辨每条线代表哪个月份。如果你尝试使用plt.legend(),可能会得到一个微小的空框,这不是我们需要的。为什么不问问你的大语言模型如何为每个月在图例中添加标签呢?

以下是添加自定义图例标签的代码:

# 使用label参数为每条线指定标签
sns.lineplot(x=x_vals_feb, y=feb_2020_data.values, color=‘red‘, linestyle=‘--‘, linewidth=2, label=‘Feb‘)
sns.lineplot(x=x_vals_jan, y=jan_2020_data.values, color=‘black‘, linewidth=2, label=‘Jan‘)
sns.lineplot(x=x_vals_mar, y=mar_2020_data.values, color=‘darkgray‘, linewidth=2, label=‘Mar‘)

plt.xlabel(‘Day of Month‘)
plt.ylabel(‘Adjusted Close Price ($)‘)
plt.title(‘Apple Stock Price: Q1 2020‘, fontsize=14)
plt.legend(title=‘Month‘)
plt.show()
图例位置良好,你可能唯一想做的就是去掉图例标题中的年份,因为年份已经在主标题中了。
plt.legend(title=‘Month‘)
总结
本节课中,我们一起学习了以下内容:
- 你了解到可以使用
sns.lineplot函数创建时间序列数据的折线图。 - 你可以直接绘制一个数据序列,也可以使用
x和y命名参数来更精确地控制数据。 - 你看到如果索引是日期时间类型,可以使用
df.index.day等方法,在X轴上绘制不同的值(如月份中的日期)。 - 你还学习了可以在调用
plt.legend()之前,使用label命名参数为每条线添加标签。

折线图是可视化时间序列数据的首选工具。然而,格式化日期可能有点棘手。请跟随我进入下一个视频,看看如何处理这个任务。
086:日期轴标签格式化

在本节课中,我们将学习如何在时间序列可视化中正确且美观地格式化日期轴。日期是时间序列图表中的关键元素,Matplotlib库提供了强大的工具来帮助我们精确控制日期在坐标轴上的显示方式。
概述:为何需要格式化日期轴?
在时间序列可视化中,日期是核心维度。一个清晰易读的日期轴能帮助我们更好地理解数据随时间变化的趋势和模式。Matplotlib内置的日期处理工具使我们能够轻松调整刻度位置和标签格式,而无需从零开始编写复杂代码。

数据准备与初步绘图
上一节我们介绍了数据导入和基本设置,本节中我们来看看如何为亚马逊股票价格数据创建时间序列图。
首先,我们需要导入必要的模块并准备好数据集。假设数据已加载到变量 df 中。由于我们处理的是新的股票数据集,需要重新设置日期时间索引。

核心概念:我们的数据框包含多个股票在多个日期的信息,因此需要先筛选出亚马逊的股票数据,然后将索引设置为日期时间。
以下是数据准备的步骤:
- 使用筛选条件选择出亚马逊的股票数据。
- 使用
set_index方法,将“日期”列设置为索引,并指定inplace=True或覆盖原变量以保存更改。
# 筛选亚马逊股票数据
amazon_stocks = df[df[‘stock_symbol’] == ‘AMZN’]
# 将日期列设置为索引
amazon_stocks.set_index(‘date’, inplace=True)
现在,我们得到了一个亚马逊股票的时间序列数据框。
创建基础时间序列图
首先,我们为调整后的收盘价创建一个简单的折线图。
import seaborn as sns
import matplotlib.pyplot as plt
sns.lineplot(data=amazon_stocks, x=amazon_stocks.index, y=‘adjusted_close’)
plt.show()
从图中可以看出,价格总体呈上升趋势,但在2022年初有一次急剧下跌。这张图没有提供下跌原因的任何额外信息,但可以看出在2020年,股价从新冠疫情引发的市场冲击中迅速反弹。
美化图表:添加标题、网格和品牌色
为了让图表更专业,我们为其添加标题、网格线,并将线条颜色改为亚马逊的品牌亮橙色(十六进制代码 #FF9900)。
sns.lineplot(data=amazon_stocks, x=amazon_stocks.index, y=‘adjusted_close’, color=‘#FF9900’)
plt.title(‘Amazon Stock Price Over Time’)
plt.grid(True)
plt.show()
格式化日期轴:调整刻度位置
在使用折线图时,我们经常需要调整X轴(日期轴)的显示方式,使图表更易于阅读。例如,我们可能希望X轴上显示每一年,而不是隔年显示。
日期是一种复杂的数据类型,Matplotlib提供了有用的日期工具,我们可以直接导入使用。通常我们使用别名 mdates。
核心概念:为了在创建图表后修改坐标轴,我们需要先将绘图对象保存到一个变量(如 ax)中。
以下是调整X轴以显示每年刻度的步骤:
- 导入
mdates模块。 - 将绘图保存到变量
ax。 - 使用
ax.xaxis.set_major_locator(mdates.YearLocator())设置主要刻度定位器为每年。
import matplotlib.dates as mdates
ax = plt.gca() # 获取当前坐标轴
ax.xaxis.set_major_locator(mdates.YearLocator())
plt.show()
运行代码后,X轴现在会显示每一年。同时,网格线也相应地为每一年进行了更新。这使得对比2020年初和2021年初的数据变得非常容易。
格式化日期轴:调整标签格式
接下来,我们可能希望只显示年份的后两位数字(如’14‘, ’15‘),使标签更紧凑易读。我们可以复制并修改之前的代码。
核心概念:使用 set_major_formatter 方法来控制主要刻度标签的格式,而不是它们的位置。
以下是调整年份显示格式的步骤:


- 使用
ax.xaxis.set_major_formatter(mdates.DateFormatter(‘%y’))。这里的%y是一个日期格式代码,表示两位数的年份。 - 此时可以移除X轴的标签,因为日期本身已经很清晰。
ax.xaxis.set_major_formatter(mdates.DateFormatter(‘%y’))
plt.xlabel(‘’) # 移除X轴标签
plt.show()
运行后,可以看到 %y 给出了年份的后两位数字。最后,我们可以在格式字符串开头添加一个撇号,以符合某些书写习惯。

ax.xaxis.set_major_formatter(mdates.DateFormatter(“’%y”))
plt.show()
现在,我们得到了一个清晰的图表,X轴上每年都有刻度,并且年份以易读的两位数字加撇号的形式显示。
更多日期格式选项
总结一下,为了处理日期轴,我们导入了 matplotlib.dates。我们使用 set_major_locator 函数配合 mdates.YearLocator() 在X轴上标记每一年,并使用 set_major_formatter 来控制该轴上日期的显示格式。
你不需要记住所有命令,只需知道有这些工具可以微调你的图表格式即可。
之前我们使用了带有百分号的日期格式化字符串。%y 是显示不带世纪的年份的日期代码,而开头的单引号用于直接添加撇号字符。
你还有其他选项,例如:
%Y:显示带世纪的年份(如 2020)。%m:将月份显示为零填充的数字(01-12)。%d:显示日期。%b:显示月份的缩写名称(如 Jan)。
你也可以将这些代码组合在一起。例如,使用 %b %y 在X轴上同时显示月份和年份。
在可视化中格式化日期时,你拥有很多可用的选项,并且可以随时向AI助手寻求帮助。

总结
本节课中,我们一起学习了如何为时间序列图格式化日期轴。我们掌握了使用 mdates.YearLocator() 设置年度刻度,以及使用 mdates.DateFormatter() 和格式代码(如 %y)来自定义日期标签显示的方法。这些技能能显著提升时间序列图表的可读性和专业性。
接下来,你将完成本课的练习作业和实践实验室。在实践实验室中,你将探索澳大利亚政府发布的航班延误数据集。我们下节课“时间序列的描述性统计”再见。
087:移动平均线
在本节课中,我们将学习时间序列分析中的一个核心工具——移动平均线。我们将了解它的作用,并通过分析亚马逊股票的交易量数据,掌握如何在Python中计算和可视化移动平均线,从而更好地识别数据中的趋势。


时间序列的核心分析工具之一是移动平均线。移动平均线有助于平滑嘈杂的数据,帮助你更好地理解趋势、季节性和周期性。
评估股票对市场冲击(如疫情)抵抗力的另一种方法是观察其交易量。交易量是指在特定日期交易的股票数量。

我们将分析新冠疫情前后亚马逊股票的交易量,以了解该特定股票的投资者的行为。




上一节我们介绍了移动平均线的概念,本节中我们来看看如何获取并初步观察数据。
首先,需要导入模块,将数据集读入变量 df,然后选择亚马逊股票数据,并将索引设置为日期时间以创建时间序列。最后,绘制调整后收盘价的折线图。
要获取交易量数据而非调整后收盘价,需要做哪些更改?
只需将此处选择的列更改为 volume,然后更新Y轴标题即可。


现在,我们可以立即看出这张图比调整后收盘价的图要“嘈杂”得多。整体趋势似乎是向下的,但不太明显。数据中也有很多峰值。


为了平滑这个时间序列中的噪声,我们可以计算交易量的移动平均线。记住,移动平均线可以平滑数据,帮助你减少这些峰值的影响。
以下是计算移动平均线的步骤:
- 选择目标列:从你感兴趣的数据列开始,例如亚马逊股票的交易量
amazon_stocks['volume']。 - 应用滚动方法:使用
.rolling()方法。rolling代表滚动平均,是移动平均的另一种说法。.rolling()会创建具有特定窗口长度的数据子集。使用命名参数window=某个数字。例如,如果你的每个观测值代表一天,你可能想计算14天(即两周)的平均值。 - 应用聚合函数:仅使用
.rolling()不会得到任何平均值,它只是将数据行分组(类似于groupby)。你需要对数据应用某种聚合函数,如mean或sum,才能看到结果。
例如,你可以使用 .mean() 计算简单移动平均。与pandas中的许多方法一样,此命令不会直接将新列添加到数据集中,它只会生成一个新的Series。因此,你需要将其保存到一个变量中,例如 amazon_volume_14_day。
现在,如果你查看前14个值,会看到什么?前13个单元格是空的,因为还没有14天的数据来计算平均值。在此之后,你会得到第一个移动平均值。
上一节我们计算了移动平均线,本节中我们将其可视化,并与原始数据进行比较。

你可以将此列绘制在折线图中。沿用之前的绘图代码,因为你可以将此线覆盖在原始数据上绘制。
使用 sns.lineplot(),这次使用 amazon_volume_14_day 变量,并选择 color='black' 以示区分。你可能还想通过设置 alpha=0.5 和 linestyle=':'(创建虚线)来弱化原始时间序列的显示。


可以看到,这条折线图平滑得多,峰值更少,但数据中仍有一些噪声。同时注意到数据点太多,很难分辨出移动平均线。
你可以使用 xlim 来显示更多数据,或者创建一个更大的图形。让我们创建一个更大的图形,可以使用 figsize=(12, 6) 来创建一个更宽的图表。

最后,可以像上一课那样,为每个序列添加图例。在 sns.lineplot() 中使用 label 命名参数,为原始数据和“14日滚动平均”设置标签。
仔细观察原始数据,你会发现每年通常有大约5到6个峰值,这可能包括季度财报或其他定期的季度事件。


为了进一步平滑这些峰值并提炼趋势,你可以创建一个90天(约三个月)的移动平均线。
创建一个变量 amazon_volume_90_day,并借用之前的相同绘图代码,这次设置 window=90。将其添加到你的图表中,使用 color='blue',以便比较。
可以看到,与14日移动平均线相比,90日移动平均线平滑得多。你还可以看到,90日平均线在某种程度上滞后于14日平均线,因为它需要更长的时间来反映原始时间序列的行为。
现在,你可以移除14日平均线,并将90日平均线设为黑色以突出显示。因为它是对数据更易解释的表示,你真正开始提炼出时间序列数据的趋势,而没有被所有分散注意力的噪声干扰。
这类长期的移动平均线常用于股价和交易量分析,因为日与日之间的波动通常很大。

可以看到,亚马逊股票的交易量在2020年初显著增加,然后在接下来的一年半里逐渐减少。你可以将这些见解带回给你的客户,以便他们更好地理解亚马逊股票的交易行为。
本节课中我们一起学习了如何创建移动平均线。
首先,选择要为其创建移动平均线的列,例如交易量列。然后,使用 .rolling() 方法并指定 window 参数的数字(我们看到了适用于平滑每日观测值的14日和90日平均线)。最后,需要应用一个聚合函数。对于移动平均线,你会想使用 .mean(),但也可以使用不同的聚合函数,如中位数 .median()。然后,你可以使用 sns.lineplot() 将新生成的序列绘制在折线图中。

移动平均线是平滑嘈杂时间序列数据的绝佳工具。与电子表格相比,在Python中实现起来相当快捷。
在接下来的视频中,我们将学习如何计算百分比变化,以识别数据中的急剧峰值和下跌。
088:时间序列分析之百分比变化 📊
在本节课中,我们将要学习如何分析时间序列数据中的百分比变化。这是一种强大的工具,可以帮助我们识别当前时期与前一时期相比的变化情况。我们将以亚马逊股票价格数据为例,找出那些价格跌幅超过5%的日期,从而分析历史上对亚马逊股价冲击最大的市场事件。


上一节我们介绍了如何导入数据并创建时间序列。本节中我们来看看如何计算和分析百分比变化。
计算百分比变化
首先,我们关注的是调整后的收盘价。百分比变化可以告诉我们股票价格相较于前一天是上涨还是下跌。
以下是计算步骤:


- 选择包含调整后收盘价的列。
- 使用
.pct_change()方法计算百分比变化。 - 将结果保存到一个变量中。
对应的代码如下:
amazon_close_pct_change = df['Adj Close'].pct_change()
计算后,我们预期只有第一个单元格是空的,因为第一天没有前一天的股价可供比较。从第二天开始,我们会看到一系列代表每日价格变化比例的数字。
需要注意的是,.pct_change() 方法计算的是比例变化,而非百分比。例如,结果 -0.0038 表示下跌了 0.38%。为了得到真正的百分比,需要将结果乘以100。但在后续分析中,我们通常保留原始的比例形式,因为这样更方便计算。
可视化百分比变化

百分比变化本身也是一个时间序列,因此我们可以像绘制其他数据一样将其可视化。


以下是绘制百分比变化折线图的步骤:
- 使用
sns.lineplot()绘制折线图。 - 为图表添加合适的标签。
- 可以自定义线条颜色以增强可读性。

通过观察图表,我们发现百分比变化围绕零值上下波动,其中正负方向的尖峰代表了较大的单日价格变动。
为了更好地识别特定阈值(如跌幅超过5%)的日期,我们可以在图表中添加水平参考线。

例如,添加一条位于 y = -0.05 的水平线,可以清晰标出价格下跌5%的临界点。我们还可以添加一条位于 y = 0 的实线,用以区分价格上涨和下跌的区域。
筛选与分析特定变化
可视化之后,我们可以进一步筛选数据,获取那些跌幅超过5%的具体日期列表。
筛选一个序列的方法与筛选数据框中的列非常相似。以下是具体操作:
- 使用条件语句筛选出百分比变化小于
-0.05的数据点。 - 使用
.count()方法统计满足条件的日期数量。 - 计算这些“大跌”日期占总交易日的比例。
对应的代码如下:
dips = amazon_close_pct_change[amazon_close_pct_change < -0.05]
dip_count = dips.count()
dip_proportion = dip_count / len(amazon_stocks_df)
通过分析,我们发现在过去大约十年间,亚马逊股价单日跌幅超过5%的情况只发生了44次,占总交易日的比例仅为1.6%,属于相对罕见的事件。我们可以通过 dips.index 获取这些具体日期的列表,以便深入研究每次大跌背后的市场原因。例如,数据表明其中三次重大下跌恰好发生在2020年3月美国疫情初期。

总结
本节课中我们一起学习了时间序列分析中的百分比变化。

我们使用 .pct_change() 方法创建了一个表示逐期百分比变化的新序列。我们不仅学会了如何绘制百分比变化随时间推移的走势图,还掌握了如何根据变化的正负或特定幅度(例如,调整后收盘价较前一日下跌超过5%的日子)来筛选数据。
一旦掌握了移动平均线和百分比变化的应用,你可能会有兴趣对数据进行分段,以更好地理解各个子集。请跟随我到下一个视频,看看具体如何操作。
089:时间序列分群分析 📊
在本节课中,我们将学习如何对时间序列数据进行分群分析。我们将探索如何根据日期索引的属性(如月份)对数据进行分组,并通过可视化来识别数据中的季节性模式。
概述
时间序列数据包含丰富的信息,通过分群分析,我们可以从不同维度(如月份、季度)观察数据的模式和趋势。本节我们将以Netflix股票数据为例,学习如何按月份分组,分析交易量的季节性变化,并理解这些变化与公司季度财报发布的关系。
上一节我们介绍了如何导入和查看数据,本节中我们来看看如何对时间序列进行分组和聚合分析。



数据准备与初步观察
首先,我们从数据集中选取Netflix的股票数据,并将日期列设置为索引。
# 选取Netflix股票数据并设置日期索引
netflix_stocks = df[df['Ticker'] == 'NFLX']
netflix_stocks.set_index('Date', inplace=True)
接着,我们绘制交易量的折线图以观察整体趋势。



# 绘制交易量折线图
netflix_stocks['Volume'].plot()

从图中可以观察到,数据中大约每年出现四次显著的交易量峰值,这是一个值得关注的稳定模式。
按月份分组分析
日期索引允许我们访问其各个组成部分,例如年份、月份或季度。
# 从日期索引中提取月份
netflix_stocks.index.month
为了方便后续分析,我们可以将月份信息添加为数据框的一个新列。
# 将月份添加为新列
netflix_stocks['month'] = netflix_stocks.index.month
以下是按月份对数据进行分组并计算平均交易量的步骤:

- 使用
groupby方法按月份分组。 - 选择
Volume列。 - 应用
.mean()函数计算每个月的平均交易量。
# 按月份分组并计算平均交易量
monthly_volume = netflix_stocks.groupby('month')['Volume'].mean()
为了更直观地展示结果,我们可以使用条形图进行可视化。
# 绘制平均月交易量条形图
monthly_volume.plot(kind='bar')
分析显示,Netflix发布季度财报的月份(一月、四月、七月、十月)的交易量明显高于其他月份,峰值大约高出30%至50%。



使用箱线图深入分析分布
为了更细致地了解每个月份交易量的分布情况(包括中位数、四分位距和异常值),我们可以使用箱线图。
以下是使用Seaborn库绘制箱线图的步骤:

- 指定
x轴为月份,y轴为交易量。 - 通过调色板参数为不同月份应用颜色,以突出显示财报发布月。



import seaborn as sns
# 定义颜色列表,财报发布月为红色,其他月为浅灰色
colors = ['red', 'lightgray', 'lightgray'] * 4
# 绘制箱线图
sns.boxplot(x=netflix_stocks['month'], y=netflix_stocks['Volume'], palette=colors)
plt.ylim(0, 4e7) # 调整y轴范围以聚焦主要数据分布
通过箱线图可以确认,财报发布月的交易量中位数和变异性(四分位距更宽)都高于其他月份,这与平均值的观察结果一致。
总结
本节课中我们一起学习了时间序列分群分析的核心方法:


- 提取日期属性:可以通过
DataFrame.index.month、.year、.quarter等方式访问日期索引的不同部分。 - 创建分组列:可以将日期属性(如季度)保存为新列,便于后续分组操作。
- 分组与聚合:使用
.groupby()方法按特定特征(如月份)分组,然后结合.mean()、.describe()等函数进行聚合分析。 - 可视化模式:通过条形图和箱线图等可视化工具,可以清晰地揭示数据中的季节性模式和分布差异。
对时间序列进行分群是一种强大的策略,它能帮助我们从单一时间线中提取出多个有意义的子序列进行分析。在接下来的课程中,我们将学习如何重塑时间序列数据以进行更复杂的绘图。
090:Python数据分析 第3课 - 多折线图重构 📊
在本节课中,我们将要学习如何通过重塑数据格式,来高效地绘制包含多个数据序列的折线图。核心在于将数据转换为适合绘图的结构,而非专注于复杂的绘图方法本身。

概述
绘制数据时,主要的困难往往在于将数据整理成适合绘图的格式,而不是指定具体的绘图方法。本节我们将探讨一些常见的数据重塑操作。
上一节我们介绍了基本的折线图绘制,本节中我们来看看如何将多个数据序列整合到一张图中。
数据重塑的必要性
在之前的课程中,我们通过两次独立的 sns.lineplot 调用来绘制多个股票序列。这种方法在只处理少数几只股票时可行,但手动筛选股票并分别绘制会变得繁琐且容易出错。
然而,要创建更复杂的图表,有时需要重塑数据。具体来说,需要将数据排列成:每个要绘制在Y轴上的值,都与一个唯一的X值(如日期时间)相关联。
虽然有时可以通过多次调用 sns.lineplot 来创建复杂图表,但这会产生大量重复工作,例如需要多次手动筛选数据。
一旦掌握了数据重塑,绘图效率将大大提高。
实例:比较苹果与亚马逊的股价

例如,假设你想比较苹果和亚马逊的调整后收盘价,以了解每只股票对新冠疫情的反应。你希望用多条线绘制每只股票的调整后收盘价。
但是,如果查看原始数据框,数据尚未设置妥当。仅查看 datetime、ticker 和 adjusted_close 列,你会发现每个唯一的日期对应两行数据,即 datetime 是重复的,而苹果和亚马逊的 adjusted_close 出现在不同的行中。
为了正确绘图,需要以某种方式重塑数据,使得每个唯一的日期时间仅对应一行,而该行中的列分别是苹果和亚马逊的调整后收盘价。
以下是实现此目标的关键步骤:
- 导入模块并读取数据:首先,导入必要的模块并将数据读入变量
df。 - 筛选多个股票代码:从原始数据框中筛选出我们感兴趣的股票(例如苹果和亚马逊)。
- 数据透视:将筛选后的数据重塑为每个日期一行、每只股票一列的格式。
步骤详解
1. 筛选多个股票代码
回顾一下,之前我们使用类似 df[df.ticker == 'AAPL'] 的代码来筛选单一股票代码。要筛选多个股票代码,一个有用的方法是 isin() 方法。
以下是具体操作:
# 创建感兴趣的股票代码列表
tickers = ['AAPL', 'AMZN']
# 从数据框中选择 ticker 列值在列表中的行
selected_stocks = df[df['ticker'].isin(tickers)]


操作成功后,可以检查 selected_stocks 中唯一的股票代码来确认:
selected_stocks['ticker'].unique()
预期结果应仅为 ['AAPL', 'AMZN']。
2. 数据透视
筛选出这两只股票后,还需要一步来设置数据:即数据透视。
我们理想的数据格式是:列包括 datetime、AAPL、AMZN。每一行对应一个日期,例如 2018年8月2日,苹果的价格是100,亚马逊的价格是85。
这种格式非常适合在同一图表上绘制两条线,因为每个X值(日期)对应两个Y值(两只股票的价格)。
为了以这种方式重塑数据,需要使用 pivot 方法。pivot 与数据透视表(pivot table)略有不同:数据透视表会汇总数据,而 pivot 方法则是在行、列和值之间重新组织数据,而不进行汇总。不过,两种方法的参数名称是相同的。
使用方法如下:
# 使用 pivot 方法重塑数据
# index: 设置为日期列(作为X轴)
# columns: 设置为股票代码列(每个代码将成为一列)
# values: 设置为要绘制的值,即调整后收盘价
pivoted_stocks = selected_stocks.pivot(index='datetime', columns='ticker', values='adjusted_close')
# 查看重塑后的数据前几行
pivoted_stocks.head()
现在,数据就变成了我们想要的格式。对于每个日期,都可以绘制苹果和亚马逊的调整后收盘价。
3. 绘制多折线图
数据重塑完成后,绘图就变得非常简单:
import seaborn as sns
import matplotlib.pyplot as plt
sns.lineplot(data=pivoted_stocks)
plt.show()
你将得到一张漂亮的双股票价格折线图。注意,Seaborn 自动为每条线赋予了独特的颜色和样式以帮助区分。
从图中可以看到,两只股票在前几年都在上涨,但后来开始分化。苹果股价在2022年的跌幅没有亚马逊那么大。
此后,你可以继续为图表添加坐标轴标签、注释等元素进行完善。
扩展至更多股票
数据重塑的优势在于其可扩展性。例如,如果你想绘制五只股票而不是两只,只需将股票代码添加到列表中并重新运行代码即可。

以下是添加微软、网飞和耐克后的效果示例(代码逻辑相同,仅 tickers 列表变化):
tickers = ['AAPL', 'AMZN', 'MSFT', 'NFLX', 'NKE']
selected_stocks = df[df['ticker'].isin(tickers)]
pivoted_stocks = selected_stocks.pivot(index='datetime', columns='ticker', values='adjusted_close')
sns.lineplot(data=pivoted_stocks)
plt.show()
总结

本节课中我们一起学习了如何为绘制多序列折线图而重塑数据:
- 我们使用
isin()方法来筛选数据框中某一列的多个值。该方法检查特定值是否在你指定的列表中。 - 我们使用
pivot方法,以datetime为索引、ticker为列、adjusted_close为值来重塑数据,目标是实现每个X值对应多个Y值。 - 一旦数据重塑完成,就可以使用
sns.lineplot()轻松获得美观的图表,并可继续使用 Matplotlib 进行精细调整。
优秀的数据重塑工作使得在单一图表中绘制多个序列成为可能。除了重塑数据,经常还需要对数据进行重采样(降低或增加其频率)。请跟随我到下一个视频继续学习。
091:Python数据分析 第3课 - 重采样技术 📊
在本节课中,我们将要学习时间序列数据中的重采样技术。重采样是调整数据频率的强大工具,无论是将高频数据聚合为低频,还是通过插值增加数据频率。掌握这项技术能帮助你更好地分析和理解时间序列数据。
概述
有时,你会发现时间序列数据的采样频率过高,例如每分钟的股票价格。有时,数据又不够频繁。通过重采样,你可以改变时间序列的频率。之前我们学习了如何从日期中提取信息(如季度或月份)并存入新列,这种方法适用于数据分割,但并未改变数据的频率。要获得更聚合或更细化的时间段,你需要对数据进行重采样。


什么是重采样? 🔄
重采样主要分为两种:降采样和升采样。
降采样涉及将多个时间段聚合在一起,通常通过计算均值来实现。例如,你可以将每日股票价格数据降采样为每周数据,方法是计算每周的平均股价。其核心思想是:
低频数据 = 聚合函数(高频数据)
升采样则涉及增加数据的频率,通过在现有时间段之间创建新的时间段来实现。这种技术不太常用,但你需要了解这个术语。


实践:降采样操作
上一节我们介绍了重采样的基本概念,本节中我们来看看如何在Pandas中执行降采样。
假设你已经导入模块并将数据集读入变量 df。现在,你想创建一个每周的耐克股票时间序列,而不是每日的,以平滑时间序列中的一些噪声。
你会使用 resample() 方法,并指定频率参数,例如 'W' 代表每周。但请注意,resample() 本身只是一个中间步骤。在执行某种聚合操作(如计算均值)之前,你无法看到命令的结果。
以下是初始尝试的代码:
nike_weekly = df.resample('W').mean()
运行这行代码会产生一个错误。错误信息底部显示:TypeError: ag function failed. How mean De type object。这表明 mean() 聚合函数被应用到了对象类型(通常是字符串)的数据上,而 mean() 只能用于数值数据。
错误排查与解决
为了解决这个错误,我们需要确保只对数值列进行平均计算。以下是两种解决方法:


方法一:选择数值列
使用 select_dtypes() 方法仅选择数值类型的列,然后再进行重采样和平均计算。
numeric_df = df.select_dtypes(include='number')
nike_weekly = numeric_df.resample('W').mean()


方法二:使用其他聚合函数
如果你需要在分析中包含分类数据,可以使用像 first() 这样的聚合函数,它只取每个时间段内的第一个值,这样就能处理非数值列。

nike_weekly = df.resample('W').first()

其他重采样频率选项
Pandas的重采样功能非常灵活,提供了多种频率选项。以下是部分常用选项:
'D': 每日'W': 每周(默认周日结束)'W-MON': 每周一'ME': 每月末
你可以根据具体需求探索不同的频率参数。
总结
本节课中我们一起学习了时间序列的重采样技术。你学会了如何使用 resample() 方法对数据进行降采样,其中 'W' 参数表示按周重采样,此外还有 'D'(每日)、'ME'(月末)和 'W-MON'(每周一)等多种选项。你了解到使用 mean() 进行重采样只适用于数值列,可以通过 select_dtypes() 选择数值列来计算均值,或者在分析中需要分类数据时,使用 first() 等其他聚合函数。现在,你已经能够根据需要调整数据的频率了。

接下来,你将完成练习作业和实践实验室。在实践实验室中,将继续使用澳大利亚航班延误数据。完成后,请跟随我进入本模块的下一课,也是最后一课:使用线性回归进行时间序列预测。
092:Python数据分析(第3课)| 趋势预测 📈
概述

在本节课中,我们将学习如何使用线性回归模型来预测时间序列数据的趋势。我们将从一个简单的单变量模型开始,了解其基本原理、应用步骤以及在实际数据分析中需要注意的问题。
线性回归与时间序列
上一节我们介绍了线性回归在截面数据中的应用。本节中我们来看看线性回归如何应用于时间序列数据。
线性回归不仅适用于截面数据,也是分析时间序列数据的有用技术。你可以使用一个简单的线性回归模型(即只有一个自变量的模型)来预测时间序列数据的趋势。
在之前使用钻石数据的课程中,自变量(克拉数)和因变量(价格)的取值范围是明确的。在使用克拉数预测价格的简单线性回归案例中,克拉数大致在0.2到5之间。通常,新钻石的克拉数预期会落在这个范围内。
当使用线性回归预测时间序列时,分析的重点通常是预测未来时期。例如,如果你拥有2020年1月1日至2024年1月1日的数据,你通常感兴趣的是预测2024年或更晚的时间。你的模型假设趋势和季节性在未来会持续,但预测得越远,不确定性往往越大。条件会发生变化,微小的不确定性或误差可能在多年间累积。

影响你时间序列建模的一个复杂因素是,线性回归通常假设观测值是独立的。例如,假设一颗钻石的价格不影响另一颗的价格是合理的。然而,某一天的温度与它前后几天的温度高度相关。如果周二是炎热的,周三很可能也是炎热的。不必过于担心这个问题的技术细节。这对你分析的影响是,模型会高估P值和系数的置信度。在解释结果时需要谨慎。因此,用于时间序列预测的线性回归通常是一种初步方法。一些更高级的方法可以弥补时间序列数据中这种固有的非独立性。
当你在代码中进行时间序列预测时,需要考虑两个额外的步骤。首先,为了帮助减少独立性问题,你可以对数据进行重采样,例如,从每小时观测值重采样为每周观测值。重采样减少了模型必须处理的重复噪音量。然后,为每个时期分配一个索引编号,以便你能够对趋势建模。这是因为你的线性回归模型只处理数字,而不是日期。
假设你正在与一家农业咨询公司合作,预测德国的天气模式。你的公司希望预测德国博伊滕堡的温度,以便为当地农民规划种植季节并更好地预测收获利润。你被要求开发一个模型,根据过去的数据预测未来的温度。
为了简化,让你专注于时间序列数据,这里不会展示训练测试集划分,但通常最好使用一个。
数据准备与探索
以下是开始建模前的准备工作。
首先,导入所需的库,加载数据并查看。

import pandas as pd
import statsmodels.api as sm

记住,这行代码能运行是因为天气数据CSV文件与你的笔记本在同一文件夹中。这些数据是德国博伊滕堡的每小时天气数据。注意这个包含日期和小时的日期列。除了你试图预测的温度(摄氏度)外,你还有许多其他可用的特征,包括气压、露点等,你还有一个季节列。
为了使这些数据成为时间序列,将索引设置为日期时间列。确保进行原地操作。
df = pd.read_csv('weather_data.csv')
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace=True)
最后,在创建线性回归模型之前,还有两个准备步骤。
首先,你需要将数据重采样为每周数据点。重采样可以减少数据中的随机噪音。使用.resample('W')方法来实现。由于你想保留季节列供以后使用,可以使用.first()聚合函数,而不是.mean()。


df_weekly = df.resample('W').first()

其次,你需要为每一周分配一个数字,因为日期时间是其自身的类型,不是数字,但你的线性回归模型需要一个普通数字。添加一个新列idx(索引),使用range函数,该函数从0到数据框的长度(即行数)生成数字。
df_weekly['idx'] = range(len(df_weekly))
然后再次查看df_weekly。现在你有了这个索引列,它从0、1、2、3开始,一直向上递增。

建立简单线性回归模型
现在你可以开始设置回归预测变量了。从一个简单的线性回归开始,即一个自变量。使用一个只包含一个项目['idx']的列表。因此,你将尝试根据周数来预测温度。之后,你可以添加到这个列表中,并保持其他代码不变。
这个线性回归模型将尝试预测数据的趋势。记住,线性回归只是估计最佳拟合线。如果温度总体在上升,那么较晚的周将具有较高的温度。如果温度在下降,那么较晚的周或较高的索引将具有较低的温度。
代码与之前处理截面数据时相同:X等于使用sm.add_constant选择预测变量列(目前只有一列),Y将是温度(摄氏度)。
X = sm.add_constant(df_weekly[['idx']])
y = df_weekly['temperature_c']
model = sm.OLS(y, X).fit()
你现在已经设置了回归,现在可以运行回归了。
解释模型结果
记住,你正在解释趋势。首先,R平方值非常低,只有0.007。换句话说,周数只能解释约0.7%的温度变异性。这并不多。

检查索引系数的P值。它是0.22,远高于任何合理的alpha阈值,如0.05或0.01。那么这个P值告诉你什么?周数对整体温度没有显著影响。
目前,你只有从2020年到2023年的三年数据,模型没有足够的证据来预测未来的温度。如果你看一下周数与温度的散点图,你会发现这种关系是非常非线性的。你试图在这里拟合一条直线,但直线不能很好地模拟这些数据。这是一个潜在的线索,表明你需要更多的数据或一个更复杂的模型。
因此,在你的模型中添加季节性将真正帮助你更准确地预测温度。顺便说一下,当你使用最少的变量工作时,在初始模型中发现无效应是常见的。你应该继续改进你的模型。
总结

本节课中,我们一起学习了如何使用简单线性回归来模拟时间序列的趋势。我们了解了将线性回归应用于时间序列数据时的基本步骤、潜在问题(如观测值非独立性)以及如何通过重采样和创建索引来准备数据。我们还运行了一个简单的模型并解释了其结果,认识到仅用趋势项可能不足以捕捉数据的全部模式。
在下一节视频中,我们将学习如何向你的时间序列预测模型中添加季节性因素,以构建更强大、更准确的预测模型。
093:Python数据分析 第3课 - 季节性预测 🌡️📈
概述
在本节课中,我们将要学习如何为时间序列数据建立季节性预测模型。我们将从简单的线性回归模型出发,扩展到包含季节性因素的多重线性回归模型,并使用德国博尔滕堡的温度数据作为案例进行实践。
从趋势到季节性
上一节我们介绍了如何使用简单线性回归为时间序列的趋势建立预测模型。本节中我们来看看如何扩展模型,以加入季节性因素。
回顾一下,我们正在为一家咨询公司预测德国博尔滕堡的温度。之前我们已经完成了数据导入、将时间序列设置为索引、将数据降采样为周度数据,并添加了一个索引列。我们观察到数据中存在明显的季节性:夏季温度飙升,冬季温度下降。仅用一条直线拟合这些数据效果不佳。
因此,下一步是建模季节性。



识别与准备季节性数据
观察数据中的“季节”列,它包含四个类别。
以下是识别季节类别的代码:
df['season'].unique()
为了在回归模型中使用这个分类变量,需要将其转换为数值形式。我们将“季节”添加到预测变量列表中。
对于分类数据,需要使用 pd.get_dummies 来获取数值,而不是字符串。
以下是创建虚拟变量的代码:
X = pd.get_dummies(df_predictors, columns=['season'], drop_first=True, dtype=int)
参数说明:
df_predictors:你的预测变量DataFrame。columns=['season']:需要创建虚拟变量的列。drop_first=True:省略一个季节类别作为基准。dtype=int:生成整数而非布尔值。
你不需要记住所有参数,可以随时查阅之前的笔记或咨询大语言模型。
最后,像之前一样使用 sm.add_constant,以便模型可以估计截距。
查看 X.head(),格式符合预期:包含常数项、代表周数的索引列以及三个季节的虚拟变量。
被省略的季节是秋季。这有助于解释,因为秋季既非夏季极端也非冬季极端,有助于从基准温度进行解释。
运行回归并解读结果
回归设置完毕,没有错误,可以运行。
现在得到了一些有趣的结果。模型的 R 平方值为 0.575,这意味着目前可以解释约58%的温度变化。这是模型的整体解释力。
之前仅包含趋势的模型 R 平方为 0.007。因此,同时建模趋势和季节性的回归模型比仅建模趋势的模型能预测更多的温度变化。这很合理,因为从图中可以看出,温度随季节的变化远大于随周数的变化。


你可能还想理解系数。

索引(趋势)的系数仍然不显著。模型仍然没有足够的数据来识别显著的趋势。
回顾一下,被省略的基准季节是秋季。因此,其他季节的系数都是与秋季类别相比较的结果。
春季、夏季和冬季这三个季节的系数都非常显著。
- 与秋季相比,夏季月份平均使温度增加 8 度。
- 与秋季相比,冬季月份平均使温度降低 6.5 度。
- 同时,春季月份比秋季低 2.2 度。
进行未来预测
既然已经训练了一个具有显著系数的模型,就可以开始进行预测了。
如果你想预测未来的一周,可以查看数据的末尾。最高的索引是 209,因此现在可以预测第 210 周(数据中的下一周,即2024年第二周)的温度。
查看 X.head(),你需要一个类似这样的值列表来预测第210周:一个包含常数项1、周数210、春季为0、夏季为0、冬季为1的列表。
使用 results.predict() 对第210周进行预测,得到温度约为 3.3 摄氏度(约38华氏度)。
那么,如果这一周是夏季,预测温度会是多少?
夏季应该比冬季增加好几度。也许你会预期高出约14.5度(8 + 6.5)。这正是你看到的:如果这周是夏季,预测温度约为 17.8 摄氏度。
虽然我们知道这一周不是夏季,但这个假设展示了模型的季节性成分在预测温度时发挥了巨大作用,尤其是与趋势成分相比。
总结
本节课中我们一起学习了如何为时间序列模型添加季节性。
我们了解到,即使趋势不显著,仍然可以使用多重线性回归来建模数据中的季节性。我们还学习了如何使用比模型训练数据更高的索引值来预测新的一周。由于预测的本质是处理原始数据之外的值,因此需要仔细解释结果。


请记住,季节性不仅仅是“季节”,它指的是数据中任何有规律的重复模式。天气数据只是一个说明性的例子,你可以理解为什么这些模式被称为“季节性”,因为天气模式与季节密切相关。
在时间序列中建模季节性是一项出色的工作。你已经开发了一个基于历史数据预测天气模式的复杂模型。
请继续学习下一个视频,以更好地理解线性回归误差指标如何应用于时间序列预测。
094:Python数据分析(第3课)|预测误差指标
在本节课中,我们将学习如何评估时间序列线性回归模型的性能。我们将使用与横截面数据相同的误差指标,并探讨在时间序列背景下如何解读这些指标。
🔍 回顾与准备
上一节我们介绍了如何构建时间序列回归模型。本节中,我们来看看如何评估该模型的预测准确性。
首先,我们正在为德国博伊登堡的气温进行预测。此前,我们已经完成了数据导入、降采样为周度数据,并构建了一个多元线性回归模型来预测气温。
与计算钻石价格残差的方法类似,我们也可以计算时间序列预测的残差。残差定义为实际值(此处为气温)减去预测值。
残差公式:
residuals = y_actual - y_predicted
残差揭示了模型预测值与真实值之间的差异。
📈 计算与可视化残差


以下是获取预测气温(y_pred)的步骤。实际气温为 y,残差则为实际气温减去预测气温。
与之前一样,我们可以查看预测值与实际值的散点图。图中显示出四个不同的簇,可能对应四个不同的季节。


中间温度对应春季和秋季,秋季温度略高。较高温度对应夏季,较低温度对应冬季。为图表添加颜色编码会更好,这可以借助你的LLM工具来完成。
理想情况下,我们希望看到预测值与实际值之间存在线性关系,即一种一一对应的相关性。正如之前所见,季节性(而非趋势)在此数据中承担了主要的预测工作。
🔎 分析残差
我们可以查看残差的头部数据,以了解模型各个预测的偏差程度。


# 示例:查看残差头部
print(residuals.head())
第一个预测看起来相当接近,偏差约为1.8度。在2020年的第一周,实际气温比预测气温高出不到2度。
如果你对数据集中的最大误差感到好奇,也可以查看最大值。


在本例中,存在一个偏差约14度的预测。它可能接近零,但数据显示有一周的气温预测偏差了约14度。
📊 计算平均绝对误差
使用与横截面数据完全相同的代码,我们可以计算模型的平均绝对误差。
平均绝对误差公式:
MAE = (1/n) * Σ|y_actual - y_predicted|
平均绝对误差的单位与数据单位相同,此处为摄氏度。计算结果显示,模型平均偏差约为3.6摄氏度。
对于“今天是否需要穿毛衣”这类问题,这个误差或许可以接受。但对于农业或科学应用,可能解释力不足。


🎯 总结与回顾
本节课中我们一起学习了如何评估时间序列回归模型。
以下是评估步骤总结:
- 首先,查看实际值与预测值的散点图,以识别线性关系并评估模型性能。
- 接着,计算残差。
- 最后,利用残差计算平均绝对误差。平均绝对误差告诉你模型预测平均偏差多少,无论误差是正还是负。
现在,你已经开发出一个具有一定解释力的模型。你可以将此模型带回给客户,作为讨论的起点,或者运用之前模块中的迭代过程来改进它。例如,通过添加更多特征作为预测变量,或在LLM中探索更多选项。
现在,你已经能够熟练地使用多元线性回归来预测时间序列数据并正确解读结果。
🚀 后续课程预告
本课即将结束,课程也接近尾声。接下来,你将完成本模块的评分作业和实验。
在评分实验中,你将分析珊瑚礁数据,以帮助海洋保护团队。
最后,你将完成本课程的顶点练习。你将扮演一名数据分析师,与一家新的金融科技初创公司合作。你的目标是创建一个预测模型来估算贷款利率。你将综合运用本课程中学到的所有知识,包括数据操作、描述性统计、可视化和推断统计,来完成一项全面、严谨的分析。
完成评分作业、实验以及顶点练习后,我将在最后一个视频中与你讨论作为数据分析师的后续步骤。继续努力,期待在完成这些任务后与你再见!
095:Python数据分析(第3课)|Python for Data Analytics
课程编号:P95:94_你的下一步计划
📚 概述
在本节课中,我们将总结你在数据分析课程中取得的成就,并展望接下来的学习方向。你已经掌握了Python编程和数据分析的核心技能,现在可以开始探索更高级的数据处理技术。
🎉 课程完成祝贺
祝贺你完成顶点项目和本课程。
你在编程和数据分析方面取得了惊人的进步。
你学习了Python函数、数据类型以及许多高级数据分析师常用的技术。
你分析了各种真实世界的数据,从公共图书馆收入和餐厅评分,到贷款利率、珊瑚礁指标和钻石价格。
你已经准备好进行大规模的自定义分析,并且还有很多可以学习的内容。
即使在这个领域工作多年,每天仍然有新的知识可以学习。
🔄 过渡到下一阶段
上一节我们总结了你在本课程中的成就,本节中我们来看看接下来的学习计划。
我希望你能加入本系列的下一个课程:使用SQL和Python进行数据处理。
到目前为止,在本专业课程中,你主要处理的是干净、整洁的数据。😊


但现实世界中的数据通常是混乱的。
📊 下一课程内容
你将学习如何收集、存储和处理数据,为分析做准备。
以下是下一课程的核心学习内容:
- 你将实现多种数据收集方法,包括网络爬虫和使用API。
- 你还将学习SQL语言,用于与数据库通信,编写查询以进行排序、筛选、聚合等操作。
- 你还将学习使用SQL和Python进行数据验证的高级技术。
🎯 课程目标
这门课程将教你从众多真实世界的数据源中收集数据,并将其转化为像你目前所处理的那些一样美观和干净的数据集。
✅ 总结
本节课中我们一起回顾了你在Python数据分析课程中的学习成果,并介绍了后续课程“使用SQL和Python进行数据处理”的核心内容。
再次祝贺你完成本课程,我们下一门课再见。😊


浙公网安备 33010602011771号