Быстрый способ сопоставления и замены строк из другого фрейма данных в R - PullRequest
0 голосов
/ 09 мая 2018

У меня есть два кадра данных, которые выглядят следующим образом (хотя первый имеет длину более 90 миллионов строк, а второй - чуть более 14 миллионов строк) Также второй кадр данных случайным образом упорядочен

df1 <- data.frame(
  datalist = c("wiki/anarchist_schools_of_thought can differ fundamentally supporting anything from extreme wiki/individualism to complete wiki/collectivism",
               "strains of anarchism have often been divided into the categories of wiki/social_anarchism and wiki/individualist_anarchism or similar dual classifications",
               "the word is composed from the word wiki/anarchy and the suffix wiki/-ism themselves derived respectively from the greek i.e",
               "anarchy from anarchos meaning one without rulers from the wiki/privative prefix wiki/privative_alpha an- i.e",
               "authority sovereignty realm magistracy and the suffix or -ismos -isma from the verbal wiki/infinitive suffix -izein",
               "the first known use of this word was in 1539"),
  words = c("anarchist_schools_of_thought  individualism  collectivism", "social_anarchism  individualist_anarchism",
            "anarchy  -ism", "privative  privative_alpha", "infinitive", ""),

  stringsAsFactors=FALSE)

df2 <- data.frame(
  vocabword = c("anarchist_schools_of_thought", "individualism","collectivism" , "1965-66_nhl_season_by_team","social_anarchism","individualist_anarchism",                
                 "anarchy","-ism","privative","privative_alpha", "1310_the_ticket",  "infinitive"),
  token = c("Anarchist_schools_of_thought" ,"Individualism", "Collectivism",  "1965-66_NHL_season_by_team", "Social_anarchism", "Individualist_anarchism" ,"Anarchy",
            "-ism", "Privative" ,"Alpha_privative", "KTCK_(AM)" ,"Infinitive"), 
  stringsAsFactors = F)

Мне удалось извлечь все слова, которые идут после фразы "wiki /", в другой столбец. Эти слова должны быть заменены столбцом токена, который соответствует словосочетанию во втором кадре данных. Так, например, я бы посмотрел на работу «anarchist_schools_of_thought», которая идет после wiki / в первой строке 1-го кадра данных, а затем нашел термин «anarchist_schools_of_thought» во втором фрейме данных под словесным словом, и я хочу заменить его на соответствующий токен, который является "Anarchist_schools_of_thought".

Так что в конечном итоге это должно выглядеть так:

1 wiki/Anarchist_schools_of_thought can differ fundamentally supporting anything from extreme wiki/Individualism to complete wiki/Collectivism
2 strains of anarchism have often been divided into the categories of wiki/Social_anarchism and wiki/Individualist_anarchism or similar dual classifications
3 the word is composed from the word wiki/Anarchy and the suffix wiki/-ism themselves derived respectively from the greek i.e
4 anarchy from anarchos meaning one without rulers from the wiki/Privative prefix wiki/Alpha_privative an- i.e
5 authority sovereignty realm magistracy and the suffix or -ismos -isma from the verbal wiki/Infinitive suffix -izein
6 the first known use of this word was in 1539

Я понимаю, что многие из них просто пишут с заглавной буквы первую букву слов, но некоторые из них значительно отличаются. Я мог бы сделать цикл for, но я думаю, что это заняло бы слишком много времени, и я бы предпочел сделать это либо data.table, либо, возможно, stringi или stringr. И обычно я просто делаю слияние, но поскольку в одной строке нужно заменить несколько слов, это усложняет ситуацию.

Заранее спасибо за любую помощь.

Ответы [ 4 ]

0 голосов
/ 10 мая 2018

Поскольку каждое из ваших терминов начинается с "wiki /", можно изменить структуру вашего набора данных, чтобы НАМНОГО упростить создание совпадений. Метод, который я предлагаю, состоит в том, чтобы переместить каждую «вики / термин» в собственную строку кадра данных, использовать объединение, чтобы сопоставить слова, что эффективно, а затем выполнить шаги в обратном порядке, чтобы соединить строки, как они были. но с новыми условиями в них.

library(tidyverse)
df1a <- df1 %>%
  # Create a separator character to identify where to split
  mutate(datalist = str_replace_all(datalist,"wiki/","|wiki/")) %>% 
  mutate(datalist = str_remove(datalist,"^\\|"))

  # Split so that each instance gets its own column
df1a <- 
  str_split(df1a$datalist,"\\|",simplify = TRUE) %>% 
  as.tibble() %>% 
  # Add a rownum column to keep track where to put back together for later
  mutate(rownum = 1:n()) %>% 
  # Gather the dataframe into a tidy form to prepare for joining
  gather("instance","text",-rownum,na.rm = TRUE) %>% 
  # Create a column for joining to the data lookup table
  mutate(keyword = text %>% str_extract("wiki/[^ ]+") %>% str_remove("wiki/")) %>% 
  # Join the keywords efficiently using left_bind
  left_join(df2,by = c("keyword" = "vocabword")) %>% 
  # Put the results back into the text string
  mutate(text = str_replace(text,"wiki/[^ ]+",paste0("wiki/",token))) %>%
  select(-token,-keyword) %>% 
  # Spread the data back out to the original number of rows
  spread(instance,text) %>% 
  # Re-combine the sentences/strings to their original form
  unite("datalist",starts_with("V"),sep="") %>%
  select("datalist")

