拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

数据分析学习小结:用pymysql+pandas+matplotlib打通数据全流程

数据分析学习小结:用pymysql+pandas+matplotlib打通数据全流程

1. 从 MySQL 取数到出图:一条能跑通的数据分析入门链路

数据分析入门最容易卡住的地方,往往不是某个库的语法,而是「取数—清洗—聚合—出图」这条链路中间断了一环。你可能跟着教程写完了pymysql.connect,结果fetchall()回来一堆元组不知道怎么下手;或者 DataFrame 建好了,groupby之后列名对不上;再或者图画出来了,中文全是方块。这篇学习小结就按我自己踩过的顺序,把 pymysql 读取 MySQL、pandas 做 DataFrame 清洗聚合、matplotlib 出图这三段拼成一条完整可复制的流程,最后给你一个可以持续记录的学习小结模板。

先说清楚这套东西是什么、能做什么、适合谁。pymysql 是 Python 连接 MySQL 的驱动,负责把 SQL 查询结果拿回本地;pandas 的 DataFrame 是带行列索引的二维表格结构,负责筛选、打标签、分组、聚合、排序;matplotlib 负责把聚合后的结果画成折线图、饼图、柱状图、K 线图。适合刚学完 Python 基础、想用真实数据库数据练手的数据分析入门者,也适合需要快速做内部报表原型的同学。整条链路的核心检索词就是 pymysql 取数、pandas DataFrame 清洗聚合、matplotlib 可视化,三者缺一不可。

我建议你按「先跑通取数、再练 DataFrame、最后接图表」的顺序推进,每一步都有可验证的输出。下面从环境准备讲到排错,中间所有代码都可以直接复制改连接参数使用。你不需要一次全懂,先把第一段跑出len(history_count)的数字,信心就来了。

2. 前置准备:TaoToken 接入与 pymysql/pandas/matplotlib 环境搭建

这一节解决两件事:一是把模型调用能力接进来,方便你在写 SQL 和调 DataFrame 时随时问;二是把本地 Python 环境装好。很多入门者卡在环境上,所以我把版本和安装命令写全。

先说 TaoToken 的接入。它的 API 地址是https://taotoken.net/api,官网是https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。你需要在控制台创建 API Key,然后把它写进环境变量或配置文件。如果你用的是 Claude Code 这类编码工具,可以走 Coding Plan;如果只是想验证模型对话效果,用模型对话页面即可。接入文档在 doc 页面,API Key 管理在 api-keys 页面。注意,TaoToken 是合规的模型调用入口,不要把它和任何网络加速工具混为一谈。

环境这边,Python 建议 3.9 以上。安装三个核心库:

pip install pymysql pandas matplotlib

如果你还要处理 K 线里的高精度小数,标准库decimal就够了,不用额外装。验证安装:

python -c "import pymysql, pandas, matplotlib; print(pymysql.__version__, pandas.__version__, matplotlib.__version__)"

能打印出三个版本号就说明环境 OK。接下来准备一个测试库。我用的是本地 MySQL,建一张history_count表存历年人口变化,字段有year, total, man, woman, city, village;再建一张age_count表存按年龄人口统计,字段有area, age0_14, age15_59, age60, age65。建表语句:

CREATE TABLE history_count ( year INT, total DECIMAL(10,2), man DECIMAL(10,2), woman DECIMAL(10,2), city DECIMAL(10,2), village DECIMAL(10,2) ); CREATE TABLE age_count ( area VARCHAR(32), age0_14 DECIMAL(10,2), age15_59 DECIMAL(10,2), age60 DECIMAL(10,2), age65 DECIMAL(10,2) );

插入几条测试数据后,用命令行mysql -u root -p能select * from age_count;看到结果,就说明数据库侧没问题。这一步别跳过,后面报错排查时你会感谢自己先确认了数据源。

关于模型接入的配置文件,如果你用支持 OpenAI 兼容协议的工具,可以写一个settings.json或config.toml。以通用 JSON 为例:

{ "base_url": "https://taotoken.net/api", "api_key": "sk-你的Key", "model": "claude-sonnet-4-20250514" }

三件套就是 Base URL、Key、Model ID,缺一个都连不上。写 SQL 遇到不确定的聚合写法时,直接把表结构和需求丢给模型,让它给一版 SQL,你再回数据库验证,这个循环对入门者特别高效。

3. 可复制配置:pymysql 连接、DataFrame 清洗聚合与 matplotlib 出图脚本

这一节是全文的核心,给你三段可直接复制的代码。第一段负责取数,第二段负责清洗聚合,第三段负责出图。我按「连接配置—取数—建 DataFrame—清洗—聚合—画图」的顺序组织。

