查找具有相同值的唯一密钥对
Posted
技术标签:
【中文标题】查找具有相同值的唯一密钥对【英文标题】:Finding the unique key pair with same values 【发布时间】:2022-01-16 02:58:21 【问题描述】:我正在尝试为以下问题找到解决方案但无法做到,请帮助我解决逻辑,我也可以指导,我可以编码但无法提出必要的逻辑。
问题来了:
我有一个这样的数据集:
df <- data.frame(x = c(1, 1, 2, 2, 2, 2, 3, 4, 5, 1, 2,3, 4, 7, 8, 9, 4, 10, 10, 11, 12), y = c('a', 'b', 'c','d', 'e', 'f', 'a', 'a', 'e', 'k', 'l', 'm', 'n', 'b', 'e', 'e', 'b', 'x', 'y', 'z', 'z' ))
预期的输出应该是:
col1 col2
1 1,4,3, 7
2 2,5,8,9
10 10
11 11, 12
逻辑:将 x 列视为键,将 y 视为值,现在如果一个键与不同的 value(y) 值重复,那么所有这些键都是连接的,作为 例子:1 与 a 和 b、k 相连,但 a 也与 4,3、7 相连。现在 2 与 cde 和 f 相连,所以 2、5、8、9 也与 z 与 11 相连和 12. 为了建立最终连接,我们可以将它们连接在一起,并取出第一个键作为键,其余为逗号分隔值。
我的尝试
library(data.table)
setDT(df)
setnames(df, c('x', 'y'),c('los', 'mob'))
dfLos <- df[, .(mobconcat = paste0(mob, collapse = ',')), .(los)]
dfMob <- df[, .(losconcat = paste0(los, collapse = ',')), .(mob)]
df <- merge(df, dfMob, by='mob', all.x=TRUE)
dim(df)
df <- merge(df, dfLos, by='los', all.x=TRUE)
(showing only few rows)
los mob losconcat mobconcat
1: 1 a 1,3,4 a,b,k
2: 1 b 1,7,4 a,b,k
3: 1 k 1 a,b,k
4: 2 c 2 c,d,e,f,l
5: 2 d 2 c,d,e,f,l
6: 2 e 2,5,8,9 c,d,e,f,l
7: 2 f 2 c,d,e,f,l
8: 2 l 2 c,d,e,f,l
现在我被困在这里,可能是这种方法是浪费,我在这里尝试使用逗号分隔所有键的方法来获取所有键,但无法理解如何进一步。
非常感谢。欢迎您提出任何其他方法或扩展我的方法,我对任何人都很好。
【问题讨论】:
【参考方案1】:这是一个应该做你想做的功能。这可能不是最快或最优雅的答案...
key_connect <- function(data, key, val)
val_by_key <- split(data[[val]], data[[key]])
key_by_val <- split(data[[key]], data[[val]])
f <- function(val) unique(unlist(key_by_val[val]))
res <- data.frame(
## Unique keys
key = as.integer(names(val_by_key)),
## Connected keys with duplicates
key_con = I(lapply(val_by_key, f))
)
ul <- unlist(res[["key_con"]], use.names = FALSE)
ends <- cumsum(lengths(res[["key_con"]]))
ends <- c(0L, ends[-length(ends)])
g <- function(i, end) i[match(i, ul[seq_len(end)], 0L) == 0L]
## Connected keys without duplicates
res[["key_con"]] <- Map(g, i = res[["key_con"]], end = ends)
res <- res[lengths(res[["key_con"]]) > 0L, ]
row.names(res) <- NULL
res
key_connect(df, key = "x", val = "y")
key key_con
1 1 1, 3, 4, 7
2 2 2, 5, 8, 9
3 10 10
4 11 11, 12
【讨论】:
所以这似乎可行,但等待更多答案,否则我会接受这个作为答案。我有 300 万条记录,在上面运行需要时间。不过还是非常感谢mcuh 我已将代码放入一个函数中,以便更轻松地针对其他答案进行测试。当data
有300 万行时,两个split
调用会非常慢。希望有人能够根据data.table
给你一个更有效的答案。【参考方案2】:
另一个不是很漂亮的解决方案,但它是基于 data.table 的。也许有帮助。
library(data.table)
library(stringr)
df = data.table(x = c(1, 1, 2, 2, 2, 2, 3, 4, 5, 1, 2,3, 4, 7, 8, 9, 4, 10, 10, 11, 12), y = c('a', 'b', 'c','d', 'e', 'f', 'a', 'a', 'e', 'k', 'l', 'm', 'n', 'b', 'e', 'e', 'b', 'x', 'y', 'z', 'z' ))
df2 = df[, .(conc = str_c(x, collapse = ", ")), by=y]
df3 = merge(df, df2, by="y", all=TRUE)
df4 = unique(df3[, .(conc = unlist(strsplit(str_c(conc, collapse = ", "), ", "))), by=x][order(conc)], by="conc")
df_final = df4[, .(conc = str_c(conc, collapse = ", ")), by=x][order(x)]
输出:
x conc
1: 1 1, 3, 4, 7
2: 2 2, 5, 8, 9
3: 10 10
4: 11 11, 12
【讨论】:
谢谢,代码中的最后一行似乎在开头缺少 df4,我在最后添加了,但您似乎错过了它。还是谢谢以上是关于查找具有相同值的唯一密钥对的主要内容,如果未能解决你的问题,请参考以下文章