数据分析与机器学习:Gonum 生态与「异常值统治一切」的教训¶
这一章回答「Go 能做数据分析吗」。 答案是:能,但生态比 Python 年轻。 Go 的甜点位不在实验室里调整数学模型,而在把模型/数据流水线(数据一步步 流过去被处理的一条龙)部署成跑得快、并发强的服务。主线例子会亲手让你看到 数据分析最重要的一课: 一个异常值(10 亿的薪水)就能把均值推到 5 亿——统计量不看分布(数据摊开 长什么样)就是自欺。
1. 两个定义与 Go 的位置¶
书里先划清两个词1:
- 机器学习:让计算机从数据里学规律、做预测,不靠人逐条写规则;
- 数据分析:检查、清洗、转换、建模数据,提取有用的信息支撑决策。
Go 的角色书里说得很直白:不是取代 Python 当 ML 研究平台, 而是用 Gorgonia、GoLearn、Gonum 这些库,把数据处理、模型部署 做成「快、可扩展」的应用——吃 Go 速度和并发红利2。
机器学习为什么重要,书里列了七个应用方向(数据挖掘、预测分析、推荐系统、 欺诈检测、医疗、NLP(让机器理解人类语言)、科研)3——这张表读一遍建立直觉即可,不用记。
2. 数据处理三件套:清洗、转换、归一化¶
数据处理的三个基本动作,书里各给了可跑的代码骨架4:
清洗(cleaning):去重、去空行、统一格式。原书的 cleanData 函数
是教科书式写法:用一个 map 当「见过的集合」去重
(键是行的字符串化,值用空结构体——第 13 章的惯用法),
每行转小写、去首尾空格。
转换(transformation):换格式、换结构。书里用 struct + encoding/xml
演示了 XML 序列化(Marshal)与反序列化(Unmarshal):
结构体标签(反引号里的 xml:"name")告诉编码器字段和标签的对应关系——
这是第 10 章埋过伏笔的「结构体标签」,这里第一次实战5。
归一化(normalization):把不同量纲的特征(数据里的每一列,比如年龄、薪水) 压到同一尺度, 防止「数值大的字段统治分析」。书里选了最直观的 min-max 缩放:
x_scaled = (x - min) / (max - min)
数据:[100, 550, 280, 4000, 50]
→ [0.0127, 0.1266, 0.0582, 1, 0] ← 最小值变 0,最大值变 1
图说:5 个数原来跨 4 个数量级的感觉(50 到 4000),缩放后全部落在 0~16。
3. 主线例子:一份脏 CSV 的七步体检¶
本章主线,照原书的 EDA(探索性数据分析)完整流程。
数据集 dataset.csv 两列(Age、Salary),10 行——其中藏着两个雷:
年龄 0(缺失)和薪水 10,000,000,000(异常)7。
第 ① 步:解析。 encoding/csv 读全量;FieldsPerRecord = -1
容忍列数不齐;每个值 TrimSpace 后用 strconv.ParseFloat 转 float64,
转不了的静默跳过(if err == nil)。
第 ② 步:准备。 所有数值摊平进一个 []float64——
注意这会把 Age 和 Salary 两列混进同一根切片,是教学简化。
第 ③ 步:描述性统计(gonum/stat 包):
sort.Float64s(data) // Quantile 要求先排序
mean := stat.Mean(data, nil) // 均值
median := stat.Quantile(0.5, stat.Empirical, data, nil) // 中位数
variance := stat.Variance(data, nil) // 方差
stdDev := stat.StdDev(data, nil) // 标准差:数据离均值平均有多远
第 ④ 步:可视化。 gonum/plot 画直方图,16 个分桶,存成 histogram.png8。
第 ⑤ 步:相关分析(书里给的是 2×2 示例矩阵——矩阵就是排成矩形的一批数—— 示意 mat 包的用法)。
第 ⑥ 步:数缺失值。 规则:值 == 0 视为缺失 → 数到 1 个(那个 Age 0)。
第 ⑦ 步:找异常值。 规则:超过 3 倍标准差 → 抓到 [1e+10]。
现在看输出,这是全章最有冲击力的一组数字9:
Mean: 500028467.05 ← 五亿!
Median: 50.00 ← 五十
Variance: 4999970035809240064.00
Standard Deviation: 2236061277.29 ← 二十二亿
Number of missing values: 1
Outliers: [1e+10]
图说:10 行数据、1 个异常值,均值被拖到 5 亿,而中位数纹丝不动(50)。 这就是数据分析的第一课,用 10 行数据讲完了:
均值怕异常值,中位数不怕。 拿到任何数据,先问「这里面有没有怪物」, 再决定用哪个统计量描述它。标准差在这里也失效了(22 亿,比数据本身还大)。
书里这一步的处理很克制——只检测、不修复,把「删还是修」留给了读者判断。
4. 机器学习三范式:一张地图¶
书里按「有没有标签、怎么学」把机器学习(让计算机从数据里自己学规律的总称)切成三类10:
| 范式 | 学什么 | 书内点名的算法(名字认脸即可) |
|---|---|---|
| 监督学习 | 有标签(每个训练样本都带正确答案):学「输入→输出」的映射(对应关系) | 分类(预测属于哪一类,如垃圾邮件判断):决策树(一路 if-else 问到答案)、KNN(看离它最近的邻居是谁);回归(预测一个数值,如房价):线性回归(用一条直线拟合数据) |
| 无监督学习 | 没标签:自己从数据里找结构 | 聚类(自动把相似的归成一堆):K-means;降维(把太多特征压缩成少数几个,方便画图和分析):PCA |
| 强化学习 | 试错的智能体:做什么动作能拿到最多奖励 | Q-Learning(把「状态+动作」的好坏记在一张表里,边试边学) |
强化学习的五要素书里单独给了定义:智能体(agent)、环境(environment)、 状态(state)、策略(policy)、动作(action)、奖励(reward)—— 「智能体观察环境状态、按策略选动作、拿奖励反馈」这个循环就是全部11。
5. Go 的机器学习库清单¶
书里列了九个,按用途归拢(2025 年口径)12:
| 库 | 干什么 |
|---|---|
| GoLearn | 最像 Scikit-learn 的全家桶:分类/回归/聚类/交叉验证 |
| Gonum | NumPy/MATLAB 的精神续作:线性代数、统计、优化、矩阵——本章 EDA 和回归的主力 |
| Gorgonia | 神经网络(模仿脑细胞连接的数学模型)/深度学习(很多层堆起来的神经网络)框架,Gonum 家族 |
| GoML | 在线学习、反应式学习模型 |
| GoBrain / Gomind | 神经网络 |
| Hector | 经典算法合集(主攻二分类,即只分「是/否」两类的问题) |
| libsvm-go | LIBSVM 的 Go 移植(SVM 训练与预测) |
| go-cluster | 聚类:DBSCAN、OPTICS、k-means++ |
| GoBot | 机器人/IoT 物理设备接口(ML 实验的四肢) |
判断(我们的,不是书里的): 这张清单里最值得投入的是 Gonum—— 它不是「机器学习库」,是科学计算的地基;而 Go 机器学习生态的共识用法是: 训练在 Python,部署/服务化在 Go(ONNX Runtime 的 Go 绑定、 TensorFlow Serving 的客户端)。GoLearn/Gorgonia 能玩,但别指望它们 追平 PyTorch 一天的更新量。 如果错,会错在: 如果 Gorgonia 或后续项目把「图计算 + 自动微分」 做成了生产级,Go 也可能长出像样的训练生态——但就本书成书时可见的 社区活跃度看,这个可能性不大。
6. 时间序列:用线性回归预测股价(玩具版)¶
本章压轴例子:30 天的股价(y 从 143.0 缓涨到 144.8),用 Gonum 的 线性回归 + 优化器(自动搜索最优参数的工具)预测第 31 天13:
第 1 步:造设计矩阵 X —— 每行 [1, x],那个 1 是偏置项(bias)
第 2 步:目标向量 Y —— 30 个真实价格
第 3 步:目标函数 = Σ(X·θ - Y)² ← 预测与实际的差的平方和
第 4 步:optimize.Minimize 用默认的 BFGS 算法找让目标函数最小的 θ
第 5 步:预测 = θ₀ + θ₁ × 31
图说:「训练」在这里就是一句话:找一组参数,让「预测错的平方和」最小。 线性回归没有魔法,优化器替你试参数而已。
书里附的免责声明同样原样接住:这是非常基础的例子,真实股价预测 需要特征工程、严肃模型、风险管理与评估14——这句诚实, 是整章数据科学内容的合格线。
7. 边界与局限¶
- EDA 的例子把两列数据混进一根切片(Age 和 Salary 一起算均值)—— 教学上省事,实际上每列应该独立统计;书中的「均值 5 亿」因此更是 「列不该混」的反面教材;
- 缺失值处理只数了个数,没讲填充(均值/中位数/模型插补);
- 相关分析是硬编码(把数据直接写死在代码里,不从外部读)的 2×2 示例矩阵, 不是真从数据算的相关系数;
- 异常值检测的「3 倍标准差」在标准差本身被污染时会失效(本章数据就是), 更稳的是 IQR 或稳健统计量——书里列了名字没给代码15。
8. 可带走的¶
- Go 的数据科学定位:部署与流水线,不是实验室调模型;
- 数据处理三件套:清洗(去重去空)、转换(序列化/换格式)、归一化(min-max);
- 结构体标签(反引号)是 Go 数据交换(XML/JSON)的通用机制;
- EDA 六步:解析 → 准备 → 统计 → 画图 → 相关 → 缺失/异常;
- 均值怕异常值、中位数不怕——10 行数据、1 个怪物,均值 5 亿 vs 中位数 50;
- 标准差也会被异常值绑架;稳健场景先看分布再选统计量;
- 机器学习三范式:监督(有标签)、无监督(找结构)、强化(试拿奖励);
- Go 库先记 Gonum(地基)和 GoLearn(全家桶);Gorgonia 管神经网络;
- 线性回归 = 找参数让「错的平方和」最小;optimize.Minimize 一行代劳;
- 股价预测例子是玩具——书里自己写了免责声明,真实场景要特征工程与评估。
9. 原文地图¶
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 机器学习与数据分析定义 | Data Analysis and Machine Learning | text/29-fm-learning-go-programming.txt:55(搜「without explicit programming」) · text/29-fm-learning-go-programming.txt:61(搜「Gorgonia, GoLearn, and Gonum」) |
| 数据结构与文件读写 | Data Analysis and Machine Learning | text/29-fm-learning-go-programming.txt:121(搜「third-party libraries」) · text/29-fm-learning-go-programming.txt:220(搜「ioutil package is obsolete」) · text/29-fm-learning-go-programming.txt:232(搜「bufio package」) |
| 数据清洗示例 | Data Analysis and Machine Learning | text/29-fm-learning-go-programming.txt:370(搜「cleanData」) · text/29-fm-learning-go-programming.txt:418(搜「TrimSpace(strings.ToLower」) |
| 数据转换(XML 与结构体标签) | Data Analysis and Machine Learning | text/29-fm-learning-go-programming.txt:472(搜「xml.Name」) · text/29-fm-learning-go-programming.txt:499(搜「MarshalIndent」) |
| min-max 归一化 | Data Analysis and Machine Learning | text/29-fm-learning-go-programming.txt:577(搜「MinMaxScaler」) · text/29-fm-learning-go-programming.txt:663(搜「0.012658227848101266」) · text/29-fm-learning-go-programming.txt:672(搜「x scaled」) |
| EDA 工具清单 | Data Analysis and Machine Learning | text/29-fm-learning-go-programming.txt:684(搜「gonum/gonum/stat」) · text/29-fm-learning-go-programming.txt:687(搜「gonum/plot」) · text/29-fm-learning-go-programming.txt:693(搜「Interquartile Range」) |
| 脏数据集与七步流水线 | Data Analysis and Machine Learning | text/29-fm-learning-go-programming.txt:835(搜「10000000000」) · text/29-fm-learning-go-programming.txt:931(搜「FieldsPerRecord = -1」) · text/29-fm-learning-go-programming.txt:991(搜「stat.Quantile」) |
| 均值 vs 中位数的输出 | Data Analysis and Machine Learning | text/29-fm-learning-go-programming.txt:1126(搜「500028467.05」) · text/29-fm-learning-go-programming.txt:1129(搜「Median: 50.00」) · text/29-fm-learning-go-programming.txt:1150(搜「Outliers: [1e+10]」) |
| 三范式与算法清单 | Data Analysis and Machine Learning | text/29-fm-learning-go-programming.txt:1162(搜「labeled data」) · text/29-fm-learning-go-programming.txt:1186(搜「unlabeled data」) · text/29-fm-learning-go-programming.txt:1198(搜「maximize a reward」) |
| 库清单 | Data Analysis and Machine Learning | text/29-fm-learning-go-programming.txt:1228(搜「Similar to Python's Scikit-learn」) · text/29-fm-learning-go-programming.txt:1234(搜「inspired by NumPy」) · text/29-fm-learning-go-programming.txt:1237(搜「neural networks」) |
| 线性回归预测股价 | Data Analysis and Machine Learning | text/29-fm-learning-go-programming.txt:1297(搜「design matrix」) · text/29-fm-learning-go-programming.txt:1330(搜「objective」) · text/29-fm-learning-go-programming.txt:1372(搜「Minimize」) · text/29-fm-learning-go-programming.txt:1411(搜「145.27」) |
| 免责声明 | Data Analysis and Machine Learning | text/29-fm-learning-go-programming.txt:1433(搜「may not yield reliable results」) |
-
出处:「Data Analysis and Machine Learning」第 55–58 段(
text/29-fm-learning-go-programming.txt:55,搜「without explicit programming」)。 ↩ -
出处:「Data Analysis and Machine Learning」第 61 段(
text/29-fm-learning-go-programming.txt:61,搜「Gorgonia, GoLearn, and Gonum」)。 ↩ -
出处:「Data Analysis and Machine Learning」第 64–91 段(七个应用方向)。 ↩
-
出处:「Data Analysis and Machine Learning」第 94–121 段(数据结构回顾)、第 364–445 段(清洗示例)。 ↩
-
出处:「Data Analysis and Machine Learning」第 448–553 段(
text/29-fm-learning-go-programming.txt:472,搜「xml.Name」;text/29-fm-learning-go-programming.txt:499,搜「MarshalIndent」)。 ↩ -
出处:「Data Analysis and Machine Learning」第 556–672 段(
text/29-fm-learning-go-programming.txt:663,搜「0.012658227848101266」;text/29-fm-learning-go-programming.txt:672,搜「x scaled」)。 ↩ -
出处:「Data Analysis and Machine Learning」第 675–931 段(数据集见第 713–856 段的表;解析见第 913–976 段)。 ↩
-
出处:「Data Analysis and Machine Learning」第 979–1052 段(
text/29-fm-learning-go-programming.txt:991,搜「stat.Quantile」;text/29-fm-learning-go-programming.txt:1018,搜「NewHist」)。 ↩ -
出处:「Data Analysis and Machine Learning」第 1123–1150 段(
text/29-fm-learning-go-programming.txt:1126,搜「500028467.05」;text/29-fm-learning-go-programming.txt:1129,搜「Median: 50.00」;text/29-fm-learning-go-programming.txt:1150,搜「Outliers: [1e+10]」)。 ↩ -
出处:「Data Analysis and Machine Learning」第 1156–1219 段(三范式的定义与算法清单)。 ↩
-
出处:「Data Analysis and Machine Learning」第 1198–1216 段(强化学习五要素的定义)。 ↩
-
出处:「Data Analysis and Machine Learning」第 1222–1252 段(九个库的分工)。 ↩
-
出处:「Data Analysis and Machine Learning」第 1255–1411 段(
text/29-fm-learning-go-programming.txt:1297,搜「design matrix」;text/29-fm-learning-go-programming.txt:1306,搜「Bias term」;text/29-fm-learning-go-programming.txt:1372,搜「Minimize」;text/29-fm-learning-go-programming.txt:1411,搜「145.27」)。 ↩ -
出处:「Data Analysis and Machine Learning」第 1433 段(
text/29-fm-learning-go-programming.txt:1433,搜「may not yield reliable results」)。 ↩ -
出处:「Data Analysis and Machine Learning」第 693 段(
text/29-fm-learning-go-programming.txt:693,搜「Interquartile Range」)。 ↩