先看连接配置。关键点是cursorclass=cursors.DictCursor,它让fetchall()返回带字段名的字典列表,而不是元组列表,这样DataFrame()一建就有列名,省掉手动指定 columns 的麻烦。

# coding: utf-8 import pymysql as mysql from pymysql import cursors from pandas import DataFrame import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] plt.rcParams['axes.unicode_minus'] = False conn = mysql.connect( host='192.168.0.3', port=3306, user='jiker-coding', passwd='jiker-coding-Pwd-1234', db='coding', charset='utf8', cursorclass=cursors.DictCursor ) def fetch(sql): cursor = conn.cursor() cursor.execute(sql) rows = cursor.fetchall() cursor.close() return rows history_count = fetch("select `year`,`total`,`man`,`woman`,`city`,`village` from `coding`.`history_count` order by year") age_count = fetch("select `area`,`age0_14`,`age15_59`,`age60`,`age65` from `coding`.`age_count` order by area") print("[取数] history_count =", len(history_count), " age_count =", len(age_count))

跑通这段,你会看到两个长度数字。如果报Access denied,检查 user/passwd;如果报Unknown database,检查 db 名。

第二段是 DataFrame 清洗聚合。把字典列表转成 DataFrame,然后做删列、加列、求均值、分组、排序。

df_history_count = DataFrame(history_count) df_age_count = DataFrame(age_count) # 去掉 area 列后按列求平均,得到各年龄段占比 df_age_group = df_age_count.drop('area', axis=1, inplace=False) df_age_group['age60_65'] = df_age_group['age60'] - df_age_group['age65'] df_age_group = df_age_group.mean() del df_age_group['age60'] print(df_age_group)

这里drop(..., inplace=False)返回新对象,不动原表;mean()默认按列求平均;del删掉不需要的列。如果你要按发卡机构统计交易,用groupby().agg():

df_trade = DataFrame(trade_infos) result = df_trade.groupby('ISS_INS_ID_CD').agg({'TRANS_ST': 'count', 'TRANS_AT': 'sum'}) result = result.sort_values(['TRANS_ST'], ascending=False).head(10)

逾期概率统计用打标签加分组:

df_bad = DataFrame(bad_loan_infos) total_num = len(df_bad) overtime = df_bad[df_bad['past_due_days'] > 0] overtime.loc[(overtime.age >= 18) & (overtime.age <= 25), 'AgeGroup'] = '18-25' overtime.loc[(overtime.age >= 26) & (overtime.age <= 30), 'AgeGroup'] = '26-30' overtime.loc[(overtime.age >= 31) & (overtime.age <= 40), 'AgeGroup'] = '31-40' overtime.loc[(overtime.age >= 41), 'AgeGroup'] = '41+' age = overtime[['AgeGroup', 'loan_id']].groupby('AgeGroup').agg('count')

第三段出图。折线图看趋势,饼图看占比,柱状图看排名。

fig, axes = plt.subplots(1, 2, figsize=(12, 5)) axes[0].plot(df_history_count['year'], df_history_count['total'], marker='o') axes[0].set_title('历年人口变化') axes[0].set_xlabel('年份'); axes[0].set_ylabel('总人口') axes[1].pie(df_age_group.values, labels=df_age_group.index, autopct='%1.1f%%') axes[1].set_title('各年龄段占比') plt.tight_layout() plt.savefig('summary.png', dpi=120) plt.show()

K 线大阳线判断用decimal.Decimal保证精度:

import decimal df_k = DataFrame(stock_klines) df_k['big_yang'] = 0 df_k['wave_range'] = 0 df_k.loc[df_k['yclose'] == 0, 'yclose'] = df_k.loc[df_k['yclose'] == 0]['close'] df_k['wave_range'] = (df_k['close'] - df_k['yclose']) / df_k['yclose'] * decimal.Decimal(100.0) df_k.loc[(df_k['wave_range'] >= 1.5) & (df_k['close'] > df_k['open']), 'big_yang'] = 1

房价增长率排序:

df_house = DataFrame(house_prices) df_house['wave_range'] = pd.to_numeric( (df_house['end_price'] - df_house['start_price']) / df_house['start_price'] * decimal.Decimal(100.0), errors='coerce') df_house = df_house.sort_values(by=['wave_range'], ascending=[False]) df_house = df_house.round({'wave_range': 2})

to_numeric把结果转数字,errors='coerce'把转不了的变 NaN,round保留两位。这几段拼起来就是完整链路。

4. 验证请求与成功结果:逐步确认每一步的输出

写完代码不验证,等于没写。这一节给你一套逐步验证动作,每步都有预期输出。

第一步,验证数据库连接。执行print(conn.open),返回True说明连接活着。如果返回False,说明连接已断,检查网络和 MySQL 服务。

