
在这行干久了经常被新入行的朋友问同一个问题想学 Python 做数据科学到底先学什么我的答案永远是固定的三件套——NumPy、Pandas、Matplotlib。这套数据科学工具链几乎覆盖了从数据读取、清洗、计算到可视化的全流程不管你是想分析一份 Excel 表格、爬虫拿到的一堆 JSON还是公司数据库导出的 CSV最终都会落到这三个库上。这篇文章不是官方文档的翻译而是按我自己的踩坑经历来写的哪些概念最容易卡住新手哪些安装坑我每年都要帮人解决一次哪些报错其实两句话就能处理掉。全文会从环境搭建开始带你依次跑通 NumPy 的数组运算、Pandas 的表格处理、Matplotlib 的图形输出最后用一个完整的小案例把这套工具链串起来。适合刚入门 Python、正准备接触数据处理的读者也适合那些装好了环境但不知道从哪下手的同学。1. 先搞清楚一件事这套工具链到底帮你省了什么1.1 为什么是这三件套而不是 Pandas 直接干到底很多人有个疑问既然 Pandas 能读 Excel、能做统计、能算均值排序为什么还要单独学 NumPy这里解释一下它们的分工。NumPy 是整个工具链的地基提供高性能的 ndarray 数组对象和向量化运算能力Pandas 在 NumPy 之上构建了带标签的表格结构也就是 Series 和 DataFrameMatplotlib 则负责把数据变成图形。打一个可能不太严谨但很直观的比方NumPy 像厨房里的基础食材和切配标准Pandas 是按菜谱配好的半成品托盘Matplotlib 是摆盘上桌的环节。没有 NumPy 的高效运算打底Pandas 处理几十万行数据时会明显变慢不学 Matplotlib你做出来的分析结论就只能写文字说服力直接减半。我的建议是从一开始就把这套工具链当成配合关系来理解而不是替代关系。数据处理的典型节奏是读取数据 → 用 Pandas 做预处理和切片 → 需要数值计算的地方切到 NumPy → 最后把结果交给 Matplotlib 画图。实际操作中你会频繁在三个库之间来回切换所以入门阶段就要有意识地建立这个协作思维。库核心对象主要职责类比角色NumPyndarray高性能数值计算、矩阵运算地基/食材PandasDataFrame / Series数据读取、清洗、聚合半成品托盘MatplotlibFigure / Axes数据可视化呈现摆盘上桌我见过大量新手拿到一份 CSV 之后第一反应是head()看一下然后试图写循环处理每一行。这在数据量小的时候没问题一旦跑真实业务数据慢到怀疑人生。真正的思路是先想清楚数据形态再决定用哪个库的方法一步到位解决问题。1.2 你的第一个环境体验装不上、装错位置、装错版本聊正题之前先说个特别现实的现状工具链本身不难难点从安装就开始出现了。我每年帮人排查环境问题花的功夫比教写代码还多。常见的症状就三种。第一种屏幕上明明显示安装成功import 的时候却报 ModuleNotFoundError。第二种在命令行里 import 正常换到 VSCode 或 PyCharm 里就报错。第三种版本太老或太新导致某个 API 不存在、某个参数对不上。这些问题九成是同一个根因机器上有多个 Python 环境pip 装到了一个环境解释器用的却是另一个环境。举个例子你电脑里可能同时存在官网下载的 Python 3.11、Microsoft Store 装的 Python 3.9还有某个 IDE 自带的基础解释器。它们在系统里是完全独立的各有各的 site-packages 目录。你在命令行用官网 Python 的 pip 安装 NumPy装进去的位置和 VSCode 选中的 3.9 版 Python 搜索模块的位置根本不是一回事。理解这一点环境问题就解决了一半。安装这件事不是敲命令这么简单你需要确认三件事当前用的 Python 解释器是哪个当前环境的 pip 是哪个包到底装到了哪里。下面我会用一整节讲清楚。2. 环境搭建从零到能跑第一个 Demo重点说清安装的坑2.1 先定位 Python 解释器和 pip别急着敲安装命令无论你用的是下载安装包的方式还是通过 Anaconda/Miniconda第一步永远是定位解释器路径。在命令行里执行# Windows 与 macOS/Linux 通用 python --version pip --version # 更进一步确认解释器路径 python -c import sys; print(sys.executable)这一步能看出机器上默认的 Python 是哪一个。如果你分不清自己用的是哪个后面所有 我明明装了为什么还报错 的问题都没法定位。对于纯新手我强烈建议直接装 Anaconda 或者 Miniconda然后用它的 base 环境。这不是说 conda 有多高级而是它自带一套解释器和包管理大幅降低环境混乱的概率。当然如果你已经用官网 Python 加 VSCode 能跑通那就别折腾换工具了能用才是王道。这里特别提一下 VSCode 用户最容易踩的坑VSCode 右下角状态栏会显示当前 Python 解释器点击它就可以切换。很多命令行能跑编辑器里跑不了的怪问题都是因为右下角选中的解释器和命令行里的不是同一个。打开命令面板输入Python: Select Interpreter手动选一次往往比你在终端里折腾半小时都有效。2.2 用 pip 安装三件套的正确姿势确认好解释器之后安装就很简单了。打开命令行输入pip install numpy pandas matplotlib如果下载速度太慢可以临时换用国内镜像源。这里给一个通用写法pip install numpy pandas matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple装完之后不要急着跑项目先做一个冒烟测试。在命令行里输入python -c import numpy, pandas, matplotlib; print(numpy:, numpy.__version__); print(pandas:, pandas.__version__); print(matplotlib:, matplotlib.__version__)这个命令会把三个库的版本号一次性打印出来。如果打印成功说明三件套已经进入同一个解释器。如果这步都失败不要再继续写代码先回头处理环境。提示pip install numpy和python -m pip install numpy在大部分情况下等价但在多环境并存的机器上python -m pip能确保 pip 和当前 python 命令绑定的是同一个环境安全性更高。如果pip本身报错或找不到我建议改用这个写法。2.3 离线安装、IDE 内安装和 Linux 服务器安装有些场景下机器不能联网或者网络策略很严格这时候要提前准备离线安装包。方法是在一台能联网的同平台机器上下载 wheel 文件然后拷过去用pip install 文件名安装。先执行 pip download# 在一台联网机器上下载并保留依赖 pip download numpy pandas matplotlib -d ./offline_packages然后把整个文件夹拷到目标机器再执行pip install --no-index --find-links./offline_packages numpy pandas matplotlib注意pip download只会下载指定包不会自动把依赖全部拉全。如果目标环境是全新的建议在联网机器上用pip freeze requirements.txt先导出依赖清单再把所有依赖的 wheel 一起下载下来。另一个常见场景是 PyCharm 里安装包——打开 File → Settings → Project → Python Interpreter右下角加号搜索包名安装即可。它的本质还是调用了这个解释器对应的 pip所以界面上显示安装成功也不代表万事大吉你依然要确认项目用的解释器是哪一个。Linux 服务器上安装时有两个容易踩的细节一是服务器可能同时存在系统自带的 Python 3 和用户自己编译的 Python建议用python3 -m pip install而不是直接pip install二是没有 root 权限时给 pip 加--user参数把包装到用户目录避免权限问题。装完之后再用第 2.2 节的冒烟测试验证一下这个习惯能帮你省掉后面一大半的 Debug 时间。3. NumPy 快速上手数组、向量化运算和那几件反直觉的事3.1 ndarray 与 dtype为什么数组里每个元素类型必须一致NumPy 的核心数据结构是 ndarray也就是 N 维数组。它比 Python 内置列表快得多的一个重要原因就是数组里所有元素的类型必须统一。内存分配是连续且紧凑的CPU 可以直接批量处理不需要像 Python 列表那样挨个查对象的类型信息。代价就是你往一个整数数组里塞浮点数或字符串要么被强转要么直接报错。这种类型敏感特性就是新手最容易反直觉的第一点。创建数组非常直观import numpy as np a np.array([1, 2, 3, 4]) # 一维数组 b np.zeros((3, 4)) # 3 行 4 列全零数组 c np.ones((2, 2)) # 2 行 2 列全一数组 d np.arange(0, 10, 2) # 从 0 到 10(不含)步长为 2 e np.linspace(0, 1, 5) # 0 到 1 之间均匀取 5 个数但要注意写np.array([1, 2, 3.5])时数组 dtype 会被自动推断为 float64因为整数 1 被提升成了 1.0。如果后面你想对前两个元素做整数逻辑运算就容易踩坑。所以建议在创建时就显式指定 dtypea np.array([1, 2, 3], dtypenp.float64)检查 dtype 最常用的方式是a.dtype。看到 dtype 是 int32 还是 float64基本就能判断很多莫名其妙的结果是因为精度丢失还是类型转换引起的。NumPy 提供了一整族 dtype比如 int32、int64、float32、float64还有处理字符串的U类型。刚开始不需要记全只要知道数组是有类型强约束的这一点就够用了。3.2 切片、布尔索引与广播机制NumPy 的切片语法和 Python 列表类似但它有一个让新手措手不及的特性切片返回的是视图不是副本。也就是说执行b a[1:3]之后你修改 b 的元素a 也会跟着变。这是因为 NumPy 为了性能默认不复制底层数据只有显式调用.copy()才会复制。解决这个问题的方法很简单需要独立数据时就写.copy()不需要时就老实使用视图以节省内存。我建议新手养成一个习惯凡是不确定后面会不会改动切片结果的场景都补一个.copy()安全第一。这个细节在写大型数据处理的脚本时特别重要因为视图的副作用往往不会在出错的第一时间暴露而是隔了很久才从某个诡异的数值里体现出来。布尔索引是 NumPy 的高效过滤手段data np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) print(data[data 5]) # 输出所有大于 5 的元素广播机制是 NumPy 最强大的特性之一。简单说当两个数组形状不完全一致时NumPy 会按规则自动扩展较小的数组去匹配较大的数组。比如arr 1会把 1 广播到每个元素上(3, 1)和(1, 4)相加会先扩展成(3, 4)。我见过不少人在需要按列归一化时很自然地写了data - data.mean(axis0)却得到了一堆看起来完全错误的结果。问题通常出在形状对齐上data.mean(axis0)是一维的(n,)减去它时 NumPy 沿着行广播结果就乱了。遇到这种情况先打印两个数组的 shape再用reshape或keepdimsTrue显式对齐维度。3.3 mgrid 的用法与常用聚合函数有人专门搜索numpy库mgrid方法说明这是很多人学习时卡住的地方之一。mgrid 的作用是生成一个用于网格计算的密集坐标数组。比如我们要生成一个 3x3 网格的 x 坐标和 y 坐标x, y np.mgrid[0:3, 0:3] # x 是纵向重复 3 行y 是横向重复 3 列 print(x) # [[0 1 2] # [0 1 2] # [0 1 2]] print(y) # [[0 0 0] # [1 1 1] # [2 2 2]]它在画二维图、做数值模拟时非常常见。比如你想对平面上每个点计算z f(x, y)先用 mgrid 生成坐标网格再对整个网格做向量化计算比嵌套两层 for 循环快得多代码也更简洁。很多人第一次看到 mgrid 的输出会愣住因为它是把坐标拆开而不是给你一组现成的坐标点。多打印几次输出理解维度方向就好。聚合函数方面最常用的是sum、mean、max、min、std。注意axis参数的语义axis0是沿着行方向压缩计算每一列的结果axis1是沿着列方向压缩计算每一行的结果。这个方向问题初学者几乎必错一次我也只能提醒你多打印结果验证。判断方法很简单结果数组的维度比原数组少一维你只要看输出形状是 (n,) 还是 (,n) 就能反推出方向。4. Pandas 快速上手从表格思维到数据处理思维4.1 Series 和 DataFrame两个核心对象的直觉理解Pandas 的两个核心对象经常被新同学混淆。简单理解Series 是一列带标签的数据DataFrame 是由多个 Series 组成的二维表格。大多数时候你直接操作的是 DataFrame但 DataFrame 里的每一列本质上是 Series。如果你在数据处理时写df.iterrows()去逐行循环处理大概率是没理解 Pandas 的向量化能力。大部分需求可以用整列操作完成速度和代码可读性都远好于循环。比如计算两列的比值直接写df[A] / df[B]就行不需要一行一行来。这个思维方式的转变是很多人从会写 Python到会用 Pandas的分水岭。创建 DataFrame 最常用的方式是从字典创建和从文件读取import pandas as pd # 从字典创建key 是列名value 是列数据 df pd.DataFrame({ 姓名: [张三, 李四, 王五], 年龄: [25, 30, 35], 城市: [北京, 上海, 广州] })创建完之后用df.shape看行列数用df.columns看列名。新手容易把字典的 key 顺序和 DataFrame 的列顺序搞混实际上 Pandas 会按传入顺序保留不需要担心字典在 Python 3.7 是有序的这个前提。4.2 读取 Excel/CSV 与数据类型转换的关键细节pd.read_excel()和pd.read_csv()是处理数据的起点。读 CSV 时我强烈建议先试encodingutf-8遇到乱码就换成encodinggbk这是国内导出数据的常见编码。读 Excel 时注意sheet_name参数不传默认读第一个 sheet也可以传多个 sheet 名返回一个字典。读取之后第一件事不是直接 print而是先用三个方法检查数据形态df.head() # 看前 5 行 df.info() # 看列名、非空值数量、dtype df.describe() # 看数值列的统计描述df.info()是我个人最常用的因为它的输出会直接告诉你每一列是什么 dtype、有没有缺失值这比肉眼翻表格高效太多。类型转换是 Pandas 踩坑重灾区。最常见的场景是年龄列看起来是数字实际上是字符串。比如读 Excel 时把某一列读成了 object一求均值直接报错。转换的标准写法是df[年龄] pd.to_numeric(df[年龄], errorscoerce) df[日期] pd.to_datetime(df[日期], errorscoerce)errorscoerce的作用是把无法转换的值变为 NaN而不是直接抛异常断开整个流程。这个参数非常重要能让你在数据质量差的时候先保留流程后面再统一处理缺失值。另一个高频需求是把字符串类型的浮点数列转换为真正的浮点列方法同样是pd.to_numeric。关于读写文件还有一个经常被忽略的导出细节df.to_excel(output.xlsx, indexFalse)时记得加indexFalse否则会把行索引写进 Excel 的第一列给自己制造多余数据。写 CSV 给 Excel 用时建议df.to_csv(output.csv, indexFalse, encodingutf-8-sig)utf-8-sig能避免 Excel 打开中文乱码。4.3 数据清洗三板斧缺失值、重复值、异常值数据清洗是 Pandas 使用频率最高的场景。我的经验是把它拆成三板斧。第一板斧是缺失值。先看缺失情况分布df.isnull().sum()然后决定策略删除df.dropna()还是填充df.fillna()。删除时注意参数subset可以指定只在某些列缺失时才删填充时常用df[列名].fillna(df[列名].mean())或者用前向填充ffill()。我的一般原则是关键业务字段缺失优先填充非关键字段缺失可以考虑删除时间序列数据优先前向填充因为用未来值去填过去值在逻辑上是说不通的。第二板斧是重复值。df.duplicated()可以判断哪些行重复df.drop_duplicates()删除重复行。注意默认是按整行判断如果想按某一列判断重复必须传subset[列名]。比如会员表里一个人可能出现多行你只想保留每人最近一条记录就要按会员 ID 去重。第三板斧是异常值。最简单快速的是通过分位数过滤q1 df[金额].quantile(0.25) q3 df[金额].quantile(0.75) iqr q3 - q1 df_filtered df[(df[金额] q1 - 1.5 * iqr) (df[金额] q3 1.5 * iqr)]这套 IQR 方法不是万能的但对入门阶段处理脏数据非常实用。清洗过后再用df.info()对比一下行数和非空值就能知道清洗有没有生效。很多时候数据清洗不是一次性做完的而是检查 → 清洗 → 再检查的循环你在第 2 次检查时可能又会发现新的问题。5. Matplotlib 快速上手画出第一张能看的数据图5.1 绘图基础流程与 Figure/Axes 的层级关系Matplotlib 的 API 经过多年演进很多老教程还在用plt.plot()直接画虽然也能出图但理解 Figure画布和 Axes坐标系的层级关系才能让后续的布局调整不那么痛苦。Figure 是整个图形窗口Axes 是图上的一个坐标系。一张 Figure 上可以有多个 Axes比如并排几张子图每个 Axes 有自己的 x 轴、y 轴和数据。最基础的绘图流程是import matplotlib.pyplot as plt x [1, 2, 3, 4, 5] y [3, 5, 7, 9, 11] fig, ax plt.subplots(figsize(6, 4)) ax.plot(x, y, markero, linestyle--, colorb, label示例数据) ax.set_xlabel(X 轴) ax.set_ylabel(Y 轴) ax.set_title(我的第一张 Matplotlib 图表) ax.legend() plt.show()这里的fig, ax plt.subplots()是显式创建 Figure 和 Axes 对象后续所有配置都通过ax完成。对比老式写法plt.xlabel()这个方式更清晰也方便在一张画布里创建多个子图时统一管理。如果你想画并排的两张子图核心逻辑是一样的fig, (ax1, ax2) plt.subplots(1, 2, figsize(10, 4)) ax1.plot(x, y) ax2.bar(x, y) plt.show()subplots(1, 2)返回(fig, axs)axs是一个包含两个 Axes 对象的数组展开赋值给(ax1, ax2)就行。后面你分别调用 ax1 和 ax2 的方法两张图就在同一张画布里各占一半。5.2 常见图表选型与中文显示问题该选什么图我的习惯是看趋势用折线图ax.plot看分布用直方图ax.hist或箱线图ax.boxplot看占比用饼图ax.pie比较各类别数值用柱状图ax.bar。新手最容易犯的错是用柱状图去表达时间序列趋势这会让读者很难看清连续变化换成折线图马上自然很多。几乎每个用 Matplotlib 的人都会碰到中文显示问题。默认字体里没有中文字体出来的图全是方框。解决方法要先指定支持中文的字体import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei, PingFang SC] plt.rcParams[axes.unicode_minus] False # 解决负号显示为方框的问题把这两行放在脚本开头大部分场景的中文显示问题都能解决。如果系统里确实没有这些字体就需要手动安装中文字体并重新构建字体缓存过程比较繁琐。我建议入门阶段直接采用这个配置如果不行再考虑装字体。另外直方图和箱线图很适合快速查看数据分布。比如我们要检查销售金额是否呈偏态分布import matplotlib.pyplot as plt import numpy as np data np.random.gamma(2, 2, 500) fig, (ax1, ax2) plt.subplots(1, 2, figsize(10, 4)) ax1.hist(data, bins30, edgecolorblack) ax1.set_title(直方图) ax2.boxplot(data) ax2.set_title(箱线图) plt.show()箱线图里的中位数线、四分位边界和离群点一眼就能看出数据分布的形状。配合前面第 4.3 节讲的 IQR 异常值过滤你会发现 Matplotlib 和 Pandas 的联动非常紧密。6. 高频报错的完整排查链路别再靠猜很多人在社区发求助帖时直接贴个报错截图连错误信息和环境都没说清楚。这里我按几个高频报错挨个拆解一遍排查过程目的是帮你建立一条排查思路而不是背答案。以后再遇到类似报错至少知道从哪里下手。6.1AttributeError: module pandas has no attribute core的真实原因这个报错看起来很吓人其实是典型的名字遮蔽或版本不一致问题。排查链路是这样的先确认代码里有没有一个文件叫pandas.py或者某个目录叫pandas/。如果有Python 在导入import pandas时会优先导入你本地这个文件而不是真正的 Pandas 库。这时候你访问pandas.core时就报出module pandas has no attribute core。确认方式是在报错前先打印模块路径import pandas print(pandas.__file__)如果打印出来的路径不是 site-packages 下的 pandas 目录而是你项目里的某个路径基本就是实锤了。解决办法是把本地文件改名删除当前目录下的pandas.py或pandas/文件夹然后彻底重启解释器。这类问题在真实项目里其实不少见因为很多人喜欢把脚本命名为pandas.py或者numpy.py来做练习这个习惯非常危险。另一个原因是 Pandas 版本极老或极新导致内部结构变动。现在的 Pandas 已经把pandas.core视为内部实现不推荐直接访问。如果你在旧项目里看到pandas.core.frame.DataFrame这类写法升级后可能就找不到了。解决办法是改用公开 API比如直接import pandas as pd然后pd.DataFrame。6.2UserWarning: failed to initialize numpy: no module named numpy与版本冲突这个报错常见于装完某个库之后出现。表面上是没找到 numpy但很可能是环境里有多个 Python或者 numpy 没有装到正确的环境中。排查链路如下先执行python -c import numpy; print(numpy.__version__)看当前解释器能不能导入 numpy。如果能导入说明当前解释器没问题报错来自另一个解释器。这时候要看是谁在报警告经常是某个 IDE 或软件内置的 Python 在扫描环境、初始化扩展时扫描到了一个不完整的环境。如果不能导入说明只是装错了位置。用pip show numpy查看包装到了哪里用python -c import sys; print(sys.executable)确认当前解释器路径两者对比把包装到正确的解释器下即可。另外还要注意 NumPy 和 Pandas/Matplotlib 存在版本兼容区间。如果一起安装时没注意版本可能出现旧版编译产物和新版运行时不匹配报错形式五花八门。最简单稳妥的修复方式是新建一个干净的虚拟环境然后重新安装一次最新稳定版python -m venv myenv # Windows: myenv\Scripts\activate macOS/Linux: source myenv/bin/activate pip install numpy pandas matplotlib虚拟环境的好处是每个项目独立一套依赖不会和系统全局环境互相污染。我以前也偷懒不建虚拟环境直到某次把公司服务器的 Python 环境搞坏了才老实了一辈子。6.3 请安装 matplotlib 以显示图标这类提示是怎么来的有时候你在跑某个第三方库或 GUI 应用时会看到类似 请安装 matplotlib 以显示图标 或者 pip install matplotlib 的提示。这种情况通常是你要用到的某个功能依赖 matplotlib 作为后端来绘图或渲染图标但当前环境里没有装。我在实际调试这类问题时总是先去看错误发生的位置而不是直接执行它提示的命令。因为很多项目里的报错实际上是因为本机有其他依赖没满足提示安装 matplotlib 只是顺带一提。最稳妥的方案依然是在项目虚拟环境里用pip install matplotlib装上然后重新跑一下。如果你是离线环境就回到前面第 2.3 节的那套离线安装流程去联网机器下载 wheel 包拷贝过来后手动安装注意同时把依赖一并处理好。一个容易遗漏的细节是离线安装后也要记得做一次import matplotlib冒烟测试因为 wheel 包之间有依赖顺序要求少一个依赖哪怕安装了也会在运行时才报错。7. 综合实战从 Excel 到一张完整图表的完整数据链路7.1 案例背景与完整代码到这里三个库各自的用法都过了一遍。我用一个完整的小案例把它们串起来目标是把一份订单表数据读取进来做清洗和计算最后画出一张销售额趋势图。假设当前目录下有一个orders.xlsx包含三列日期、销售金额、销售数量。其中日期列有部分缺失销售金额列有部分字符串类型混入。下面是完整代码import pandas as pd import numpy as np import matplotlib.pyplot as plt # 1. 读取数据 df pd.read_excel(orders.xlsx) # 2. 查看数据结构和缺失情况 print(df.info()) print(df.isnull().sum()) # 3. 数据清洗日期转成 datetime金额转成数值缺失值填充处理 df[日期] pd.to_datetime(df[日期], errorscoerce) df[销售金额] pd.to_numeric(df[销售金额], errorscoerce) df df.dropna(subset[日期]) # 删掉日期缺失的行 df[销售金额] df[销售金额].fillna(df[销售金额].median()) # 金额缺失用中位数填充 # 4. 用 NumPy 计算一些聚合统计 amounts df[销售金额].to_numpy(dtypenp.float64) print(总销售额:, amounts.sum()) print(单笔平均金额:, amounts.mean()) print(最大单笔金额:, amounts.max()) # 5. 按月份汇总销售额 df[月份] df[日期].dt.to_period(M) monthly df.groupby(月份)[销售金额].sum() # 6. 导出清洗后的数据 df.to_excel(orders_cleaned.xlsx, indexFalse) # 7. 绘图 plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei, PingFang SC] plt.rcParams[axes.unicode_minus] False fig, ax plt.subplots(figsize(10, 5)) ax.plot(monthly.index.astype(str), monthly.values, markero, linestyle-) ax.set_xlabel(月份) ax.set_ylabel(销售额) ax.set_title(各月销售额趋势) plt.tight_layout() plt.show()7.2 每一行代码背后的关键细节这段代码看着不复杂但里面每一个选择背后都有原因。读取 Excel 后第一件事不是绘图而是df.info()看结构因为清洗前你永远不知道数据有多脏。日期转 datetime 失败的行会被置为 NaT所以dropna(subset[日期])删除的只是真正无效的行。金额列混入字符串时pd.to_numeric(..., errorscoerce)会把非数字变成 NaN后面用中位数填充避免异常值对结果冲击过大。用 NumPy 计算聚合统计其实用 Pandas 的df[销售金额].sum()也能直接做但这里特意演示了df[销售金额].to_numpy(dtypenp.float64)的转换方式。这在实际工作中非常常见Pandas 做完了数据整理要把列转成 NumPy 数组去做更底层的计算或者传入机器学习模型。月份分组用的是df[日期].dt.to_period(M)这个操作可以很方便地按月份提取周期对象再groupby就能得到月度汇总。这里不用 NumPy因为groupby本来就是 Pandas 的强项。绘图时我把monthly.index转成字符串再传给 x 轴避免了 Matplotlib 对 PeriodIndex 的一些兼容问题。这个细节在旧版 Matplotlib 上特别有用新版虽然也能直接处理但显式转字符串更保险。跑完这段代码你会看到一张月度销售额趋势折线图同时当前目录下多了一个orders_cleaned.xlsx。整个过程就是这套数据科学工具链最典型的协作方式Pandas 清理和汇总数据NumPy 做底层数值计算Matplotlib 把结论可视化。三个库各用一点数据链路就走通了。7.3 数据源换成爬虫 JSON 和导出结果如果读入的不是 Excel而是爬虫拿到的 JSON 列表流程也没有太大区别。把列表转成 DataFrame 后后面的清洗、分组、绘图流程完全一致。import pandas as pd # 假设爬虫返回的是一个包含多个 dict 的列表 data [ {日期: 2024-01-05, 销售金额: 120.0}, {日期: 2024-01-12, 销售金额: 85}, {日期: None, 销售金额: 90} ] df pd.json_normalize(data) # 把嵌套结构展开成 DataFrame df[销售金额] pd.to_numeric(df[销售金额], errorscoerce) print(df)pd.json_normalize()能把嵌套的 JSON 结构拍平成表格这对于爬虫数据特别友好。工具链的优势就在这里数据源可以变处理管线不用推翻重写。如果你还需要把结果导出到 Excel 给同事看一行df.to_excel(output.xlsx, indexFalse)就搞定。注意在写入带有中文字符的 CSV 时用encodingutf-8-sig在写入 Excel 时记得关闭索引这些前面都提过做一遍就会形成肌肉记忆。最后分享一个我个人很受用的经验入门这套工具链不要一上来就背 API而是准备一个自己的最小数据集。我当年就是用一份几百行的历史销售表反复练手日期解析、缺失值、字符串混入、中文图例显示所有问题一次性踩了个遍。想真正记住 NumPy、Pandas、Matplotlib 这些东西靠的不是看文档而是拿一份真实数据从头到尾跑通一遍清洗、计算、绘图全流程。等你跑完两三遍后再回头看会发现所有当初觉得玄乎的概念其实都是手边最朴素的工具而已。如果实战中遇到环境又乱了多打印sys.executable、pandas.__file__、numpy.__version__这三个值它们能把绝大多数环境错配问题直接暴露出来。这套工具链本身并不难难的是在庞大生态里找到一条清晰的入门路径希望这篇内容能帮你少走一段弯路。