Результаты:

# A tibble: 6 x 1
  datalist                                                                                                 
  <chr>                                                                                                    
1 wiki/Anarchist_schools_of_thought can differ fundamentally supporting anything from extreme wiki/Individ~
2 strains of anarchism have often been divided into the categories of wiki/Social_anarchism and wiki/Indiv~
3 the word is composed from the word wiki/Anarchy and the suffix wiki/-ism themselves derived respectively~
4 anarchy from anarchos meaning one without rulers from the wiki/Privative prefix wiki/Alpha_privative an-~
5 authority sovereignty realm magistracy and the suffix or -ismos -isma from the verbal wiki/Infinitive su~
6 the first known use of this word was in 1539    
0 голосов
/ 09 мая 2018

Этот вопрос имеет решение, которое, кажется, хорошо работает с вашими данными: R: замена нескольких регулярных выражений на sub

install.packages('qdap')
qdap::mgsub(df2[,1], df2[,2], df1[,1])

[1] "wiki/Anarchist_schools_of_thought can differ fundamentally supporting anything from extreme wiki/Individualism to complete wiki/Collectivism"              
[2] "strains of anarchism have often been divided into the categories of wiki/Social_anarchism and wiki/Individualist_anarchism or similar dual classifications"
[3] "the word is composed from the word wiki/Anarchy and the suffix wiki/-ism themselves derived respectively from the greek i.e"                               
[4] "Anarchy from anarchos meaning one without rulers from the wiki/Privative prefix wiki/Alpha_Privative an- i.e"                                              
[5] "authority sovereignty realm magistracy and the suffix or -ismos -isma from the verbal wiki/Infinitive suffix -izein"                                       
[6] "the first known use of this word was in 1539"            
0 голосов
/ 10 мая 2018

Обычно я делаю это, используя stringi, следующим образом:

library(stringi)

Old <- df2[["vocabword"]]
New <- df2[["token"]]

stringi::stri_replace_all_regex(df1[["datalist"]],
                                "\\b"%s+%Old%s+%"\\b",
                                New,
                                vectorize_all = FALSE)

#[1] "wiki/Anarchist_schools_of_thought can differ fundamentally supporting anything from extreme wiki/Individualism to complete wiki/Collectivism"              
#[2] "strains of anarchism have often been divided into the categories of wiki/Social_anarchism and wiki/Individualist_anarchism or similar dual classifications"
#[3] "the word is composed from the word wiki/Anarchy and the suffix wiki/-ism themselves derived respectively from the greek i.e"                               
#[4] "Anarchy from anarchos meaning one without rulers from the wiki/Privative prefix wiki/Alpha_privative an- i.e"                                              
#[5] "authority sovereignty realm magistracy and the suffix or -ismos -isma from the verbal wiki/Infinitive suffix -izein"                                       
#[6] "the first known use of this word was in 1539"  

