Smile — Java 生态中最被低估的机器学习框架
·
在 Java 生态中做机器学习,选择其实不多。Weka 太老、DL4J 太重、Mahout 要搭 Hadoop。但有一个库,功能全、性能好、API 优雅,却很少有人提起——Smile (Statistical Machine Intelligence & Learning Engine)。
这个月初(2026年5月4日),Smile 发布了 6.1.0 版本,代码库已经非常成熟。本文从实战出发,带你快速掌握 Smile 的核心功能。
一、Smile 是什么?
Smile 是一个纯 Java/Scala 的机器学习框架,涵盖:
- 分类:决策树、随机森林、SVM、KNN、神经网络
- 回归:线性回归、LASSO、弹性网络、回归树
- 聚类:K-Means、DBSCAN、GMM、谱聚类
- 关联规则:FPGrowth
- 时间序列:ARIMA、季节分解
- NLP:词袋模型、TF-IDF
- 数据可视化:SWING 图表、Scala Plot
- 数值计算:矩阵运算、插值、优化
不依赖 Hadoop/Spark,一个 jar 包搞定所有。
二、5 分钟上手
2.1 Maven 依赖
<dependency>
<groupId>com.github.haifengl</groupId>
<artifactId>smile-core</artifactId>
<version>6.1.0</version>
</dependency>
注意:Smile 6.1.0 需要 Java 25+。如果你还在 Java 11/17/21,可以用 Smile 3.x 版本:
<version>3.1.1</version>
2.2 第一个示例:分类鸢尾花
Smile 内置了经典数据集,三行代码跑一个分类器:
import smile.classification.RandomForest;
import smile.data.DataFrame;
import smile.data.type.DataTypes;
import smile.io.Read;
// 读取内置鸢尾花数据
DataFrame iris = Read.arff("https://haifengl.github.io/smile/datasets/weka/iris.arff");
double[][] x = iris.select(0, 1, 2, 3).toArray();
int[] y = iris.column("class").toIntArray();
// 训练随机森林
RandomForest model = RandomForest.fit(x, y);
// 预测
int prediction = model.predict(new double[]{5.1, 3.5, 1.4, 0.2});
System.out.println("预测结果: " + prediction);
三、实用场景示例
3.1 分类:预测客户流失
// 准备数据: [使用时长, 月消费, 投诉次数] → 是否流失(0/1)
double[][] X = {
{12, 89, 0}, {3, 150, 2}, {24, 45, 0},
{6, 200, 5}, {18, 120, 1}, {1, 300, 8}
};
int[] Y = {0, 1, 0, 1, 0, 1};
// 训练决策树
var tree = smile.classification.DecisionTree.fit(X, Y);
// 预测新客户
double[] newCustomer = {8, 130, 1};
int result = tree.predict(newCustomer);
System.out.println(result == 0 ? "✅ 留存" : "❌ 可能流失");
3.2 聚类:客户分群
import smile.clustering.KMeans;
// 20 个客户的消费数据: [年龄, 年消费额(万)]
double[][] customers = {
{25, 3.2}, {30, 4.1}, {22, 2.8}, {35, 5.5}, {28, 3.9},
{45, 7.2}, {50, 8.1}, {42, 6.5}, {55, 9.0}, {48, 7.8},
{60, 2.1}, {65, 1.5}, {58, 2.8}, {70, 1.2}, {62, 1.9},
{32, 5.8}, {38, 6.2}, {29, 4.5}, {41, 5.9}, {33, 4.8}
};
// 聚成 3 类
KMeans kmeans = KMeans.fit(customers, 3);
// 查看每个客户的所属类别
for (int i = 0; i < customers.length; i++) {
System.out.printf("客户%2d (年龄%2d, 消费%.1f万) → 第%d类\n",
i + 1, (int) customers[i][0], customers[i][1], kmeans.predict(customers[i]));
}
运行后你会发现:年轻高消费一类、中年高消费一类、老年低消费一类——完全符合业务直觉。
3.3 关联规则:购物篮分析
import smile.association.FPGrowth;
import smile.association.FPTree;
// 商品编码: 0=牛奶, 1=面包, 2=啤酒, 3=尿布, 4=鸡蛋
int[][] transactions = {
{0, 1, 2, 3}, {0, 1, 4}, {2, 3}, {0, 1, 2, 3, 4},
{1, 2}, {0, 3}, {0, 1, 3}, {0, 2, 3}
};
String[] products = {"牛奶", "面包", "啤酒", "尿布", "鸡蛋"};
// 最小支持度 3 次
FPTree tree = new FPTree(3, transactions);
var itemsets = FPGrowth.apply(tree).toList();
System.out.println("=== 频繁项集 ===");
for (var is : itemsets) {
if (is.items().length < 2) continue;
String s = java.util.Arrays.stream(is.items())
.mapToObj(i -> products[i])
.collect(java.util.stream.Collectors.joining(" + "));
System.out.println(s + " (出现" + is.support() + "次)");
}
3.4 时间序列预测:销售额预测
Smile 的 smile.timeseries 包内置了 ARIMA 模型:
import smile.timeseries.ARIMA;
// 过去 12 个月销售额(万元)
double[] sales = {120, 135, 128, 142, 138, 150,
145, 158, 152, 165, 160, 172};
// 自动拟合 ARIMA 模型(自动选择最优参数)
ARIMA model = ARIMA.autoFit(sales);
// 预测未来 3 个月
double[] forecast = model.forecast(3);
System.out.println("=== 预测结果 ===");
for (int i = 0; i < forecast.length; i++) {
System.out.printf("第%d个月: %.1f万元\n", i + 1, forecast[i]);
}
3.5 NLP:文本 TF-IDF 特征提取
import smile.nlp.BagOfWords;
import smile.nlp.TermFrequency;
import smile.nlp.TextTerms;
// 三份文档
String[] docs = {
"苹果发布了新的iPhone",
"苹果公司的财报超出预期",
"华为发布了新的Mate手机"
};
// 构建词袋
BagOfWords bow = new BagOfWords();
for (String doc : docs) {
bow.add(doc);
}
TextTerms terms = bow.terms();
// 输出每个文档的 TF-IDF 向量
for (int i = 0; i < docs.length; i++) {
double[] tfidf = TermFrequency.tfidf(bow, docs[i]);
System.out.println("文档" + (i + 1) + " 特征维度: " + tfidf.length);
}
四、性能对比
Smile 的性能在 Java ML 库中属于第一梯队。官方数据:
| 算法 | Smile | Weka | scikit-learn |
|---|---|---|---|
| 随机森林 (1万样本×100特征) | 0.8s | 4.2s | 1.1s |
| K-Means (10万点×50维) | 1.2s | 5.8s | 1.5s |
| SVM (1万样本) | 2.1s | 12s | 3.0s |
(数据来自 Smile 官方基准测试)
五、常见问题
Q1: Smile 6.x 和 3.x 有什么不同?
| 对比项 | 3.x | 6.x |
|---|---|---|
| 最低 Java 版本 | Java 8 | Java 25 |
| 包结构 | smile.* |
smile.*(基本一致) |
| 新功能 | — | 大数据集成、ONNX 支持 |
| FPGrowth API | 包级私有 | 包级私有(仍未公开) |
建议:Java 21+ 用 3.1.1,Java 25+ 用 6.1.0。
Q2: 数据量很大怎么办?
Smile 本身是单机内存计算。大数据场景可以:
- 用 Smile 做特征工程 → 导出到 Spark/XGBoost 训练
- 使用 Smile 的流式 API(
smile.stream)处理增量数据 - 结合 Apache Arrow 列式内存格式处理高维数据
六、总结
Smile 是 Java 生态中功能最全面的原生 ML 库,没有之一。如果你在 Java 项目中需要做机器学习,完全没有必要去调 Python 服务——一个 Smile 全搞定。
完整项目示例
本文所有示例代码都在以下目录:
src/main/java/org/ml/learn/MarketBasketExample.java
运行方式:
mvn exec:java -Dexec.mainClass="org.ml.learn.MarketBasketExample"
更多推荐

所有评论(0)