На самом деле ваша проблема - это разделение графиков для компонентов. В вашем случае вершинами графов являются лица. На основе информации об атрибутах, например, адреса электронной почты и номера телефона, вы можете установить отношения, которые являются ребрами.
Похоже, что простые методы, такие как paste
или duplicate
или group_by
, не эффективны, поскольку у вас могут быть довольно сложные пути. Как вы объяснили, однако, что человек D и человек E имеют совершенно разные контакты, фактически они связаны через человека C , следовательно, должны иметь одинаковый идентификатор.
Или, другими словами, кто-то зарегистрировался на сайте с электронной почтой A и мобильным телефоном B . Затем он потерял телефон. И зарегистрирован с мобильного C . Затем он забыл свой пароль и зарегистрировался по электронной почте D . В конце концов у нас есть человек с электронной почтой D и мобильным C . По неизвестной причине он зарегистрирован под разными именами.
У вас могут быть еще более сложные пути отношений.
Приведенный ниже алгоритм использует igraph
для создания неориентированного графа на основе матрицы смежности, созданной в соответствии с вашими условиями. После того как он идентифицирует несвязанные компоненты, извлеките его и объедините с начальным data.frame
. Поскольку в вашем примере было недостаточно данных, использовалась симуляция.
Имитация ввода:
name tel email
1 AAA 222 F@xy.com
2 BBB 555 C@xy.com
3 CCC 333 E@xy.com
4 DDD 666 D@xy.com
5 EEE 666 A@xy.com
6 FFF 111 F@xy.com
7 GGG 444 B@xy.com
8 HHH 666 A@xy.com
9 III 444 B@xy.com
10 JJJ 333 F@xy.com
Код
library(igraph)
set.seed(123)
n <- 10
# simulation
df <- data.frame(
name = sapply(1:n, function(i) paste0(rep(LETTERS[i], 3), collapse = "")),
tel = sample(1:6, n, replace = TRUE) * 111,
email = paste0(sample(LETTERS[1:6], n, replace = TRUE), "@xy.com")
)
# adjacency matrix preparation
df1 <- expand.grid(df$name, df$name)
names(df1) <- c("name_x", "name_y")
df1 <- merge(df1, df, by.x = "name_x", by.y = "name")
df1 <- merge(df1, df, by.x = "name_y", by.y = "name")
df1$con <- ifelse(with(df1, tel.x == tel.y | email.x == email.y), 1, 0)
stats::reshape(df1[, c(1, 2, 7)], idvar = "name_x", timevar = "con", direction = "wide")
#v.names = , timevar = "numbers", direction = "wide")
library(igraph)
library(reshape2)
m <- dcast(df1[, c(1, 2, 7)], name_y ~ name_x)
rownames(m) <- m[, 1]
m[, 1] <- NULL
m <- as.matrix(m)
diag(m) <- 0
# graph creation
g1 <- graph_from_adjacency_matrix(m, mode = "undirected")
gcmps <- groups(components(g1))
# groups extraction
ids <- unlist(mapply(function(x, y) paste0(x, "_", y), seq_along(gcmps), gcmps))
df_ids <- as.data.frame(t(sapply(ids, function(x) unlist(strsplit(x, "_")))))
names(df_ids) <- c("id", "name")
# data merging
result <- merge(df, df_ids)
result
Выход:
name tel email
1 AAA 222 F@xy.com
2 BBB 555 C@xy.com
3 CCC 333 E@xy.com
4 DDD 666 D@xy.com
5 EEE 666 A@xy.com
6 FFF 111 F@xy.com
7 GGG 444 B@xy.com
8 HHH 666 A@xy.com
9 III 444 B@xy.com
10 JJJ 333 F@xy.com
График отношений (были взяты только первые буквы имени)