第二步,验证取数条数。print(len(history_count), len(age_count)),正常应该打印出两张表的行数,比如30 31。如果打印0 0,说明表里没数据或 SQL 条件过滤掉了。

第三步,验证 DataFrame 结构。print(df_age_count.head()),你应该看到带列名的表格:

area age0_14 age15_59 age60 age65 0 上海 9.80 66.82 23.38 16.28 1 云南 19.57 65.52 14.91 10.75

如果列名是0 1 2 3 4,说明你忘了DictCursor,fetchall()返回的是元组。

第四步,验证聚合结果。print(df_age_group),应该看到各年龄段均值,且age60_65是age60 - age65的结果。如果报KeyError: 'age60_65',检查加列那行是否在mean()之前执行。

第五步,验证图表文件。运行出图脚本后,当前目录应该生成summary.png。用ls -lh summary.png看文件大小,正常几十到几百 KB。打开图片,中文标题正常显示、负号正常显示,就说明rcParams配置生效。

第六步,验证模型接入。如果你用 TaoToken 的模型对话验证 SQL 写法,发一句「帮我写一个按年份分组求 total 均值的 SQL」,能正常返回就说明 Base URL、Key、Model ID 三件套配置正确。这一步和数据分析链路是并行的,用来加速你写 SQL 和调 DataFrame。

把这六步的输出记进你的学习小结模板,格式建议:

步骤命令/代码预期输出实际输出是否通过
连接conn.openTrue
取数len(history_count)>0
结构df.head()带列名
聚合df_age_group均值
出图summary.png文件存在

这个表格本身就是很好的学习记录,下次遇到问题直接翻表。

5. 本篇常见报错排查:401、local proxy failed、reading choices、OAuth

入门阶段报错集中在连接、鉴权、数据结构和模型接入四类。我按真实报错逐条给排查路径。

pymysql.err.OperationalError: (1045, "Access denied for user ...")。这是账号密码错。检查user和passwd是否和 MySQL 里一致,注意密码里的特殊字符。如果确认没错,可能是该用户没有从当前主机连接的权限,用select user, host from mysql.user;看 host 是不是%。

pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on ...")。这是连不上服务。先ping主机,再telnet 192.168.0.3 3306看端口通不通。端口不通多半是 MySQL 没启动或防火墙拦了。

KeyError: 'ISS_INS_ID_CD'。这是列名对不上。print(df_trade.columns)看实际列名,可能是大小写或空格问题。用df_trade.columns = df_trade.columns.str.strip()去空格。

ValueError: could not convert string to float。这是to_numeric遇到非数字。加errors='coerce'把脏数据变 NaN,再df.dropna()或fillna(0)。

模型接入侧,401 Unauthorized最常见。检查 API Key 是否复制完整、有没有多余空格、是否过期。Base URL 要写https://taotoken.net/api,不要漏掉/api。如果报local proxy failed,说明你本地配了代理但代理没起来,检查环境变量HTTP_PROXY/HTTPS_PROXY,临时unset掉再试。如果报reading choices或返回结构里没有choices字段,多半是模型 ID 写错或该模型不支持当前接口,换成文档里列出的 Model ID。OAuth相关报错通常出现在 Claude Code 这类工具,检查登录态是否过期,重新走一遍授权流程,或者改用 API Key 方式接入。

还有一个隐蔽的坑:matplotlib中文显示方块。确认plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']在import之后、画图之前设置,Linux 上可能没有雅黑,换成SimHei或WenQuanYi Micro Hei。负号显示异常就加plt.rcParams['axes.unicode_minus'] = False。

排查顺序建议:先确认数据源,再确认数据结构,最后确认图表配置。模型接入报错单独排查,不要和数据库报错混在一起看。

6. 把链路固化成学习小结模板:持续记录与下一步

跑通一次不算会,能重复跑通才算。我建议你把上面的流程固化成一个小结模板,每次练新数据集时套用。模板分四块:数据源信息、取数 SQL、DataFrame 操作记录、图表输出。数据源信息记 host、port、db、表名;取数 SQL 记完整语句和返回条数;DataFrame 操作记每一步的输入输出形状,比如df.shape从(31, 5)变成(31, 4);图表输出记文件名和结论。

下一步可以练的方向:把fetch函数改成带参数的,避免 SQL 注入;用pd.read_sql直接读,省掉手动建 DataFrame;把多个图拼成子图;把结果导出 Excel 做汇报。每练一个点,就在模板里加一行记录。

如果你在写 SQL 或调 DataFrame 时想快速验证思路,可以用 TaoToken 的模型对话页面问一版写法,再回本地跑;长期做编码和 Agent 类任务,可以看 Coding Plan;接入配置和 Key 管理分别在接入文档和 API Keys 页面。把这条链路跑顺,你的数据分析学习小结就不再是零散笔记,而是一套能复用的工作流。

返回列表