【问题标题】:How to extract only person A's statements in a conversation between two persons A and B如何在两个人 A 和 B 之间的对话中仅提取人 A 的陈述
【发布时间】:2023-03-28 02:12:01
【问题描述】:

我有任意两个人 A 和 B 之间的对话记录。

c1 <- "Person A: blabla...something Person B: blabla something else Person A: OK blabla"
c2 <- "Person A: again blabla Person B: blabla something else Person A: thanks blabla"

数据框如下所示:

df <- data.frame(id = rbind(123, 345), conversation = rbind(c1, c2))

df

    id                                                                     conversation
c1 123 Person A: blabla...something Person B: blabla something else Person A: OK blabla
c2 345   Person A: again blabla Person B: blabla something else Person A: thanks blabla

现在我想只提取人 A 的部分并将其放入数据框中。结果应该是:

   id                     person_A
1 123 blabla...something OK blabla
2 345   again blabla thanks blabla

【问题讨论】:

  • 这些人真的叫“Person_”还是更像“Greg Smith”?有名字和姓氏吗?
  • 实际上,我有一个呼叫中心代理和客户之间的对话记录。没有真实姓名。 A 始终是 AGENT,B 始终是 CUSTOMER。在大多数但不是所有情况下,客户都会开始对话。

标签: regex r dataframe text-mining text-extraction


【解决方案1】:

它可能不适用于您的所有情况。尤其是对话是从Person B开始的。让我知道是否是这种情况。别的试试

df$person_A <- gsub("Person B.*:|Person A:", "", df$conversation)
df <- data.frame(df$id, df$person_A)

