Как извлечь только высказывания человека а в разговоре между двумя людьми а и Б
У меня есть запись разговоров между двумя произвольными лицами а и В.
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
Теперь я хотел бы извлечь только часть человека А и поместить ее в фрейм данных. Результат должен быть:
id person_A
1 123 blabla...something OK blabla
2 345 again blabla thanks blabla
5 ответов:
Я большой поклонник решения такого рода проблем таким способом, который дает вам доступ ко всем данным (включая дискурс человека Б). Я люблю tidyr S
extract
за такое разделение столбцов. Я использовал подход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
Edit: на самом деле я подозреваю, что ваши данные имеют реальные имена, такие как "Джон Смит" и "человек а". Если это так, то это начальное регулярное выражение split захватит имя и фамилию, которые используют заглавные буквы, а затем двоеточие:
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
Использование пакета
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 начинает разговор, если говорит только один из двух, а также для долгий разговор.
Используя
data.table and
gsub ' из базы R: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
Это может не сработать для всех ваших случаев. Особенно те, с которых начинается разговор
Person B
. Дайте мне знать, если это так. Еще попробуйтеdf$person_A <- gsub("Person B.*:|Person A:", "", df$conversation) df <- data.frame(df$id, df$person_A)
Это моя попытка, я также добавил второй разговор, начатый человеком 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
, это удаление:
- Лицо А:
- предложения лица Б, за которыми следуют предложения а
- предложения Б В конце разговора
\Z
Я использовал
perl = TRUE
, потому что жизнь слишком коротка, чтобы не использовать зеркало заднего вида... хм... оператор назад.