查看全课大纲(第 33 / 101 节)
  1. 1.数据分析基本概念
  2. 2.学习数据分析的一般路线
  3. 3.数据分析的流程
  4. 4.数据类型
  5. 5.环境部署(1)
  6. 6.环境部署(2)
  7. 7.课程介绍
  8. 8.TXT文件操作
  9. 9.JSON文件操作
  10. 10.CSV文件操作
  11. 11.Excel文件操作
  12. 12.数据库及SQL常用语法
  13. 13.数据库基本操作
  14. 14.数据库多表连接
  15. 15.实战:欧洲职业足球数据库分析
  16. 16.爬虫简介
  17. 17.URL管理模块
  18. 18.网页下载模块
  19. 19.网页解析模块(1)
  20. 20.网页解析模块(2)
  21. 21.Scrapy简介
  22. 22.Scrapy使用步骤(1)
  23. 23.Scrapy使用步骤(2)
  24. 24.Scrapy使用步骤(3)
  25. 25.Scrapy使用步骤(4)
  26. 26.实战:获取国内城市空气质量指数数据
  27. 27.NumPy和SciPy介绍
  28. 28.多维数组
  29. 29.多维数组操作
  30. 30.NumPy的常用方法
  31. 31.向量化介绍
  32. 32.向量化及通用函数
  33. 33.实战:2016美国大选分析
  34. 34.数据结构-Series
  35. 35.数据结构-DataFrame
  36. 36.数据结构-Index
  37. 37.Series的索引操作
  38. 38.DataFrame的索引操作
  39. 39.索引操作总结
  40. 40.运算与对齐
  41. 41.函数应用操作(1) -- map
  42. 42.函数应用操作 (2) -- apply applymap
  43. 43.文件读写操作
  44. 44.排序操作
  45. 45.数据清洗--处理缺失数据
  46. 46.数据清洗--处理重复数据
  47. 47.数据清洗--替换数据
  48. 48.常用统计方法(1) -- describe quantile
  49. 49.常用统计方法(2) -- sum mean median count
  50. 50.常用统计方法(3) -- max min idxmax idxmin
  51. 51.常用统计方法(4) -- mad var std cumsum
  52. 52.实战:全球食品数据分析
  53. 53.层级索引
  54. 54.分组与聚合介绍
  55. 55.分组操作(1) -- GroupBy对象及常用聚合操作
  56. 56.分组操作(2) -- 自定义分组及聚合操作
  57. 57.透视表介绍
  58. 58.透视表操作
  59. 59.数据规整(1) -- 数据合并concat
  60. 60.数据规整(2) -- 数据连接merge
  61. 61.数据重构(3) -- 数据重构stack unstack
  62. 62.实战:互联网电影资料库分析
  63. 63.探索性数据分析EDA介绍
  64. 64.EDA的目的
  65. 65.EDA常用工具
  66. 66.Matplotlib绘图基本介绍
  67. 67.Matplotlib画布
  68. 68.散点图和柱状图的绘制
  69. 69.直方图的绘制
  70. 70.矩阵绘图
  71. 71.子图的使用
  72. 72.Matplotlib颜色、标记、线型
  73. 73.Matplotlib坐标刻度、标签、图例、标题
  74. 74.Seaborn介绍
  75. 75.数据集分布可视化(1) -- 单变量分布、双变量分布
  76. 76.数据集分布可视化(2) -- 变量关系可视化
  77. 77.类别数据可视化 -- 类别散布图、类别内数据分布、类别内统计图
  78. 78.交互式数据可视化工具Bokeh介绍
  79. 79.Bokeh绘制散点图、柱状图、盒子图、弦图
  80. 80.Bokeh绘制常用图形元素
  81. 81.3D绘图 -- mplot3d
  82. 82.3D曲线可视化
  83. 83.3D散点图可视化
  84. 84.3D柱状图可视化
  85. 85.Pandas绘图
  86. 86.实战:Lending Club借贷数据探索性分析及可视化
  87. 87.机器学习介绍及应用场景
  88. 88.机器学习建模介绍 (1) -- 分类
  89. 89.机器学习建模介绍 (2) -- 回归
  90. 90.机器学习建模介绍 (3) -- 聚类
  91. 91.机器学习分类
  92. 92.机器学习工具scikit-learn
  93. 93.使用scikit-learn的流程
  94. 94.数据集准备及划分
  95. 95.模型选择
  96. 96.数据预处理及特征工程
  97. 97.过拟合与欠拟合
  98. 98.模型调参介绍
  99. 99.模型调参方法
  100. 100.模型测试及评价
  101. 101.实战:通过移动设备行为数据预测性别和年龄

实战:2016美国大选分析