【讨论】:

    【解决方案2】:

    使用stringr

    首先我们使用“Person A:”作为分隔符分割字符串

    library(stringr)
    conv.split <- str_split(df$conversation, "Person A: ")
    

    这将为我们提供由 A 发起的所有对话,并附上 B 的(可选)答案

    我们现在删除 B 的答案

    conv.split <- lapply(conv.split, function(x){str_split(x, "Person B:.*")})
    

    最后我们取消列出每个元素并将其折叠成一个字符串

    sapply(conv.split, function(x){x <- unlist(x); paste(x, collapse = "")})
    

    结果:

    [1] "blabla...something OK blabla" "again blabla thanks blabla" 
    

    也适用于 B 开始对话的情况,前提是两人中只有一个在说话,并且也适用于长时间的对话。

    【讨论】:

      【解决方案3】:

      这是我的尝试,我还添加了由人 B 发起的第二次对话和同样由人 B 结束的对话,只是为了涵盖这些情况:

      c1 <- "Person A: blabla...something Person B: blabla something else Person A: OK blabla"
      c2 <- "Person A: again blabla Person B: blabla something else Person A: thanks blabla"
      c3 <- "Person A: again blabla Person B: blabla something else"
      df <- data.frame(id = rbind(123, 345, 567), conversation = rbind(c1, c2, c3))
      
      
      df$PersonA <- gsub("(Person A: |Person B: .+? (?<= Person A: )|Person B: .+?\\Z)", "", df$conversation, perl = TRUE)
      df$PersonA
      

      我正在使用 gsub 做的是删除:

      1. A 人:
      2. B 人的句子后面跟着 A 的句子
      3. 对话结束时B的句子\Z

      我使用了perl = TRUE,因为生命太短了,不能不使用后视镜……嗯……后视镜。

      【讨论】:

        【解决方案4】:

        我非常喜欢以一种让您可以访问所有数据(也包括人 B 的话语)的方式来解决这类问题。我喜欢 tidyrextract 进行这种列拆分。我曾经使用do.call(rbind, strsplit())) 方法,但喜欢extract 方法的干净程度。

        c1 <- "Person A: blabla...something Person B: blabla something else Person A: OK blabla"
        c2 <- "Person A: again blabla Person B: blabla something else Person A: thanks blabla"
        c3 <- "Person A: again blabla Person B: blabla something else"
        df <- data.frame(id = rbind(123, 345, 567), conversation = rbind(c1, c2, c3))
        
        
        if (!require("pacman")) install.packages("pacman")
        pacman::p_load(dplyr, tidyr)
        
        conv <- strsplit(as.character(df[["conversation"]]), "\\s+(?=Person\\s)", perl=TRUE)
        
        df2 <- df[rep(1:nrow(df), sapply(conv, length)), ,drop=FALSE]
        rownames(df2) <- NULL
        df2[["conversation"]] <- unlist(conv)
        
        df2 %>%
            extract(conversation, c("Person", "Conversation"), "([^:]+):\\s+(.+)")
        
        ##    id   Person          Conversation
        ## 1 123 Person A    blabla...something
        ## 2 123 Person B blabla something else
        ## 3 123 Person A             OK blabla
        ## 4 345 Person A          again blabla
        ## 5 345 Person B blabla something else
        ## 6 345 Person A         thanks blabla
        ## 7 567 Person A          again blabla
        ## 8 567 Person B blabla something else
        
        
        df2 %>%
            extract(conversation, c("Person", "Conversation"), "([^:]+):\\s+(.+)") %>%
            filter(Person == "Person A")    
        
        ##    id   Person       Conversation
        ## 1 123 Person A blabla...something
        ## 2 123 Person A          OK blabla
        ## 3 345 Person A       again blabla
        ## 4 345 Person A      thanks blabla
        ## 5 567 Person A       again blabla
        

        或者在你想要的输出中折叠它们:

        df2 %>%
            extract(conversation, c("Person", "Conversation"), "([^:]+):\\s+(.+)") %>%
            filter(Person == "Person A") %>%
            group_by(id) %>%
            select(-Person) %>%
            summarise(Person_A =paste(Conversation, collapse=" "))
        
        ##    id                     Person_A
        ## 1 123 blabla...something OK blabla
        ## 2 345   again blabla thanks blabla
        ## 3 567                 again blabla
        

        编辑:实际上,我怀疑您的数据具有真实姓名,例如“john Smith”与“Person A”。如果是这种情况,此初始正则表达式拆分将捕获使用大写字母后跟冒号的名字和姓氏:

        c1 <- "Greg Smith: blabla...something Sue Williams: blabla something else Greg Smith: OK blabla"
        c2 <- "Greg Smith: again blabla Sue Williams: blabla something else Greg Smith: thanks blabla"
        c3 <- "Greg Smith: again blabla Sue Williams: blabla something else"
        df <- data.frame(id = rbind(123, 345, 567), conversation = rbind(c1, c2, c3))r
        
        
        conv <- strsplit(as.character(df[["conversation"]]), "\\s+(?=([A-Z][a-z]+\\s+[A-Z][a-z]+:))", perl=TRUE)
        
        df2 <- df[rep(1:nrow(df), sapply(conv, length)), ,drop=FALSE]
        rownames(df2) <- NULL
        df2[["conversation"]] <- unlist(conv)
        
        df2 %>%
            extract(conversation, c("Person", "Conversation"), "([^:]+):\\s+(.+)")
        
        ##    id       Person          Conversation
        ## 1 123   Greg Smith    blabla...something
        ## 2 123 Sue Williams blabla something else
        ## 3 123   Greg Smith             OK blabla
        ## 4 345   Greg Smith          again blabla
        ## 5 345 Sue Williams blabla something else
        ## 6 345   Greg Smith         thanks blabla
        ## 7 567   Greg Smith          again blabla
        ## 8 567 Sue Williams blabla something else
        

        【讨论】:

        • 我知道有一种 splitstackshape 方式,但 @AnandaMahto 帮助失败了??
        【解决方案5】:

        使用基础 R 中的data.table andgsub`:

        require(data.table)
        setDT(df)[, Person_A := gsub(".*Person A:[ ]*(.*)[ ]*Person B.*:[ ]*(.*)$", 
                                 "\\1\\2", conversation)][, conversation := NULL]
        df
        #     id                       Person_A
        # 1: 123 blabla...something OK blabla
        # 2: 345   again blabla thanks blabla
        

        【讨论】:

          猜你喜欢
          • 2021-11-29
          • 1970-01-01
          • 2016-05-04
          • 2012-06-26
          • 2014-12-05
          • 2017-12-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多