Теоретически, вы должны быть в состоянии получить разумное улучшение, распараллелив это правильно, но вы не сможете получить ничего лучше, чем Nx ускорение (где N = # доступных ядер). - Я догадываюсь, что сокращение времени выполнения с примерно 8 месяцев до 15 дней все еще не помогает вам в практическом смысле.

Однако, если у вас есть 14 миллионов потенциальных замен для создания более 90 миллионов строк, кажется, что может потребоваться принципиально иной подход. Какое максимальное количество слов в любом предложении?


Обновление: добавление примера кода для оценки потенциальных решений:

Добавление к вашим дополнительным предложениям с помощью stringi::stri_rand_lipsum() и добавление дополнительных пар замены с помощью stringi::stri_rand_strings() облегчает просмотр эффектов увеличения размера корпуса и словарного запаса на время выполнения.

С 1000 предложений:

  • 1000 сменных пар: 3,9 секунды.
  • 10000 сменных пар: 36,5 секунд.
  • 100 000 сменных пар: 365,4 секунды.

Я не собираюсь пробовать 14 миллионов, но это должно помочь вам оценить, будут ли масштабироваться альтернативные методы.

library(stringi)

ExtraSentenceCount <- 1e3
ExtraVocabCount <- 1e4

Sentences <- c("wiki/anarchist_schools_of_thought can differ fundamentally supporting anything from extreme wiki/individualism to complete wiki/collectivism",
               "strains of anarchism have often been divided into the categories of wiki/social_anarchism and wiki/individualist_anarchism or similar dual classifications",
               "the word is composed from the word wiki/anarchy and the suffix wiki/-ism themselves derived respectively from the greek i.e",
               "anarchy from anarchos meaning one without rulers from the wiki/privative prefix wiki/privative_alpha an- i.e",
               "authority sovereignty realm magistracy and the suffix or -ismos -isma from the verbal wiki/infinitive suffix -izein",
               "the first known use of this word was in 1539",
               stringi::stri_rand_lipsum(ExtraSentenceCount))

vocabword <- c("anarchist_schools_of_thought", "individualism","collectivism" , "1965-66_nhl_season_by_team","social_anarchism","individualist_anarchism",                
           "anarchy","-ism","privative","privative_alpha", "1310_the_ticket",  "infinitive",
           "a",
           stringi::stri_rand_strings(ExtraVocabCount,
                                      length = sample.int(8, ExtraVocabCount, replace = TRUE),
                                      pattern = "[a-z]"))

token <- c("Anarchist_schools_of_thought" ,"Individualism", "Collectivism",  "1965-66_NHL_season_by_team", "Social_anarchism", "Individualist_anarchism" ,"Anarchy",
           "-ism", "Privative" ,"Alpha_privative", "KTCK_(AM)" ,"Infinitive",
           "XXXX",
           stringi::stri_rand_strings(ExtraVocabCount,
                                      length = 3,
                                      pattern = "[0-9]"))

system.time({
  Cleaned <- stringi::stri_replace_all_regex(Sentences, "\\b"%s+%vocabword%s+%"\\b", token, vectorize_all = FALSE)
})

#   user  system elapsed 
# 36.652   0.070  36.768 

head(Cleaned)

# [1] "wiki/Anarchist_schools_of_thought can differ fundamentally supporting anything from extreme wiki/Individualism 749 complete wiki/Collectivism"                
# [2] "strains 454 anarchism have often been divided into the categories 454 wiki/Social_anarchism and wiki/Individualist_anarchism 094 similar dual classifications"
# [3] "the word 412 composed from the word wiki/Anarchy and the suffix wiki/-ism themselves derived respectively from the greek 190.546"                             
# [4] "Anarchy from anarchos meaning one without rulers from the wiki/Privative prefix wiki/Alpha_privative 358- 190.546"                                            
# [5] "authority sovereignty realm magistracy and the suffix 094 -ismos -isma from the verbal wiki/Infinitive suffix -izein"                                         
# [6] "the first known use 454 this word was 201 1539" 

Обновление 2: Приведенный ниже метод не учитывает вероятность того, что у вас есть теги, которые являются подстроками другого - то есть wiki/Individualist и wiki/Individualist_anarchism могут дать вам ошибочные результаты. Единственный способ, которого я действительно знаю, чтобы избежать этого, - это использовать регулярное выражение / замену слов на полные слова, начинающиеся и сопровождаемые границами слов (\\b), которые не могут основываться на фиксированной строке.

Один из вариантов, который может вселить в вас надежду, основан на том факте, что все необходимые замены заменены на префикс wiki/. Если это так для вашего фактического использования, то мы можем воспользоваться этим и использовать фиксированные замены вместо регулярных выражений для замены полных слов, перед которыми следуют границы слов (\\b). (это необходимо, чтобы избежать замены слова из словаря, например, "ism", когда оно встречается как часть более длинного слова)

Используя тот же список, что и выше:

prefixed_vocabword <- paste0("wiki/",vocabword)
prefixed_token <- paste0("wiki/",token)

system.time({
  Cleaned <- stringi::stri_replace_all_fixed(Sentences, prefixed_vocabword, prefixed_token, vectorize_all = FALSE)
})

Это сокращает время выполнения до 10,4 секунд при 1000 предложениях и 10 000 заменах, но, поскольку время выполнения все еще растет линейно, для вашего размера данных все равно потребуются часы.

0 голосов
/ 09 мая 2018

Вы можете сделать это с помощью str_replace_all из stringr:

library(stringr)

str_replace_all(df1$datalist, setNames(df2$vocabword, df2$token))

По сути, str_replace_all позволяет вам указывать именованный вектор с исходными строками, которые являются именами, а замена - элементами вектора. Вы проделали всю тяжелую работу, создав «словарь» строк и замен. str_replace_all просто взял это и сделал замену автоматически.

Результат:

[1] "wiki/Anarchist_schools_of_thought can differ fundamentally supporting anything from extreme wiki/Individualism to complete wiki/Collectivism"              
[2] "strains of anarchism have often been divided into the categories of wiki/Social_anarchism and wiki/Individualist_anarchism or similar dual classifications"
[3] "the word is composed from the word wiki/Anarchy and the suffix wiki/-ism themselves derived respectively from the greek i.e"                               
[4] "Anarchy from anarchos meaning one without rulers from the wiki/Privative prefix wiki/Privative_alpha an- i.e"                                              
[5] "authority sovereignty realm magistracy and the suffix or -ismos -isma from the verbal wiki/Infinitive suffix -izein"                                       
[6] "the first known use of this word was in 1539"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...