查找具有相同值的唯一密钥对

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,我在最后添加了,但您似乎错过了它。还是谢谢

以上是关于查找具有相同值的唯一密钥对的主要内容,如果未能解决你的问题,请参考以下文章

具有相同查找值的自动递增列索引 (VLOOKUP)

循环遍历Series以查找具有相同索引值的

multimap容器怎么查找多个具有相同键值的数据?

SQL 查询以查找具有相同列值的多行

查找具有已定义结束的连续相同值的行组 (SQL Redshift)

查找一列中具有相同值而另一列中具有其他值的行?