基于多个变量的聚类观察
Cluster observations based on multiple variables
我正在寻找一个 r 函数来基于两个变量在我的数据集中创建聚类(希望 "cluster" 是我想要做的事情的正确名称)。 variable_1 或 variable_2 具有相同值的每两个观察值应该在同一个集群中。在接下来的简短示例中,我根据 variable_1 和 variable_2.
聚合数据帧 df
df <- data.frame(variable_1=c("a","a","b","b","c","c","d","d","e","e"),variable_2=c("g1","g2","g1","g3","g2","g4","g4","g6","g7","g8"),value=rnorm(10))
df$clusters <- some_function_to_create_clusters(df[,c("variable_1","variable_2")])
结果应如下所示:
df$clusters <- c("clu1","clu1","clu1","clu1","clu1","clu1","clu1","clu1","clu2","clu2")
df
请注意,第一个集群包含 variable_1 等于 "a"、"b"、"c" 或 "d" 的每个人:"a" 和"b" 合并在一起,因为它们共享 "g1"(第 1 行和第 3 行); "a" 和 "c" 合并,因为它们共享 "g2"(第 2 和 5 行); "c" 和 "d" 被合并,因为它们共享 "g4"(第 6 行和第 7 行)。
最后,在最后一个集群中,只有 variable_1=="e" 的观测值,因为它们不与任何人共享 variable_2。
为了阐明我打算做什么,我会更好地解释我的问题集。我将县与附近的旅游景点配对。不同的县被不同的旅游景点(TA)包围,同一个县周围有很多旅游景点。但这"touristic-clusters"个县和助教在全国分布稀疏。请注意,由于县与旅游景点连接的“连锁”效应,一些较远的县可能位于同一集群内。所以我想根据县和旅游景点的id找到那些“集群”。
这看起来很简单,但我不知道如何实现。
非常感谢
所以,我写了一个函数来实现我所需要的。它很丑陋,但它正在工作。如果有人有 better/more 有效的解决方案,我将不胜感激。
find_clusters <- function(original_df){
find_clus <- original_df
cluster_number <- 1
find_clus$cluster <- "cl"
i=1
for(i in 1:nrow(find_clus)){
if(nchar(find_clus$cluster[i])>2) next
aux <- lapply(original_df,function(x){ which(x==x[i])})%>% reshape2::melt()
idx <- aux$value %>%unique() %>%sort()
j = 1
while(j <= length(idx)){
aux <- lapply(original_df,function(x){ which(x==x[idx[j]])})%>% reshape2::melt()
idx <- c( idx, aux$value) %>%unique() %>% sort()
j <- j+1
}
find_clus$cluster[idx] <- paste0("cl",sprintf("%04d", cluster_number))
cluster_number<- cluster_number +1
}
return(find_clus$cluster)
}
因此,要找到聚类,应该这样写:
find_clusters(df[,c(1,2)])
igraph 解决方案
免责声明:我是 igraph 的新手,所以这个问题可能有更好的解决方案。然而这似乎有效。
借助 igraph
包,我们可以使用 graph_from_data_frame()
函数对数据进行聚类,然后使用 components
提取聚类。您可以获得能够可视化集群的额外优势。
library(igraph)
graph <- graph_from_data_frame(df[, 1:2], directed = FALSE)
cmp <- components(graph)$membership
df$cluster <- cmp[df$variable_1]
plot(graph)
将其包装成一个函数
如果你想把它包装成一个函数,像这样的东西是可行的:
find_clusters <- function(x, y) {
edges <- data.frame(from = x, to = y)
graph <- igraph::graph_from_data_frame(edges, directed = FALSE)
cmp <- igraph::components(graph)$membership
return(cmp[x])
}
使用您在上面作为评论发布的附加示例,我们因此有以下工作流程:
library(dplyr)
df <- data.frame(
variable_1 = c("a", "a", "b", "b", "c", "c", "d", "d", "e", "e", "f", "f"),
variable_2 = c( "g1", "g2", "g1", "g3", "g2", "g4", "g4", "g6", "g7", "g8", "g9", "g12"),
value = rnorm(12)
)
df %>%
mutate(cluster = find_clusters(variable_1, variable_2))
# variable_1 variable_2 value cluster
# 1 a g1 -0.03410073 1
# 2 a g2 0.51261548 1
# 3 b g1 0.06470451 1
# 4 b g3 -1.97228101 1
# 5 c g2 -0.39751063 1
# 6 c g4 0.17761619 1
# 7 d g4 -0.13771207 1
# 8 d g6 -0.72183017 1
# 9 e g7 0.09012701 2
# 10 e g8 0.45763593 2
# 11 f g9 -0.83172613 3
# 12 f g12 2.83480352 3
我正在寻找一个 r 函数来基于两个变量在我的数据集中创建聚类(希望 "cluster" 是我想要做的事情的正确名称)。 variable_1 或 variable_2 具有相同值的每两个观察值应该在同一个集群中。在接下来的简短示例中,我根据 variable_1 和 variable_2.
聚合数据帧 dfdf <- data.frame(variable_1=c("a","a","b","b","c","c","d","d","e","e"),variable_2=c("g1","g2","g1","g3","g2","g4","g4","g6","g7","g8"),value=rnorm(10))
df$clusters <- some_function_to_create_clusters(df[,c("variable_1","variable_2")])
结果应如下所示:
df$clusters <- c("clu1","clu1","clu1","clu1","clu1","clu1","clu1","clu1","clu2","clu2")
df
请注意,第一个集群包含 variable_1 等于 "a"、"b"、"c" 或 "d" 的每个人:"a" 和"b" 合并在一起,因为它们共享 "g1"(第 1 行和第 3 行); "a" 和 "c" 合并,因为它们共享 "g2"(第 2 和 5 行); "c" 和 "d" 被合并,因为它们共享 "g4"(第 6 行和第 7 行)。 最后,在最后一个集群中,只有 variable_1=="e" 的观测值,因为它们不与任何人共享 variable_2。
为了阐明我打算做什么,我会更好地解释我的问题集。我将县与附近的旅游景点配对。不同的县被不同的旅游景点(TA)包围,同一个县周围有很多旅游景点。但这"touristic-clusters"个县和助教在全国分布稀疏。请注意,由于县与旅游景点连接的“连锁”效应,一些较远的县可能位于同一集群内。所以我想根据县和旅游景点的id找到那些“集群”。
这看起来很简单,但我不知道如何实现。
非常感谢
所以,我写了一个函数来实现我所需要的。它很丑陋,但它正在工作。如果有人有 better/more 有效的解决方案,我将不胜感激。
find_clusters <- function(original_df){
find_clus <- original_df
cluster_number <- 1
find_clus$cluster <- "cl"
i=1
for(i in 1:nrow(find_clus)){
if(nchar(find_clus$cluster[i])>2) next
aux <- lapply(original_df,function(x){ which(x==x[i])})%>% reshape2::melt()
idx <- aux$value %>%unique() %>%sort()
j = 1
while(j <= length(idx)){
aux <- lapply(original_df,function(x){ which(x==x[idx[j]])})%>% reshape2::melt()
idx <- c( idx, aux$value) %>%unique() %>% sort()
j <- j+1
}
find_clus$cluster[idx] <- paste0("cl",sprintf("%04d", cluster_number))
cluster_number<- cluster_number +1
}
return(find_clus$cluster)
}
因此,要找到聚类,应该这样写:
find_clusters(df[,c(1,2)])
igraph 解决方案
免责声明:我是 igraph 的新手,所以这个问题可能有更好的解决方案。然而这似乎有效。
借助 igraph
包,我们可以使用 graph_from_data_frame()
函数对数据进行聚类,然后使用 components
提取聚类。您可以获得能够可视化集群的额外优势。
library(igraph)
graph <- graph_from_data_frame(df[, 1:2], directed = FALSE)
cmp <- components(graph)$membership
df$cluster <- cmp[df$variable_1]
plot(graph)
将其包装成一个函数
如果你想把它包装成一个函数,像这样的东西是可行的:
find_clusters <- function(x, y) {
edges <- data.frame(from = x, to = y)
graph <- igraph::graph_from_data_frame(edges, directed = FALSE)
cmp <- igraph::components(graph)$membership
return(cmp[x])
}
使用您在上面作为评论发布的附加示例,我们因此有以下工作流程:
library(dplyr)
df <- data.frame(
variable_1 = c("a", "a", "b", "b", "c", "c", "d", "d", "e", "e", "f", "f"),
variable_2 = c( "g1", "g2", "g1", "g3", "g2", "g4", "g4", "g6", "g7", "g8", "g9", "g12"),
value = rnorm(12)
)
df %>%
mutate(cluster = find_clusters(variable_1, variable_2))
# variable_1 variable_2 value cluster
# 1 a g1 -0.03410073 1
# 2 a g2 0.51261548 1
# 3 b g1 0.06470451 1
# 4 b g3 -1.97228101 1
# 5 c g2 -0.39751063 1
# 6 c g4 0.17761619 1
# 7 d g4 -0.13771207 1
# 8 d g6 -0.72183017 1
# 9 e g7 0.09012701 2
# 10 e g8 0.45763593 2
# 11 f g9 -0.83172613 3
# 12 f g12 2.83480352 3