ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

pandas数据可视化实战:从数据清洗到图表导出一次搞定

pandas数据可视化实战:从数据清洗到图表导出一次搞定 干这行时间久了你会发现一个现象很多人一提到 Python 数据可视化第一反应就是 matplotlib、seaborn、pyecharts 这些专门画图的库。但你们可能忽略了一个最顺手的东西——pandas 自己就内置了绘图方法。我自己的习惯是拿到一批新数据先不急着上复杂工具直接用 pandas 的 plot 快速扫一眼趋势和分布心里有数之后再决定要不要做精细化的图表或者上交互式面板。这篇文章就围绕 pandas 进行数据可视化这件事把我平时用得最多的技巧、踩过的坑、还有怎么把 pandas 的可视化能力和数据清洗、分组聚合、格式导出这些环节串起来完整梳理一遍。适合那些已经会 pandas 基础操作、但每次画图都要临时查 matplotlib 文档的朋友也适合正在做爬虫数据清洗、运营报表、毕业设计的同学。1. 为什么说 pandas 自带的可视化能力被严重低估1.1 先搞清楚定位pandas 的 plot 是以 matplotlib 为基础的轻量封装pandas 之所以能画图本质上是调用了 matplotlib 的 pyplot 接口然后针对 Series 和 DataFrame 做了大量“自动映射”。你不需要手动写plt.figure()、plt.plot()、plt.xlabel()这一整套流程只要数据整齐一行.plot()就能出图。这样做的好处显而易见在探索性数据分析阶段你要的是“快速看到趋势”而不是先花 15 分钟配置坐标轴标签。比如我从线上数据库拉出来一张 30 天的订单表直接做一次groupby(日期)[金额].sum().plot()5 秒钟就能判断哪天是峰值、哪天是低谷这个效率是手工写 matplotlib 流程没法比的。但这里要强调一个定位问题pandas 的 plot不是为了替代 matplotlib更不是为了替代 seaborn 等统计绘图库。它的定位应该是“数据分析链路里的快照工具”解决的是“我接下来该往哪个方向深入分析”这个前置问题。如果你要做一份要交给客户或者领导看的正式报告还是建议把数据导出后用 matplotlib 精细调整或者直接上 pyecharts 做交互式大屏。从我个人的经验来看pandas 内置绘图最适合三类场景数据清洗过程中的随看随画刚加载完数据想知道缺失值分布、类型分布直接.hist()看一遍。特征工程和筛选阶段看两个变量有没有线性关系画个散点图矩阵迅速判断。阶段性成果汇报给同事看中间分析结果不需要多精美能表达观点就行。1.2 从“数据处理”到“数据可视化”的自然衔接用 pandas 做可视化的另一个隐形优势是它能把数据处理和绘图这两件事放在同一套 API 下完成。做爬虫数据可视化的朋友应该深有体会数据抓下来之后往往要经过一层层清洗——去重、补缺失值、改类型、筛选范围这些操作全在 pandas 里完成如果画图还得切到另一个库的语法思路很容易断。而在 pandas 里处理完直接.plot()整个工作流一气呵成。我见过很多人在入门阶段被 matplotlib 的状态机搞得一头雾水什么plt.subplots()、ax plt.gca()、plt.tight_layout()……其实这些不需要在探索阶段就理解。pandas 的 plot 方法帮你把多数状态管理掉了你需要关注的只是“数据长什么样”和“该用哪种图”。而且 pandas 的 plot 返回值可以直接继续操作。.plot()返回的是一个 matplotlib 的Axes对象也就是说你完全可以先用 pandas 快速出一张基线图再在这个 Axes 上叠加自定义元素。这相当于给“快速出图”和“精细调整”之间搭了一座桥。等分析进入尾声需要用 matplotlib 精细调整的时候你也不会觉得前面的工作被浪费了。2. 准备工作装好环境避开版本坑2.1 pandas 安装与 Python 版本适配先说说环境安装。很多人用的 Python 版本五花八门有 3.8、3.9、3.10现在 Python 3.12、3.13 也出来了。最常被问的问题之一是“Python 3.10 到底应该用哪个 pandas 版本”。直接给结论Python 3.10 建议使用 pandas 1.4.0 以上的版本最好直接上 1.5.x 或 2.x 系列。原因很简单pandas 从 1.4.0 开始完整支持 Python 3.10 的 C 扩展编译机制如果你装了老版本比如 1.3.x在 Windows 上安装时很可能因为无法找到匹配的预编译包而报错或者安装成功但运行时报一些诡异的底层错误。在终端里安装最稳的方式# 使用 pip 安装最新稳定版 pip install pandas matplotlib # 如果因为网络原因下载慢可以换国内镜像源 pip install pandas matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple # 如果你使用的是 conda 环境用 conda 安装更省心会自动帮你匹配版本 conda install pandas matplotlibPyCharm 里安装的话在File - Settings - Project - Python Interpreter中点击右边的号搜索 pandas 并点击 Install Package 即可。有两点要注意第一安装前先确认右下角选中的解释器是你当前项目用的那个别装到别的环境去了第二PyCharm 的包管理有时候会卡在进度条这不是死机通常等一会儿就好如果长时间没反应建议切到终端用 pip 安装反正效果一样。装完之后在交互环境里验证一下import pandas as pd print(pd.__version__)顺便也检查一下 matplotlibimport matplotlib print(matplotlib.__version__)如果你发现 pandas 版本很老比如 1.2.x可以用pip install -U pandas升一下级。版本这个东西虽然很多时候老版本也能跑但在绘图相关的 API 行为上新老版本之间的差异可能直接导致你的代码报错或者画出来的图跟预期完全不一致。2.2 绘图后端与中文显示的基本配置pandas 的 plot 依赖 matplotlib 渲染后端。在 Jupyter Notebook 里你需要先执行一行魔法命令否则图形不会内嵌显示%matplotlib inline在 PyCharm 的 Python 控制台或者普通脚本里如果图像没弹出来往往是因为缺少plt.show()。pandas 的.plot()方法只是把图画在内存里并不会自动推送到屏幕上很多人第一次用的时候会遇到“没反应”的情况其实只要在代码末尾加上import matplotlib.pyplot as plt和plt.show()就行了。还有一个几乎人人都会遇到的问题是中文乱码。matplotlib 默认字体不包含中文字符直接绘图的话标题和图例里的中文会显示成方框。这个问题的标准解法是手动指定字体参数。下面的代码我先给出一种比较通用的方案更详细的原因和排查方法放到第 7 章import matplotlib.pyplot as plt # Windows 下常见中文字体是 SimHei 或 Microsoft YaHei plt.rcParams[font.sans-serif] [SimHei] # 解决负号显示为方块的问题 plt.rcParams[axes.unicode_minus] FalsemacOS 下可以改成[Arial Unicode MS]Linux 下可以改成[WenQuanYi Zen Hei]或[Noto Sans CJK SC]。别小看这几行配置很多初学者第一个坑就是在这里。3. 绘图前必须做好的数据预处理3.1 数据类型转换让每一列都用对类型很多人画图的时候发现坐标轴不对劲比如横轴上的数值变成了字符串形式、日期被当成了文本或者纵轴上的数据堆积在一起看不出差异。这些问题里八成是数据类型没转对。pandas 里比较常用的类型转换方法有astype()、pd.to_datetime()和pd.to_numeric()。其中astype()适合在数据本身是数字但存成了字符串的情况下使用比如从网页爬下来的数字带上了千分位逗号或者从 Excel 里读出来后被强制变成了文本。我举个实际场景假设你有一个销售明细 DataFrame其中销售额这一列是从爬虫抓下来的值是1,234.56这种带逗号的字符串。直接画图肯定不行得先清理import pandas as pd df pd.DataFrame({ 日期: [2024-01-01, 2024-01-02, 2024-01-03], 销售额: [1,234.56, 1,890.02, 2,345.10] }) # 先去掉千分位逗号再转成数值类型 df[销售额] df[销售额].str.replace(,, ).astype(float) print(df.dtypes)日期字段最好也统一转成datetime64类型不然画折线图的时候pandas 会把日期当成普通类别横轴的顺序可能完全乱掉df[日期] pd.to_datetime(df[日期])转完之后你可以顺手df.info()看一眼每一列的 dtype确认没问题再开始画图。这个习惯非常重要我几乎每次拿新数据都会先执行一下df.info()和df.head()别偷懒。3.2 去重与筛选只画需要的数据数据清洗里另一个高频操作是去重。做爬虫数据可视化的朋友肯定遇到过这种问题同一个商品在一天内被抓了多次或者同一个用户在多个渠道重复注册结果统计出来的计数虚高。pandas 提供的drop_duplicates()就是干这个的。有一个挺典型的需求是指定两列的值均相同则取第一条数据即可。这个需求在订单数据里特别常见比如订单号和商品编码都相同说明是同一行记录被重复导入了这时候只需要保留第一条。实现方式很简单# 先按时间排序确保保留的是最早那条 df df.sort_values(下单时间) # 指定两列作为判断依据保留第一条 df_deduplicated df.drop_duplicates(subset[订单号, 商品编码], keepfirst)这里面的关键细节是先sort_values再去重。因为keepfirst保留的是“在原始 DataFrame 顺序中第一次出现的行”如果你希望保留的是时间最早或时间最晚的那条就必须先把顺序排好。还有一种场景是只要去重、顺序无所谓那就不必排序直接drop_duplicates(subset[列A, 列B])就行。如果希望更新原来的 DataFrame记得加inplaceTrue或者直接赋值覆盖。筛选操作也是绘图前常做的事。比如我只想看看最近一周的数据趋势或者只看销售额大于某个阈值的品类可以直接用布尔索引# 只保留销售额大于1000的记录 df_filtered df[df[销售额] 1000] # 只看最近7天 recent_7_days df[df[日期] pd.Timestamp.now() - pd.Timedelta(days7)]画图之前做筛选的目的不只是为了减少数据量更重要的是避免异常值或无关数据干扰你的判断。比如总订单里混入了几笔测试订单金额是负数如果不筛选画出来的柱状图会出现一个负向的大坑导致整个图的比例失衡受众的第一印象就是“数据有问题”。这种低级错误在真正的工作汇报里非常减分。4. 手把手实操pandas 核心图表与参数速查4.1 折线图看清趋势最常用的图折线图是时间序列分析里最常用的图。pandas 里画折线图最简单的方式就是直接对 Series 调用.plot()默认就会生成折线图。我拿一个访问量日志来示范。假设数据已经按天统计好了存放成daily_visits这个 Seriesindex 是日期value 是访问量import pandas as pd import numpy as np # 模拟40天的访问量数据 np.random.seed(42) date_range pd.date_range(2024-03-01, periods40, freqD) visits np.random.normal(3000, 500, size40).astype(int) daily_visits pd.Series(visits, indexdate_range, name访问量) # 基础折线图 daily_visits.plot(figsize(10, 5), title每日访问量趋势, gridTrue)如果数据在 DataFrame 里比如有多列指标直接.plot()会自动生成多条折线并且自动创建图例。多列场景下有个参数值得记住subplotsTrue可以把各列分别画在独立的子图里避免多条线挤在一起看不清。比如df[[访问量, 订单量, 用户数]].plot(subplotsTrue, figsize(10, 8), sharexTrue)这个sharexTrue也很重要它保证了所有子图共享同一个横轴对比的时候不容易错位。折线图的核心参数我再整理几个figsize(宽, 高)控制整个图形尺寸。title标题设置图标题。gridTrue显示网格线读数值的时候方便。xlim、ylim手动指定轴范围比如ylim(0, 5000)。style--o设置线条样式和数据点标记--表示虚线o表示圆形数据点。colorred自定义颜色、多系列时也可以传颜色列表。我实际使用中的一个小技巧是在数据点比较多超过50个时不加数据点标记只保留折线数据点少少于20个时加上marker方便直接读出每个点的值。4.2 柱状图对比分类数据柱状图适合对比不同类别的数值大小比如各品类销量、各地区业绩、各时间段订单量等。pandas 里通过kindbar指定# 各品类销量 category_sales df.groupby(品类)[销量].sum().sort_values(ascendingFalse) # 画柱状图 category_sales.plot(kindbar, figsize(10, 6), title各品类销量对比, color#4C72B0)横向柱状图kindbarh在品类名称很长的时候特别好用因为名称可以直接显示在 y 轴左侧不会像纵向柱状图那样把 x 轴标签挤得歪歪扭扭。如果想把多个指标并列显示可以把数据整理成 DataFrame比如compare pd.DataFrame({ 销量: [100, 200, 150], 销售额: [10000, 25000, 18000] }, index[品类A, 品类B, 品类C]) # 并排柱状图 compare.plot(kindbar, figsize(8, 5))如果希望把各个指标堆叠起来看总量传入stackedTrue就可以了。比如按月统计各渠道订单量堆叠柱状图可以清楚地看到每个月的总订单量同时还能看出不同渠道的占比变化。这里有个经验柱状图默认 x 轴刻度位置是基于整数索引的如果 index 是字符串它会自动显示字符串如果 index 是日期画bar图时日期会被当作普通类别而不是连续时间轴。如果你希望日期均匀分布在横轴上应该用折线图而不是柱状图。4.3 饼图与环形图看占比但别滥用于复杂数据饼图在 pandas 里通过kindpie绘制用autopct参数控制百分比显示格式sales_by_channel df.groupby(渠道)[销售额].sum() sales_by_channel.plot( kindpie, figsize(8, 8), autopct%.1f%%, # 显示百分比保留1位小数 startangle90, # 起始角度 legendFalse )如果想让饼图变成环形图中间镂空效果可以通过plt.pie搭配wedgeprops实现pandas 内置参数里没有直接的hole参数所以我一般在需要环形图的时候干脆改用 matplotlib 手写import matplotlib.pyplot as plt values sales_by_channel.values labels sales_by_channel.index plt.pie(values, labelslabels, autopct%.1f%%, startangle90, wedgeprops{width: 0.4}) # width 控制内径比例 plt.show()关于饼图我要多说两句当分类超过 5 个时不要再画饼图。人的视觉对“角度大小”的敏感度远低于对“长度高低”的敏感度分类一多小比例的扇区根本看不清。这时候更应该用柱状图。饼图只适合展示“两三个核心分类占总体的比例”这类简单信息。4.4 直方图与箱线图看数据分布直方图用来观察数值型变量的分布形态在 pandas 里用kindhist或者直接.hist()# 看用户年龄分布 df[年龄].hist(bins20, figsize(8, 5), edgecolorwhite)bins参数控制分箱数量这个参数直接影响图表的展示效果。bins太少分布形态被过度平滑bins太多噪声太大反而看不出规律。我的经验是先用默认值画一次再根据数据范围调整。比如数据是 18-60 岁用 20 个箱体就比较合适每个箱体大约 2 岁一个区间。如果要一次看多个数值字段的分布可以直接对 DataFrame 调用.hist()它会自动生成一组子图每个字段一个df[[年龄, 消费金额, 活跃天数]].hist(bins20, figsize(12, 8))箱线图是另一个非常实用的分布图能看到中位数、四分位数和异常点。pandas 里用kindbox绘制df[[年龄, 消费金额]].plot(kindbox, figsize(8, 6))箱线图特别适合在数据清洗阶段用来发现异常值。如果某个字段出现了大量远超箱体范围的散点很可能数据里存在脏值需要在画其他图之前处理掉。4.5 散点图看两个变量之间的关系散点图用来判断两个数值变量之间是否存在线性关系、正相关还是负相关。pandas 里两种画法# 方法一直接用 kindscatter要求指定 x 和 y df.plot(kindscatter, x广告投入, y销售额, figsize(8, 6)) # 方法二如果 data 参数改成这种写法更容易记住 df.plot.scatter(x广告投入, y销售额, s20, alpha0.5)alpha0.5让点有半透明效果在数据点很多、重叠严重的时候能看出密度差异。如果想在散点图上再加点颜色维度比如按用户分组着色可以传入c参数或者结合colormap。同时看多对变量关系时可以用 pandas 内置的scatter_matrix但这个功能在较新的 pandas 版本里移动到了pandas.plotting模块下from pandas.plotting import scatter_matrix scatter_matrix(df[[年龄, 消费金额, 活跃天数]], figsize(12, 12), diagonalhist)diagonalhist表示对角线位置显示直方图其他位置显示两两散点图。这张矩阵图在特征筛选阶段能帮你快速判断哪些变量之间可能存在共线性值得多用。5. 进阶分组聚合与透视表可视化5.1 groupby 与 plot 的经典组合数据可视化很多场景不是直接对原始数据画图而是先分组聚合、再对聚合结果绘图。pandas 里groupby和plot的组合非常自然。假设我们要看每个月的销售额变化趋势并且想要区分不同产品线的贡献。做法是先按月份和产品线分组聚合再用unstack()把产品线展开成多列monthly df.groupby([月份, 产品线])[销售额].sum().unstack() monthly.plot(figsize(12, 6), title各产品线月度销售额趋势)这里unstack()的作用是把二级索引变成列名形成“行是月份、列是产品线”的表格结构这样 plot 才能自动画出多条折线图例自动对应产品线名称。还有一种场景是对同一字段做多种聚合比如想看每个区域的总销售额、平均客单价、订单数量可以这样grouped df.groupby(区域)[销售额].agg([sum, mean, count]) grouped.plot(kindbar, subplotsTrue, figsize(12, 8), sharexTrue)subplotsTrue让三个指标分别显示在三个子图里避免数量级不同导致某个子图被压扁。比如总销售额可能是百万级平均客单价只有几百画在同一张图里客单价的趋势完全看不出来。5.2 pivot_table 透视表比 Excel 透视表更适合出图如果你用过 Excel 的透视表那么 pandas 的pivot_table一定能让你觉得亲切。它比 groupby 更适合做多维交叉分析因为它允许你同时指定行索引、列索引和聚合值并且自动处理缺失值。举个例子我想看不同产品线在不同月份的销售额分布用两个维度交叉透视表一步到位pivot pd.pivot_table( df, values销售额, index月份, # 行索引 columns产品线, # 列索引 aggfuncsum, # 聚合方式 fill_value0 # 缺失值填充为0 ) pivot.plot(kindbar, figsize(12, 6), title产品线 × 月份销售额)透视表生成的结果是一个标准的 DataFrame所以可以直接用前面说过的所有绘图方法。如果列数太多比如有 10 个产品线用并排柱状图会挤成一团。这时候有两个选择一是只用折线图看趋势二是用堆叠柱状图stackedTrue看总量和结构。另一个比较高级的用法是把透视表的结果画成热力图需要 seaborn 支持import seaborn as sns sns.heatmap(pivot, annotTrue, fmtd, cmapYlOrRd)热力图在观察“哪个月哪个产品线销售额高”这种交叉维度问题时比柱状图高效得多颜色深浅一眼扫过去就有结论。我经常先画热力图做初步探索然后挑出需要重点分析的单元格再针对性地画柱状图。6. 常见数据格式与结果导出6.1 用 Parquet / Feather 替代 CSV数据量大的时候必须知道做爬虫数据可视化、或者处理稍微大一点的数据集时CSV 文件读起来就有点力不从心了。CSV 有几个痛点不带数据类型读进来还要重新转、体积大、读写慢。相比之下Parquet 和 Feather 这两种列式存储格式能明显提升效率。我从实际项目里的体感数据来看同样一份 500MB 的 CSV用 pandas 读取大约要 10-20 秒换成 Parquet 后只需要 1-2 秒而且内存占用更低。当然CSV 的好处是通用性强任何工具都能打开。所以我的建议是原始数据可以存 CSV中间处理结果和频繁复用的数据存 Parquet程序内部临时交换数据用 Feather。Feather 和 Parquet 的区别主要有两点读写速度Feather 在单机场景下通常更快本质上是 Arrow 格式的原生存储。文件大小和生态兼容性Parquet 压缩率更高而且是大数据生态Spark、Hive、ClickHouse 等的通用格式跨系统交换时优先级最高。代码操作非常简单和read_csv/to_csv几乎一样# 写入 Parquet df.to_parquet(data.parquet, indexFalse) # 读取 Parquet df pd.read_parquet(data.parquet) # 写入 Feather df.to_feather(data.feather) # 读取 Feather df pd.read_feather(data.feather)我这里提一下“pandas 与 numpy 如何在 Parquet/Feather 场景下配合”的问题。很多人的数据在 pandas 里经过处理后需要转成 numpy 数组做矩阵运算或模型输入然后再回到 DataFrame 里画图。实际上 pandas 和 numpy 的数据转换是无缝的# DataFrame 的某一列转 numpy 数组 arr df[销售额].to_numpy() # numpy 数组转 DataFrame df_new pd.DataFrame(arr.reshape(-1, 1), columns[销售额]) # 画图之前再转回 DataFrame 的 Series pd.Series(arr).plot()之所以强调这个流程是因为很多初学者会花大量时间把数据在 CSV、Excel、JSON 之间转来转去等数据处理完了才想起来要画图。其实从原始数据到最终成图中间完全可以用 Parquet/Feather 做中转又快又不容易出错。6.2 把多级表头的数据和图表一起导出到 Excel做运营报表、周报月报的时候经常需要把 pandas 的分析结果导出成 Excel而且如果分析维度多往往要用多级表头就是那种第一行是大类、第二行是细分列名的效果。pandas 导出 Excel 本身支持多级表头只要 DataFrame 的列是 MultiIndex 即可。一个典型的场景统计各区域各渠道的销售额和订单量希望区域作为一级表头渠道作为二级表头# 创建多级列索引 columns pd.MultiIndex.from_product( [[华东, 华北], [销售额, 订单量]], names[区域, 指标] ) # 模拟数据 df_report pd.DataFrame( np.random.randint(100, 1000, size(5, 4)), columnscolumns, indexpd.date_range(2024-06-01, periods5, freqD) ) # 导出 Excel with pd.ExcelWriter(报表.xlsx, engineopenpyxl) as writer: df_report.to_excel(writer, sheet_name明细)注意pd.ExcelWriter需要指定engineopenpyxl这是 xlsx 格式的引擎。如果你没装 openpyxl会报错提示缺少依赖先pip install openpyxl就行。默认情况下pandas 导出多级表头时会把相同的一级表头合并单元格。如果想保留每一个格子都是独立值方便后续在 Excel 里做透视或筛选可以传merge_cellsFalsedf_report.to_excel(writer, sheet_name明细, merge_cellsFalse)如果想把画好的图也放进同一个 Excel 文件步骤会稍微多一点。需要用 openpyxl 的 Image 对象加载图片再通过writer.book访问 workbook 插入工作表from openpyxl import load_workbook from openpyxl.drawing.image import Image as XLImage import matplotlib.pyplot as plt import io # 先把图保存成临时图片 fig, ax plt.subplots(figsize(10, 5)) df_report.sum(axis1).plot(axax, title每日总额趋势) plt.tight_layout() # 保存到内存 img_buffer io.BytesIO() fig.savefig(img_buffer, formatpng) img_buffer.seek(0) # 写入 Excel 同一个文件 with pd.ExcelWriter(报表.xlsx, engineopenpyxl) as writer: df_report.to_excel(writer, sheet_name明细) ws writer.book.create_sheet(趋势图) ws.add_image(XLImage(img_buffer), A1)把图和表放在同一个 Excel 文件里在日常工作中非常实用。很多时候你不需要开发一个复杂的数据看板只要把 pandas 生成的分析结果和图表打成包发给同事对方就能直接在 Excel 里看到完整结论了。7. 常见问题与排查技巧实录7.1 AttributeError: module pandas has no attribute Int64Index这个报错在 pandas 升级后特别容易出现。热词里都出现了说明踩坑的人不少。原因是在 pandas 1.5 及以上版本Int64Index这个类被移除了官方推荐直接用Index类。那为什么还有人会碰到这个错误呢绝大多数情况是代码里写了类似这样的老式用法# 老版本里的写法新版本已经不支持 idx pd.Int64Index([1, 2, 3])或者某些第三方库内部还在调用pd.Int64Index导致一运行就报这个 AttributeError。解决方法很简单分两种情况处理如果是你自己的代码直接把pd.Int64Index([1, 2, 3])改成pd.Index([1, 2, 3])即可。如果是第三方库的问题建议先升级对应的库版本或者把 pandas 版本降回 1.4.x。某些老库在新 pandas 下确实会出现兼容问题强行运行会有连锁报错。我自己的建议是直接改成pd.Index([1, 2, 3])。因为从功能上来讲pandas 的整数索引完全可以由Index类统一代表没有必要去特化一个Int64Index。这类问题的排查思路也简单报错信息里会明确提示是哪一行代码调用了不存在的属性顺着堆栈往上翻就能找到责任人。7.2 版本相关pandas 与 numpy、matplotlib 的兼容性问题pandas 对 numpy 和 matplotlib 版本有比较强的依赖。如果你在安装 pandas 的时候用的是非常新的 numpy而 pandas 还没适配就可能出现底层 C 扩展加载失败或者某些数值运算结果异常。比如这个经典错误AttributeError: module pandas has no attribute NA通常是因为 numpy 和 pandas 版本不匹配pandas 检测不到它需要的 numpy API。遇到这种情况先用 pip 检查一下当前环境里的版本pip list | grep -E pandas|numpy|matplotlib如果发现 numpy 版本过于新比如 pandas 2.0 搭配 numpy 2.x 的早期版本是有问题的可以先把 numpy 降到一个稳定版本pip install numpy2反过来如果你的 pandas 版本太旧那就升级 pandaspip install -U pandas最稳妥的做法是直接使用 conda 环境用conda install pandas matplotlib安装conda 会帮你解析版本的依赖关系。我自己的习惯是数据项目一律用 conda 建独立环境避免不同项目之间互相污染依赖。7.3 中文乱码和负号显示问题前面提过中文乱码这里展开说。matplotlib 默认字体 DejaVu Sans 不支持中文所以图里的中文标题、标签都会变成小方块。解决方法是设置 matplotlib 的字体参数选择系统里已安装的中文字体。Windows 系统用以下方式一般能解决import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] FalsemacOS 用户可以换成plt.rcParams[font.sans-serif] [Arial Unicode MS]如果你不知道系统到底装了哪些中文字体可以用下面这段代码列出所有可用字体寻找关键字import matplotlib.font_manager as fm fonts [f.name for f in fm.fontManager.ttflist] cjk_fonts [f for f in fonts if any(k in f for k in [Hei, Song, Kai, Ming, Noto, WenQuanYi, Microsoft YaHei])] print(cjk_fonts)axes.unicode_minus False这个设置是用来解决负号显示为方块的问题的很多新手只设置了中文字体忘了设置这一行结果坐标轴负号全部变成方块第一眼还以为是中文字体没生效。7.4 图不显示的几种情况画了图却不出来这在 pandas 可视化里很常见。我整理了四种最典型的原因一是 Jupyter Notebook 里没有执行%matplotlib inline。这个魔法命令的作用是把 matplotlib 的图形直接内嵌到 Notebook 输出区没有它画完的图只能在弹出窗口里显示如果 Notebook 运行在远程服务器上甚至看不到弹窗。二是在普通 Python 脚本里没有调用plt.show()。pandas 的.plot()只是创建了图形对象没有真正把窗口显示出来。记住在脚本最后加上import matplotlib.pyplot as plt plt.show()三是在函数里画图函数执行完图形对象被回收了。这种情况在 Jupyter 里会遇到解决办法是在函数里显式返回.plot()的返回值或者在函数内部调用plt.show()把图形推送到输出。四是同时画多张图但只显示了最后一张。原因是 matplotlib 默认会把所有画在当前的图形叠加或覆盖解决方案是用plt.figure()开启新的图形画布plt.figure(figsize(8, 5)) df[年龄].hist(bins20) plt.show() plt.figure(figsize(8, 5)) df.plot.scatter(x广告投入, y销售额) plt.show()排查思路简单说就是先确认有没有调用plt.show()再确认后端是什么最后检查是否每次画图前都新建了 figure。7.5 导出 Excel 时常见的“伪错”还有一个导出 Excel 时的常见问题to_excel()报错提示找不到引擎比如ModuleNotFoundError: No module named openpyxl。这个不是 pandas 的问题只是缺少 xlsx 格式的依赖引擎。安装一下就行pip install openpyxl如果导出时遇到ValueError: Excel does not support datetimes with timezones说明数据里有时区信息的日期列。解决办法是把时区去掉df[日期] df[日期].dt.tz_localize(None)这个问题在爬虫数据处理时特别容易踩到因为很多网页时间字段自带时区后缀比如2024-06-01 12:00:0008:00直接导出 Excel 就会炸。8. 我给新手的一个建议最后分享一个我自己的习惯拿到任何数据先用 pandas 画三张图——直方图看分布、折线图看趋势、柱状图看分组对比。这三张画完你对数据的理解水平已经超过大多数只会跑describe()的人了。而且这三张图用的全是 pandas 内置 plot不需要额外记忆一堆绘图库的 API。随着对 pandas 越来越熟你会发现绘图和数据处理之间的界限其实是模糊的。真正影响图表质量的往往不是绘图语法本身而是数据清洗是否到位、分组口径是否合理、是否选对了图表类型。希望这篇文章能帮你把这些环节打通。
返回列表