【问题标题】:Comparing string matches between groups by category按类别比较组之间的字符串匹配
【发布时间】:2017-01-12 08:43:53
【问题描述】:

我有一个以下形式的大型数据集,其中包含从语料库中提取的文本字符串:

Category      Group         Text_Strings 
1             A             c(string1, string2, string3)
1             A             c(string1, string3)
1             B             character(0)
1             B             c(string1)
1             B             c(string3)

2             A             character(0)
2             A             character(0)
2             B             c(string1, string3)

3             A             c(string1, string2, string3)
3             A             character(0)
3             A             c(string1)
3             B             character(0)
3             B             c(string1, string2, string3)

...其中 A 和 B 在类别 1 中有共同的 string1 和 string3;第 2 类中没有共同点;并且所有三个都属于第 3 类。

我想计算每个类的 A 组和 B 组之间匹配的字符串数。字符串匹配可以是任何顺序;例如针对 c(string2, string1) 评估的 c(string1, string2) 应计为两个匹配项。此外,匹配只能在每个类别中的唯一字符串之间进行;例如c(string1, string2), c(string1) vs. c(string2, string1) 应该仍然只有两个匹配项。例如:

Category      Group         Text_Strings 
4             A             c(string1, string2, string3)
4             A             c(string1)
4             B             c(string1)
4             B             c(string1)

... 即使 string1 重复,也只会产生一个匹配项。

我的最终输出应该是这样的:

Category     Matches
1            2
2            0 
3            3
4            1

我做了很多研究,但我无法自己找出答案。我突然想到,我可能能够按组对数据框进行子集化,以某种方式在类别上聚合/连接字符串,然后使用 lapply() 和 intersect()... 类似

for(i in 1:nrow(data)[1]) {
    data$matches[i] <- sum(intersect(subset(data, Group=="A")$Text_Strings[i], 
                                     subset(data, Group=="B")$Text_Strings[i])) 
}

当然,这缺少步骤并且不起作用,但是我走在正确的轨道上吗?感谢您的帮助!

更新:jeremycg 的解决方案非常有用,但我的数据非常混乱,以至于它无法接受 parse()。感谢另一个线程中的另一个用户,我通过基于逗号分隔符拆分行而不是尝试直接取消嵌套来解决这个问题:

library(tidyverse)
x %>% 
     separate_rows(Text_Strings, sep = ",") %>% # split on commas
      dmap_at("Text_Strings", ~ gsub("^c\\(\"|\")$|\"", "", .x))

这产生了相同的未嵌套数据,但更加更干净。

【问题讨论】:

    标签: r


    【解决方案1】:

    您可以使用 dplyr 和 tidyr:

    library(dplyr)
    library(tidyr)
    x %>% unnest() %>% #spread out the nested columns
          distinct() %>% #remove dupes
          group_by(Category) %>% #by Category
          summarise(out = sum(Text_Strings[Group  == 'A'] %in% Text_Strings[Group  == 'B'])) #sum the overlap
    

    给予:

    Source: local data frame [3 x 2]
    
      Category   out
         (int) (int)
    1        1     2
    2        2     0
    3        3     3
    

    您的实际数据非常混乱 - 您应该尝试修复将其输出为“长格式”的任何内容。这是一个笨拙的修复:

    x$listcites =  gsub('\\\\n', '',x$listcites) #remove newlines
    x$listcites = gsub("\"", "'", x$listcites, fixed = TRUE) #remove quotes to singles
    x$listcites[grepl('^[^c]',x$listcites)] = paste("c('", x$listcites[grepl('^[^c]',x$listcites)],"')", sep = '') #fix single lines to same format
    x$listcites = sapply(x$listcites, function(x) eval(parse(text = x))) #eval to vecs in dataframe
    x %>% unnest() %>%
          distinct %>%
          group_by(case_num) %>%
          summarise(out = sum(listcites[type  == 'claimant'] %in% listcites[type  == 'court'])) #sum the overlap
    

    【讨论】:

    • 您能解释一下为什么如果不将字符串重新定义为 a、b、c 就无法运行代码吗?它卡在 sapply() 部分并吐出一个错误:“找不到对象'string1'。”这是相关的,因为在我的数据集中有太多字符串无法以这种方式定义。
    • 这是您发布数据的方式的产物 - 我无法访问您定义为 string1/2/3 的内容,它要么将它们括在引号中,要么将它们定义为用于解析的东西。您大概将它们定义为实际数据框中的字符串,因此可以跳过数据输入步骤。
    • 我在问题中包含了一些具有代表性的 ASCII 数据。 sapply() 产生:“解析错误(text = toString(x)) : :1:8: unexpected symbol 1: israel v.”我意识到这是因为只有一个元素的字符串周围的引号没有被转义。现在我只需要弄清楚如何解决这个问题......
    • 感谢您不遗余力地回答我的问题。在示例数据上工作得很好。不幸的是,它没有考虑到我的实际数据......调用 parse() 时一个接一个的“意外符号”错误。使用 OCR 数据的乐趣。每次我修复另一个时,它们都很难调试,因为错误不会报告行号。您能否建议另一种在没有 parse() 的情况下读取嵌套字符串的方法,这似乎过于挑剔?也许 expand.grid() 会这样做?
    猜你喜欢
    • 2012-10-12
    • 1970-01-01
    • 2020-05-05
    • 2022-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多