【问题标题】:Expand data.table so one row per pattern match of each ID展开 data.table 以便每个 ID 的每个模式匹配一​​行
【发布时间】:2019-04-16 10:13:14
【问题描述】:

我在 data.table 中有很多文本数据。我有几个我感兴趣的文本模式。我设法对表格进行了子集化,以便它显示与至少两个模式匹配的文本(相关问题here)。

我现在希望每个匹配有一行,并带有一个标识匹配的附加列 - 因此,除了该列之外,存在多个匹配的行将是重复的。

感觉这应该不会太难,但我很挣扎!我模糊的想法可能是计算模式匹配的数量,然后多次复制行......但是我不完全确定如何为每个不同的模式获取标签......(也不确定那是无论如何都非常有效)。

感谢您的帮助!

示例数据

library(data.table)
library(stringr)
text_table <- data.table(ID = (1:5), 
                         text = c("lucy, sarah and paul live on the same street",
                                  "lucy has only moved here recently",
                                  "lucy and sarah are cousins",
                                  "john is also new to the area",
                                  "paul and john have known each other a long time"))


text_patterns <- as.character(c("lucy", "sarah", "paul|john"))

# Filtering the table to just the IDs with at least two pattern matches
text_table_multiples <- text_table[, Reduce(`+`, lapply(text_patterns, 
                                    function(x) str_detect(text, x))) >1]

理想输出

required_table <- data.table(ID = c(1, 1, 1, 2, 3, 3, 4, 5),
                             text = c("lucy, sarah and paul live on the same street",
                                      "lucy, sarah and paul live on the same street",
                                      "lucy, sarah and paul live on the same street",
                                      "lucy has only moved here recently",
                                      "lucy and sarah are cousins",
                                      "lucy and sarah are cousins",
                                      "john is also new to the area",
                                      "paul and john have known each other a long time"), 
                             person = c("lucy", "sarah", "paul or john", "lucy", "lucy", "sarah", "paul or john", "paul or john"))

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    一种方法是为每个指标创建一个变量并融化:

    library(stringi)
    text_table[, lucy := stri_detect_regex(text, 'lucy')][ ,
      sarah := stri_detect_regex(text, 'sarah')
    ][ ,`paul or john` := stri_detect_regex(text, 'paul|john')
    ]
    
    melt(text_table, id.vars = c("ID", "text"))[value == T][, -"value"]
    ##    ID                                            text     variable
    ## 1:  1    lucy, sarah and paul live on the same street         lucy
    ## 2:  2               lucy has only moved here recently         lucy
    ## 3:  3                      lucy and sarah are cousins         lucy
    ## 4:  1    lucy, sarah and paul live on the same street        sarah
    ## 5:  3                      lucy and sarah are cousins        sarah
    ## 6:  1    lucy, sarah and paul live on the same street paul or john
    ## 7:  4                    john is also new to the area paul or john
    ## 8:  5 paul and john have known each other a long time paul or john
    

    执行相同程序的一种简洁方法是:

    library(tidyverse)
    text_table %>%
      mutate(lucy = stri_detect_regex(text, 'lucy')) %>%
      mutate(sarah = stri_detect_regex(text, 'sarah')) %>%
      mutate(`paul or john` = stri_detect_regex(text, 'paul|john')) %>%
      gather(value = value, key = person,  - c(ID, text)) %>%
      filter(value) %>%
      select(-value)
    

    【讨论】:

    • 看起来这行得通,谢谢!我认为这大致是我想象中的,但我正在努力完成各个步骤。谢谢!
    【解决方案2】:

    免责声明:这不是惯用的data.table 解决方案

    我将构建一个如下所示的辅助函数,它采用单行和一个输入并返回一个带有 Nrows 的新 dt:

    library(data.table)
    library(tidyverse)
    
    new_rows <- function(dtRow, patterns = text_patterns){
    
        res <- map(text_patterns, function(word) {
    
            textField <- grep(x = dtRow[1, text], pattern = word, value = TRUE) %>% 
                ifelse(is.character(.), ., NA)
    
            personField   <- str_extract(string = dtRow[1, text], pattern = word) %>% 
                ifelse(  . == "paul" | . == "john", "paul or john", .)
    
            idField <- ifelse(is.na(textField), NA, dtRow[1, ID])
    
            data.table(ID = idField, text = textField, person = personField) 
    
            }) %>% 
            rbindlist()
    
        res[!is.na(text), ]
    }
    

    我会执行它:

    split(text_table, f = text_table[['ID']]) %>% 
        map_df(function(r) new_rows(dtRow = r))
    

    答案是:

       ID                                            text       person
    1:  1    lucy, sarah and paul live on the same street         lucy
    2:  1    lucy, sarah and paul live on the same street        sarah
    3:  1    lucy, sarah and paul live on the same street paul or john
    4:  2               lucy has only moved here recently         lucy
    5:  3                      lucy and sarah are cousins         lucy
    6:  3                      lucy and sarah are cousins        sarah
    7:  4                    john is also new to the area paul or john
    8:  5 paul and john have known each other a long time paul or john
    

    看起来像您的required_table(包括重复的 ID)

       ID                                            text       person
    1:  1    lucy, sarah and paul live on the same street         lucy
    2:  1    lucy, sarah and paul live on the same street        sarah
    3:  1    lucy, sarah and paul live on the same street paul or john
    4:  2               lucy has only moved here recently         lucy
    5:  3                      lucy and sarah are cousins         lucy
    6:  3                      lucy and sarah are cousins        sarah
    7:  4                    john is also new to the area paul or john
    8:  5 paul and john have known each other a long time paul or john
    

    【讨论】:

    • 我还没有机会看这个,但我很快就会和上面的答案进行比较:)
    猜你喜欢
    • 1970-01-01
    • 2021-04-09
    • 1970-01-01
    • 1970-01-01
    • 2021-07-21
    • 2022-01-11
    • 2012-05-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多