最近写了一个新包,实现了极大同质性 (maximum homogeneity) 聚类算法 (W. D. Fisher, 1958)。

源码:https://github.com/nanxstats/oneclust
文档:https://nanx.me/oneclust/

这个方法在 Breiman 的 1984版 CART 书中被应用于决策树的节点分割中并且进行了推广。LightGBM 中也实现了这个方法,用于类别型变量树节点的分割计算。本质是动态规划,保证全局最优解。文档里列出了几个我感兴趣的应用,比如高基数类别型特征的特征工程(摆脱 one-hot encoding)、高维回归系数分组、序列型数据的峰检测和分割。

算是我第一个严肃的 C++ 工程,体验了 zero-based indexing 的厉害 😂 等过几天 CRAN 的维护者们度假回来就打算就提交上去,欢迎试用。

赞赞赞! 顺手试用了一下, 速度很快!

library(oneclust)
library(ids)
set.seed(1)
df_levels <- data.frame(postcode = ids::adjective_animal(500), size = round(runif(500, min = 200, max = 500),0) )
train <- oneclust::sim_postcode_samples(df_levels, n = 100000, threshold = 300, prob = c(0.2, 0.1), seed = 4)
test <- oneclust::sim_postcode_samples(df_levels, n = 100000, threshold = 300, prob = c(0.2, 0.1), seed = 5)

## training
k <- 28
level_hist <- table(train$postcode)
level_new <- oneclust(level_hist, k)$cluster
feature_tr <- level_new[match(train$postcode, names(level_hist))] %>%
  as.character() %>%
  ordered(levels = as.character(1:k))

par(las = 1)
plot(feature_tr, train$label, lty = 0, xlab = "Cluster", ylab = "Label")
abline(h = 0.9, col = cud(1))
abline(h = 0.8, col = cud(2))

## test
feature_te <- level_new[match(test$postcode, names(level_hist))] %>%
  as.character() %>%
  ordered(levels = as.character(1:k))
par(las = 1)
plot(feature_te, test$label, lty = 0, xlab = "Cluster", ylab = "Label")
abline(h = 0.9, col = cud(1))
abline(h = 0.8, col = cud(2))

谢谢!这里还有一个坑是辅助调参。一般的套路是写个 wrapper,输入一个 k 值网格,计算某个准则的值,选择经验最优的 k 即可。欢迎贡献代码。

可以拓展去做很多工作了,赞赞赞