简介:这是一份面向数据分析初学者与进阶学习者的Python数据分析与可视化PDF文档,围绕Pandas、NumPy、SciPy、StatModels等数据分析库,以及Matplotlib、Seaborn、Plotly、Bokeh、Cufflinks等可视化库展开讲解,帮助读者建立从数据清洗、统计建模到图形呈现的完整知识框架。资源包内共1个PDF文件,大小约114KB,内容紧凑,适合作为随查随用的入门参考或课堂补充材料。文档通过读取CSV、计算均值并绘制条形图的示例,直观演示了Pandas与Matplotlib的配合方式,读者可据此掌握数据读取、聚合运算与基础图表输出的基本流程,并进一步理解各库的适用场景与选型思路。目前已有1849人浏览学习,适合希望快速上手Python数据分析与可视化、需要一份轻量级知识梳理的读者参考使用。
1. 从一份 PDF 说起:Python 数据分析与可视化到底该学什么
很多人第一次接触「python数据分析与可视化.pdf」这类资料,是在搜索框里敲下「Python 数据分析入门」「pandas 可视化教程」之后。下载下来一看,几十上百页,目录从 NumPy 讲到 Matplotlib 再到 Seaborn,读完却依然不知道拿到一份真实业务表格该从哪一行代码下手。问题不在资料本身,而在于大部分 PDF 是「知识罗列」,不是「工作流」。这篇笔记想干的事很具体:把 Python 数据分析与可视化拆成一条能跑通的流水线——读数据、清洗、算指标、画图、导出结论,每一步给出可复制的代码和参数含义,让你看完就能对着自己的 Excel 或 CSV 复现一遍。适合两类人:刚学完语法但没做过完整分析的新手,以及用 Excel 做报表做到手酸、想换工具的老手。
2. 环境与数据读取:把第一行代码跑通再谈分析
2.1 为什么选 pandas + matplotlib 这套组合
Python 做数据分析的库很多,polars 快、plotly 交互好,但对着一份 PDF 教程入门的人,我一般还是推荐 pandas + matplotlib 打底。原因很实际:pandas 的 API 覆盖了 90% 的表格操作,社区问答最多,你遇到的报错基本都能搜到;matplotlib 虽然默认样式丑,但它是 Seaborn、pandas.plot 的底层,理解了它,上层封装出问题你才调得动。选型不是比谁先进,而是比谁在你卡住时能救你。
安装不用折腾,一个命令解决。建议单独建虚拟环境,避免和系统里其他项目的包版本打架。
# 创建并激活虚拟环境(Windows 用 venv\Scripts\activate) python -m venv venv source venv/bin/activate # 一次装齐核心四件套 pip install pandas matplotlib seaborn openpyxl这里openpyxl容易被忽略,它是 pandas 读写.xlsx的引擎,不装的话read_excel会直接报缺少依赖。版本上不必追新,pandas 2.x 和 1.x 在本文用到的 API 上行为一致,真正影响你的是数据本身。
2.2 读取 CSV 与 Excel 的三种典型姿势
真实数据来源无非三类:CSV、Excel、数据库导出。先看最常翻车的编码问题。国内很多系统导出的 CSV 是 GBK 编码,直接读会乱码或抛UnicodeDecodeError。
import pandas as pd # 姿势一:标准 UTF-8 CSV df = pd.read_csv("sales.csv") # 姿势二:GBK 编码的 CSV,指定编码和分隔符 df = pd.read_csv("sales_gbk.csv", encoding="gbk", sep=",") # 姿势三:Excel 指定工作表,跳过前两行说明文字 df = pd.read_excel("report.xlsx", sheet_name="明细", skiprows=2)encoding决定字节怎么翻译成字符,猜错了就是乱码;sep在遇到分号或制表符分隔时必须显式指定,否则整行会被当成一列;skiprows对付那种表头上面还有标题和空行的报表特别有用。读进来第一件事不是分析,是df.info()和df.head(),看清楚有多少行、每列什么类型、有没有明显的空值。这一步花三十秒,能省后面半小时的调试。
2.3 数据类型不对,后面全白干
pandas 读进来的列类型经常不是你想要的:金额被识别成字符串、日期被识别成 object、ID 被识别成整数导致前导零丢失。类型错了,排序、求和、时间筛选全都会出问题。
# 查看当前类型 print(df.dtypes) # 金额列去掉货币符号再转 float df["amount"] = df["amount"].str.replace("¥", "", regex=False).astype(float) # 日期列转 datetime,无法解析的置为 NaT df["order_date"] = pd.to_datetime(df["order_date"], errors="coerce") # ID 列强制按字符串处理,保住前导零 df["user_id"] = df["user_id"].astype(str)errors="coerce"是关键参数,它把解析失败的脏数据变成NaT而不是直接抛异常,让你能先跑完再回头查有多少条坏数据。astype转换前一定要确认列里没有混入非数字字符,否则会报ValueError,这时候先用str.replace清洗。
3. 清洗与指标计算:让数据能算、算得对
3.1 缺失值和重复值的处理顺序
清洗有个顺序问题:先去重还是先补缺失?我的经验是先去重。重复行会让缺失率统计虚高,也可能让你误判某列缺失严重。去重之后再决定缺失值怎么处理。
# 按业务主键去重,保留最后一条 df = df.drop_duplicates(subset=["order_id"], keep="last") # 统计每列缺失比例 missing_ratio = df.isnull().mean().sort_values(ascending=False) print(missing_ratio[missing_ratio > 0]) # 数值列用中位数填充,类别列用众数填充 df["amount"] = df["amount"].fillna(df["amount"].median()) df["channel"] = df["channel"].fillna(df["channel"].mode()[0])subset指定按哪些列判断重复,不写就是整行完全一致才算重复。填充策略上,均值容易被极端值带偏,中位数更稳;类别列用众数是因为它代表最常见的取值,比填「未知」对后续分组统计更友好。但要注意:如果某列缺失超过 40%,填充就是在编数据,这时候更该考虑的是这列还要不要用。
3.2 分组聚合:groupby 的三个必调参数
分析的核心动作是「按某个维度看某个指标」,这就是 groupby。很多人只会写df.groupby("city")["amount"].sum(),遇到多指标、多维度就卡住。
result = ( df.groupby(["city", "channel"], as_index=False) .agg( order_cnt=("order_id", "nunique"), total_amount=("amount", "sum"), avg_amount=("amount", "mean"), ) .sort_values("total_amount", ascending=False) )as_index=False让分组列回到普通列,方便后续继续操作和导出;agg里用「新列名=(源列, 函数)」的写法一次算出多个指标,比循环调用干净得多;nunique统计去重后的订单数,避免同一订单多行被重复计数。这三个参数是我每次写 groupby 都会检查的,漏掉任何一个结果都可能不对。
3.3 时间维度上的滚动与同比
业务分析绕不开时间。把日期设为索引后,resample能做任意周期的聚合,rolling能做移动平均,这两个是看趋势的利器。
# 以日期为索引 df = df.set_index("order_date").sort_index() # 按月汇总销售额 monthly = df["amount"].resample("M").sum() # 计算 7 天滚动平均,min_periods 保证前几行也有值 daily = df["amount"].resample("D").sum() daily_ma7 = daily.rolling(window=7, min_periods=1).mean()resample("M")的 M 是月末频率,"D"是自然日;rolling的window=7表示看最近 7 个点,min_periods=1让开头数据不足 7 天时也能算出均值而不是 NaN。同比环比则用pct_change(periods=12)这类写法,periods 填 12 就是和 12 个周期前比。时间序列最容易踩的坑是索引没排序,resample会静默给出错误结果,所以sort_index()别省。
4. 可视化:从能看走向能说明问题
4.1 中文乱码与负号显示:两行配置解决
Matplotlib 默认字体不含中文,图里中文全是方框,负号也会变成方块。这是新手第一个血泪坑,解决只要两行。
import matplotlib.pyplot as plt plt.rcParams["font.sans-serif"] = ["SimHei"] # 指定中文字体 plt.rcParams["axes.unicode_minus"] = False # 正常显示负号SimHei是 Windows 常见黑体,Mac 上换成Arial Unicode MS,Linux 服务器没有中文字体时得先装字体文件。axes.unicode_minus设 False 是因为部分中文字体的负号字形缺失,关掉它用 ASCII 负号替代。这两行建议写进每个绘图脚本的开头,别等出图了才发现。
4.2 一张合格的趋势图要调哪些参数
默认出图能看但不好用,尺寸、标签、网格、图例都得调。下面是一张月度趋势图的标准写法。
fig, ax = plt.subplots(figsize=(10, 5)) ax.plot(monthly.index, monthly.values, marker="o", linewidth=2, label="月销售额") ax.set_title("月度销售额趋势", fontsize=14) ax.set_xlabel("月份") ax.set_ylabel("销售额(元)") ax.grid(True, linestyle="--", alpha=0.4) ax.legend() fig.autofmt_xdate() # 日期标签自动倾斜,防重叠 plt.tight_layout() # 自动调整边距 plt.savefig("trend.png", dpi=150)figsize控制画布英寸尺寸,dpi=150决定导出清晰度,屏幕看 100 够用,进报告建议 150 以上。autofmt_xdate和tight_layout是防标签重叠和边距被裁的两个后悔药,几乎每张图都该加。marker="o"让数据点可见,适合点不多的月度图;点太多时去掉 marker 只留线。
4.3 分类对比与分布:柱状图和箱线图怎么选
看不同类别的数值对比用柱状图,看一组数据的分布和离群点用箱线图。选错了图,结论会被误导。
# 各城市销售额对比(横向柱状图,类别多时更好读) city_sales = df.groupby("city")["amount"].sum().sort_values() fig, ax = plt.subplots(figsize=(8, 6)) ax.barh(city_sales.index, city_sales.values, color="#4C72B0") ax.set_xlabel("销售额(元)") ax.set_title("各城市销售额对比") # 各渠道金额分布(箱线图看中位数和离群) fig2, ax2 = plt.subplots(figsize=(8, 5)) df.boxplot(column="amount", by="channel", ax=ax2) ax2.set_title("各渠道金额分布") ax2.set_xlabel("渠道") ax2.set_ylabel("金额(元)")类别超过七八个时,纵向柱状图的标签会挤成一团,barh横向排列更清爽。箱线图的箱子是中位数和四分位,须是范围,单独的点是离群值——如果某渠道离群点特别多,说明这渠道的金额波动大,均值参考价值低,该看中位数。df.boxplot的by参数按列分组,注意它会自动加一个总标题,用plt.suptitle("")可以清掉。
5. 避坑与排查:那些让分析结果悄悄出错的细节
5.1 链式赋值警告不是小事
现象:控制台反复出现SettingWithCopyWarning,代码照跑但结果偶尔不对。原因:对切片出来的 DataFrame 直接赋值,pandas 不确定你改的是原表还是副本。解决:用.copy()显式复制,或改用.loc一步到位。
# 错误写法:先切片再赋值 sub = df[df["amount"] > 100] sub["level"] = "high" # 触发警告 # 正确写法一:显式复制 sub = df[df["amount"] > 100].copy() sub["level"] = "high" # 正确写法二:用 loc 一次完成 df.loc[df["amount"] > 100, "level"] = "high"这个警告被很多人当噪音忽略,但它背后是真实的数据一致性问题,尤其在链式操作多的时候,你以为改了原表其实没有。
5.2 分组后索引对不上导致画图错位
现象:groupby 之后直接画图,x 轴标签和柱子对不上。原因:groupby 默认把分组列变成索引,画图时索引顺序和你想的不一致。解决:加as_index=False或画图前reset_index()。
# 容易错位 city = df.groupby("city")["amount"].sum() plt.bar(city.index, city.values) # 顺序依赖索引,可能乱 # 稳妥写法 city = df.groupby("city", as_index=False)["amount"].sum().sort_values("amount") plt.bar(city["city"], city["amount"])显式排序再画,顺序就完全可控,别指望默认顺序。
5.3 浮点数求和出现 0.30000000000000004
现象:金额求和结果带一长串小数尾巴。原因:计算机二进制无法精确表示某些十进制小数,这是浮点数的固有特性,不是 pandas 的 bug。解决:展示时用round控制位数,涉及金额精确计算时用Decimal或按分存储整数。
total = df["amount"].sum() print(round(total, 2)) # 展示层处理 # 精确计算场景:转成整数分 df["amount_cent"] = (df["amount"] * 100).round().astype(int)对账类场景千万别用浮点数直接比相等,0.1 + 0.2 == 0.3是 False,这个坑踩一次记一辈子。
5.4 大数据量下 read_csv 慢到怀疑人生
现象:几百万行的 CSV 读一次要几分钟。原因:默认逐行解析且全列推断类型。解决:指定dtype跳过类型推断,用usecols只读需要的列,必要时分块读。
# 只读需要的列并指定类型,速度能快数倍 df = pd.read_csv( "big.csv", usecols=["order_id", "amount", "order_date"], dtype={"order_id": str, "amount": float}, parse_dates=["order_date"], ) # 超大文件分块处理 for chunk in pd.read_csv("big.csv", chunksize=100000): process(chunk) # 每块单独处理再汇总usecols减少内存和解析量,dtype省掉推断开销,chunksize让内存放不下的文件也能处理。这三招组合起来,读文件的时间通常能砍掉一半以上。
6. 把分析固化成可复用的脚本习惯
做到这一步,你已经能对着单份数据跑完整流程了。但真实工作里,同样的分析每周都要重跑,数据一换就得手动改路径、改列名,这才是最耗人的地方。我的做法是把整条流水线封成一个函数,参数只留输入路径和输出目录,其余全部内部化。
def analyze_sales(input_path, output_dir): """读取销售数据,输出汇总表和趋势图""" df = pd.read_csv(input_path, encoding="utf-8") df["order_date"] = pd.to_datetime(df["order_date"], errors="coerce") df = df.dropna(subset=["order_date"]).drop_duplicates(subset=["order_id"]) summary = ( df.groupby("city", as_index=False) .agg(total=("amount", "sum"), orders=("order_id", "nunique")) .sort_values("total", ascending=False) ) summary.to_csv(f"{output_dir}/summary.csv", index=False, encoding="utf-8-sig") monthly = df.set_index("order_date")["amount"].resample("M").sum() fig, ax = plt.subplots(figsize=(10, 5)) ax.plot(monthly.index, monthly.values, marker="o") ax.set_title("月度销售额趋势") fig.autofmt_xdate() plt.tight_layout() plt.savefig(f"{output_dir}/trend.png", dpi=150) return summary这里有个细节值得说:导出 CSV 时用encoding="utf-8-sig",它带 BOM 头,Excel 打开中文不会乱码,这是给下游同事看的文件必须加的,自己再读回来时用普通 utf-8 即可。函数返回 summary 而不是直接打印,是为了让调用方能继续拿结果做二次处理。
再进一步,把参数抽到配置文件里,脚本和数据彻底解耦。我一般用一个简单的 YAML 或 JSON 存路径和列名映射,换项目只改配置不改代码。验证脚本是否可靠,有个笨办法但很有效:拿一份你手工用 Excel 算过结果的小数据跑一遍,逐列对数字,对上了再上大数据。这个习惯帮我拦下过好几次列名映射写错、日期解析偏移的隐蔽 bug。
最后说个我自己的教训。早期我图省事,清洗、计算、画图全写在一个几百行的脚本里,改一个指标要翻半天。后来强制自己按「读入—清洗—计算—输出」四段拆函数,每段只干一件事,出问题时能快速定位是哪一段的锅。数据分析的代码不是一次性的,它会被反复修改和复用,写的时候多花十分钟结构化,后面能省几小时。希望帮到你。
本文还有配套的精品资源,点击获取