我有一个带有
id
列、G
分组变量和 300 个数字变量的 tibble。
我想要一种方法,将原始数据聚类到每行与每个分组变量中的另一行在集群中匹配/配对的程度。 这应该是一个 1kNN。奇数组中的备用原料可以从簇中排除。
因此,如果一组中有 4 个原始数据,则将有 2 个 2 个集群。如果有 5 个原始数据,则有 2 个 2 个集群和一个备用原始数据。
我想我喜欢马哈拉诺比斯距离进行聚类,但我对替代提案持开放态度。
我认为簇内马哈拉诺比斯的诊断变量也有帮助。
从技术上讲,
MatchIt
做了非常相似的事情,对原始数据过度强加了二元分类。我不想要这样的分类。
示例:
tibble(
id = c(1:8),
g = rep(c("A","B"),4),
v1 = rnorm(8),
v2 = rnorm(8),
v3 = rnorm(8)
) -> obs
看起来多么理想啊
obs %>%
mutate(cluster = sample(c(1:2),replace = F) %>% rep(2),
.by = g) %>%
mutate(pair = str_c(g,cluster)) %>%
arrange(pair)
nbpMatching
包实现了它。
你也可以自己做一个贪婪的版本,首先寻找距离最近的对。首先,创建一个 NxN 距离矩阵,然后找到最接近的一对并记录下来。否认这些单位在未来配对的能力。重复直到所有单位都匹配。这是一些使用马哈拉诺比斯距离执行此操作的代码。
obs$pair <- NA
#Create distance matrix of variables
d <- MatchIt::mahalanobis_dist(~v1 + v2 + v3, data = obs)
#Deny matches that belong to different clusters
d[!outer(obs$g, obs$g, "==")] <- Inf
#Deny self-matching
diag(d) <- Inf
k <- 1
repeat {
min_pos <- arrayInd(which.min(d), dim(d))
if (!is.finite(d[min_pos])) break
obs$pair[drop(min_pos)] <- k
d[drop(min_pos),] <- Inf
d[,drop(min_pos)] <- Inf
k <- k + 1
}
您还可以通过将问题分成更小的部分(即在组内而不是拒绝跨组匹配)来更有效地做到这一点。