【问题标题】:Partial Match Between Two Comma Separated Factors in a Data Frame数据框中两个逗号分隔因子之间的部分匹配
【发布时间】:2019-07-26 23:59:57
【问题描述】:

正如标题所暗示的,我的目标是在至少具有两个匹配元素的单独数据框中的两个因素(用逗号分隔的值)之间进行部分匹配

我有两个这样的数据框:

df1

structure(list(ID = c(55, 153, 274, 380, 34, 156), value = c("30002, 10057, 10012, 30045, 10065, 10207, 10013, 20056, 20024, 13026, 10032, 10031", 
"10026, 10051, 10010, 10302", "10004, 10133, 10103", "10009, 10035", 
"10003, 10202, 10319, 10421, 10025, 10033, 10045, 10036, 10049, 10055, 10062, 10069, 10083, 10086, 10089, 10090, 10099, 10100, 10102, 10103, 10112, 10114, 10120, 10125, 10126, 10128, 10144, 10148, 10149, 10150, 10158, 10159, 11330, 10035, 13508, 12003, 10124, 100266, 11302, 15305, 10240, 25024, 23003, 25204, 25343, 23058, 22007, 25278, 25204, 30117, 25346, 22324, 25325, 25133, 25229", 
"11002, 11107, 13340, 10344")), class = c("tbl_df", "tbl", 
"data.frame"), row.names = c(NA, -6L))