约 17 分钟

📺 正在播放小象学院官方高清录播(支持倍速与清晰度调节)

NumPy 综合实战:月度调研数据的清洗与分组统计

小象实战讲义 · Python数据分析实战

本节是第 4 章 NumPy 的压轴综合实战。原始课程使用「2016 美国大选民调数据集」,因年代较久、数据获取不便,本节改用一套中性的「门店月度满意度调研」模拟数据,演示完全相同的一套 NumPy 分析技术:字符串日期规整、布尔掩码分组、向量化聚合与脏数据容错。学完本节,你将能把前面分散的 NumPy 知识点串成一条完整的「原始数据 → 规整 → 按月统计」流水线。

💡 核心导读

  • 实战目标:把逐日记录的调研数据,按「年-月」分组汇总,得到每个月的平均评分与领先方。
  • 三步处理流程:字符串日期规整 → 布尔掩码分组 → 向量化聚合。
  • 工程细节:如何跳过无法转换的脏数据,以及样本量不等时如何做加权平均。
  • 全部代码锁定现代环境实跑(NumPy 2.5),输出可直接核对。

1. 数据形态与日期规整

原始调研记录里,日期往往以字符串保存(如 2015-11-15),而我们要统计的是「每个月」的趋势,所以第一步是把日期规整为统一的 yyyy-mm 字符串。这里用标准库 datetime.date.fromisoformat 解析 ISO 格式日期,再用 np.array 把结果存成数组,方便后续向量化处理。

import numpy as np
import datetime

# 逐日调研原始记录(硬编码小样例,输出确定)
enddate = ["2015-11-15", "2015-12-10", "2016-01-22", "2016-02-08", "2016-02-19"]
channel_a = np.array([48.5, 47.0, 46.5, 49.0, 50.0])
channel_b = np.array([42.0, 43.0, 43.5, 41.5, 40.0])

# 1. 日期规整:逐条解析后统一格式化为 yyyy-mm
dates = [datetime.date.fromisoformat(d) for d in enddate]
months = np.array([f"{d.year}-{d.month:02d}" for d in dates])

print("规整后的年月:", np.unique(months))
print("样本总数:", len(months))
规整后的年月: ['2015-11' '2015-12' '2016-01' '2016-02']
样本总数: 5

2. 布尔掩码分组与向量化聚合

分组统计的核心思路是「遍历去重后的月份,用布尔掩码取出该月的行,再做向量化聚合」。months == m 会生成一个布尔数组,用它去索引 channel_a / channel_b,就得到了当前月份的子集——这比写循环逐行判断更简洁、也更快。

import numpy as np

months = np.array(["2015-11", "2015-12", "2016-01", "2016-02", "2016-02"])
channel_a = np.array([48.5, 47.0, 46.5, 49.0, 50.0])
channel_b = np.array([42.0, 43.0, 43.5, 41.5, 40.0])

print("月份       | 渠道A均值 | 渠道B均值 | 领先方")
print("-" * 46)
for m in np.unique(months):
    mask = (months == m)                 # 布尔掩码:仅保留当前月份的行
    a_mean = np.mean(channel_a[mask])    # 向量化聚合,无需逐行循环
    b_mean = np.mean(channel_b[mask])
    lead = a_mean - b_mean
    who = "渠道A" if lead > 0 else "渠道B"
    print(f"{m:<10} | {a_mean:<9.2f} | {b_mean:<9.2f} | {who} +{abs(lead):.2f}")
月份       | 渠道A均值 | 渠道B均值 | 领先方
----------------------------------------------
2015-11    | 48.50     | 42.00     | 渠道A +6.50
2015-12    | 47.00     | 43.00     | 渠道A +4.00
2016-01    | 46.50     | 43.50     | 渠道A +3.00
2016-02    | 49.50     | 40.75     | 渠道A +8.75

3. 脏数据容错与加权平均

真实数据里常混入无法解析的脏值(如空串、N/A)。稳妥的做法是用 try / except 兜住转换异常:能整体转换就整体转换,遇到脏值就过滤后再转换,而不是让程序直接崩溃。

另外,各次调研的样本量往往不同(有的调查 1000 人、有的 3000 人),此时直接 np.mean 会忽略权重。NumPy 提供了 np.average(值, weights=样本量) 来计算以样本量加权的平均:

import numpy as np

# 原始字符串评分(含一条无法转换的脏数据)
raw = np.array(["48.5", "47.0", "N/A", "49.0"])
try:
    scores = raw.astype(float)
except ValueError:
    clean = np.array([v for v in raw if v != "N/A"])
    scores = clean.astype(float)
    print("跳过脏数据后的有效评分:", scores)
    print("有效样本均值:", round(float(scores.mean()), 2))