df2
```r
structure(list(ID = c(75, 412, 289, 214, 48, 222), value = c("30002, 10041, 10031, 20024, 13026", 
"10026, 10040", "10004, 10133", "10023, 10025, 10314, 10143", 
"10001, 10125, 10126, 10128", 
"10012, 10020, 10344")), class = c("tbl_df", "tbl", "data.frame"
), row.names = c(NA, -6L))

如上图:1)ID不按顺序排列,我按“值”列排序,2)每行的元素数量可以不同,3)“列表”中的元素可以乱序4)原始数据框很大,所以我认为可能有多个匹配,所以我想输出匹配计数

***请注意,这里我按“值”对数据集进行排序,因此看起来它们是逐行匹配的,但实际上并非如此,如果您查看整个数据集,目标实际上是查找匹配项按项目。

如果任何两个列表至少有两个共同元素,我希望结果 df 返回数据框的 ID 和匹配元素:例如 df1 中的 ID 55 和 df1 中的 ID 75- 会返回类似

ID_1 ID_2  Matched_element     Match_count
75   55    30002,20024,13026   3

我尝试使用字符串拆分来使变量值“列表”,但这仍然对我的部分匹配没有帮助。

df1<-str_split(df1$value, ",")
df2<-str_split(df2$value, ",")

Number of Matches Between Two Comma Separated Factors in a Data Frame 这个问题与我要问的问题非常相似,但无法解决我的问题,因为它是逐行匹配的。

【问题讨论】:

  • 请使用dput输出数据帧
  • “如上图:1)ID被完全打乱了” 不知道你说的打乱是什么意思。我也不清楚"..." 在您的第二个数据集中表示什么。你真的有只包含一组点的行吗?我支持前一个评论者的请求,即使用dput 以可重复且明确的方式发布最少的数据。如果不确定,请查看如何提供minimal reproducible example/attempt
  • 嗨@djangodjango,欢迎来到 Stack!正如其他人所提到的,如果您可以 dput(df1) 并将其发布在您的问题中(使用“编辑”选项),这将极大地帮助其他人尝试回答您的问题。尝试重新创建您的第一个,我会从 ID &lt;- c(1,2,3)Value &lt;- c("27003, 47013, 17010, 17129, 75339, 17140", "10325, 10049, 10002, 10009, 10010", "19007, 19000")df1 &lt;- data.frame(ID, Value) 这样的东西开始,但是您的数据框是否有因素等?
  • 如果你有一个大数据框并且只想发布一定数量的行,你也可以使用head()。因此,要提供数据框的前 3 行,您将使用 dput(head(df1,3))
  • @RussThomas 它没有因素。我已经编辑了部分,感谢您的建议!

标签: r matching partial


【解决方案1】:

我没有完全得到您的预期输出。似乎有不一致/错别字

  1. 您说 " 例如,df1 中的 ID 55 和 df1- 中的 ID 75-",但在您的预期输出中 ID_2 = 55ID_1 = 75。不应该是ID_1 = 55(因为它来自df1)和ID_2 = 75(来自df2)吗?
  2. 为什么您给出的示例输出中没有10031 值? value = 10031 位于 df1df2 中,用于 ID_1 = 55ID_2 = 75

抛开不一致,这似乎是一个相当简单的inner_join

library(tidyverse)
inner_join(
    df1 %>% separate_rows(value),
    df2 %>% separate_rows(value),
    by = "value", suffix = c("_1", "_2")) %>%
    group_by(ID_1, ID_2) %>%
    summarise(value = toString(value))
## A tibble: 7 x 3
## Groups:   ID_1 [5]
#   ID_1  ID_2 value
#  <dbl> <dbl> <chr>
#1    34    48 10125, 10126, 10128
#2    34   214 10025
#3    55    75 30002, 20024, 13026, 10031
#4    55   222 10012
#5   153   412 10026
#6   156   222 10344
#7   274   289 10004, 10133

解释:我们使用separate_rows来分隔value列中逗号分隔的条目,然后在value上执行inner_join;然后我们 group_by ID_1ID_2 并使用 toString 通过逗号连接 values 来汇总条目。


要仅选择至少有 3 个匹配 values 的行,您可以这样做

inner_join(
    df1 %>% separate_rows(value),
    df2 %>% separate_rows(value),
    by = "value", suffix = c("_1", "_2")) %>%
    group_by(ID_1, ID_2) %>%
    filter(length(value) > 2) %>%
    summarise(
        matched_element = toString(value),
        match_count = length(value))
## A tibble: 2 x 4
## Groups:   ID_1 [2]
#   ID_1  ID_2 matched_element            match_count
#  <dbl> <dbl> <chr>                            <int>
#1    34    48 10125, 10126, 10128                  3
#2    55    75 30002, 20024, 13026, 10031           4

【讨论】:

  • 非常感谢!我不知道内部连接可以工作:) 是的,你是对的,结果有一些错字,但这个工作就像一个魅力
  • @dangodango 请把答案打出来并作为答案
  • @dangodango 正如 Omar Abd El-Naser 建议的那样,请查看 What should I do when someone answers my question 上的 StackOverflow 帮助中心文章。
【解决方案2】:

我正在使用嵌套的map

library(stringr)
df1 <- structure(list(ID = c(55, 153, 274, 380, 34, 156), value = c("30002, 10057, 10012, 30045, 10065, 10207, 10013, 20056, 20024, 13026, 10032, 10031", 
                                                             "10026, 10051, 10010, 10302", "10004, 10133, 10103", "10009, 10035", 
                                                             "10003, 10202, 10319, 10421, 10025, 10033, 10045, 10036, 10049, 10055, 10062, 10069, 10083, 10086, 10089, 10090, 10099, 10100, 10102, 10103, 10112, 10114, 10120, 10125, 10126, 10128, 10144, 10148, 10149, 10150, 10158, 10159, 11330, 10035, 13508, 12003, 10124, 100266, 11302, 15305, 10240, 25024, 23003, 25204, 25343, 23058, 22007, 25278, 25204, 30117, 25346, 22324, 25325, 25133, 25229", 
                                                             "11002, 11107, 13340, 10344")), class = c("tbl_df", "tbl", 
                                                                                                       "data.frame"), row.names = c(NA, -6L))

df2 <- structure(list(ID1 = c(75, 412, 289, 214, 48, 222), value1 = c("30002, 10041, 10031, 20024, 13026", 
                                                             "10026, 10040", "10004, 10133", "10023, 10025, 10314, 10143", 
                                                             "10001, 10125, 10126, 10128", 
                                                             "10012, 10020, 10344")), class = c("tbl_df", "tbl", "data.frame"
                                                             ), row.names = c(NA, -6L))
#Change value column into a list of numeric values
df1 <-  df1 %>% mutate(x = map(value,function(x) (as.numeric(unlist(str_split(x,","))))))
df2 <-  df2 %>% mutate(x1 = map(value1,function(x) (as.numeric(unlist(str_split(x,","))))))

#Combine dataframes
df <- cbind(df1,df2)

Final_Data <- enframe(map(df$x,~ map(df$x1,~.y[.y %in% .x],.y = .x))) %>% unnest() %>%  
        mutate(ID_1 = rep(df$ID,each = 6),ID_2 = rep(df$ID1,times=6),
               Length = lengths(value) ) %>% filter(Length > 2 )

【讨论】:

  • 谢谢!事实证明,运行 for 循环需要一些时间。但这也有效!非常感谢您花时间写这篇文章
  • @dangodango 如果你仍然感兴趣,我用 map 更改了 for 循环:D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多