# 加权平均:样本量不同时,用 np.average 以样本量加权
vals = np.array([48.5, 47.0, 49.0])
sizes = np.array([1000.0, 1500.0, 800.0])
print("按样本量加权的平均满意度:", round(float(np.average(vals, weights=sizes)), 3))
跳过脏数据后的有效评分: [48.5 47.  49. ]
有效样本均值: 48.17
按样本量加权的平均满意度: 47.939

4. 从「逐行循环」到「向量化」的思路转变

初学者最容易写出的版本是「for 循环 + if 判断」逐行累加:代码长、可读性差,数据一大还会明显变慢。本节示范的做法是把「筛选」与「聚合」都交给 NumPy:

  • 筛选:用布尔掩码(months == m)一次性取得整段子集,而不是逐行判断;
  • 聚合:用 np.mean / np.sum / np.average 直接作用在整段数组上,底层由 C 实现,远快于 Python 循环;
  • 去重分组:用 np.unique 得到全部不重复的分组键,天然省去手写去重逻辑;
  • 容错:用 try / except 兜住脏数据转换异常,保证流程不中断。

这套「先掩码、后聚合」的套路,正是从 NumPy 过渡到 pandas 分组聚合的思维基础——下一章你会看到 pandas 把它封装成了更简洁的 df.groupby(...).mean(),但底层逻辑与本节完全一致。掌握今天的写法,你就能在没有 pandas 的场景下(例如纯科学计算脚本里)照样完成分组统计。


📝 动手练一练

  1. 业务分析题:各次调研的样本量差异很大(500 人到 3000 人不等)时,如何计算以样本量为权重的加权平均支持率?

    👉 点击查看参考答案

    参考答案: 使用 np.average(a, weights=sample_sizes)。它按权重归一化求和:

    加权均值=∑(pi×wi)∑wi\text{加权均值} = \frac{\sum (p_i \times w_i)}{\sum w_i}

    其中 pip_i 为第 ii 次调研的支持率,wiw_i 为该次调研的样本量。

  2. 编程练习题:给定两个渠道的 5 期评分数组 a = np.array([48.5, 47.0, 51.0, 49.3, 46.5]) 与 b = np.array([47.0, 46.5, 48.0, 48.9, 47.8]),请用布尔掩码统计渠道 A 领先的期数。

    👉 点击查看参考答案

    参考答案:

    import numpy as np
    
    a = np.array([48.5, 47.0, 51.0, 49.3, 46.5])
    b = np.array([47.0, 46.5, 48.0, 48.9, 47.8])
    print("渠道 A 领先的期数:", int(np.sum(a > b)))
渠道 A 领先的期数: 4

a > b 生成布尔数组,np.sum 会把 True 当作 1 求和,结果为 4。


本章小结

  • 完整走通了「原始字符串数据 → 日期规整 → 布尔掩码分组 → 向量化聚合」的 NumPy 分析流水线;
  • 掌握了用 np.unique 去重分组、用布尔掩码切片、用 np.mean / np.average 做普通与加权聚合;
  • 建立了脏数据容错的工程意识(try / except + 过滤后再转换)。

📋 行动清单

  • 复习第 4 章全部内容,熟练 NumPy 数组创建、索引、布尔掩码与聚合 API。
  • 把本节示例数据的月份数扩大到 12 个月,观察分组统计结果的扩展方式。
  • 做好准备,进入第 5 章《数据分析工具 Pandas 基础》。

—— 小象教研组

配套资料 · 直接下载

课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。

  • 本节课件:实战:2016美国大选分析
    PDF · 212KB
    下载
  • 全套课件打包(第1-5章)
    ZIP · 12.8MB
    下载
  • 全套课件打包(第6-8章)
    ZIP · 15MB
    下载
  • 实战数据集:AppleStore 应用商城分析
    ZIP · 329KB
    下载
  • 实战数据集:女性服装电商分析
    ZIP · 2.8MB
    下载
  • Python 数据分析环境搭建指南
    PDF · 2MB
    下载
  • Scrapy 安装教程
    PDF · 12.7MB
    下载
  • 附加实战项目:AppleStore 应用商城数据分析
    ZIP · 0.3MB · ipynb + CSV 数据
    下载
  • 附加实战项目:银行电话营销数据分析
    ZIP · 0.4MB · ipynb + CSV 数据
    下载
  • 附加实战项目:女性服装电商评论数据分析
    ZIP · 2.7MB · ipynb + CSV 数据
    下载
  • 附加实战项目:美国化学学会杂志数据分析
    ZIP · 34.2MB · ipynb + SQLite 数据库
    下载