Search code examples
rdataframetextdatasetmassive

Text mining on a massive dataset in R (or Python !)


I have a dataset of more than 2.300.000 observations. One variable is dedicated to descriptions (text), and there is sometimes quite long sentences. With all this observations imagine the number of words we have. I want to obtain an output (a data frame) with all the words of this variable, sorted from the most to the least frequent. However, i don't want to take into account some word such as "and", "street", "the" etc.

I tested two codes :


descri1tm <- df %>%

  # Transforming in a corpus #
  
  VectorSource() %>%
  Corpus() %>% 
  # Cleaning the corpus #
  
  tm_map(content_transformer(tolower)) %>% #lowercase
  tm_map(stripWhitespace) %>% 
  tm_map(removeNumbers) %>% #numbers
  tm_map(removePunctuation) %>% #ponctuation
  tm_map(removeWords, stopwords("spanish", "cale","barrio","y","al","en","la","el","entre","del")) %>% # words we don't care about 
  
  # Transform in a Matrix # 
  
  TermDocumentMatrix() %>%
  as.data.frame.matrix() %>%
  mutate(name = row.names(.)) %>%
  arrange(desc(`1`))

#Creating the data frame #

tidytext <- data_frame(line = 1:nrow(df), Description = df$cdescription) 
#Frequency analysis 
tidytext <- tidytext %>%
  unnest_tokens(word, Description) %>%
  anti_join(stop_words) %>%
  count(word, sort = TRUE) 


head(tidytext, 10) 

For this one i think that is not powerful enough, R was running for 24 hours with no result... So i tested this one (found here) :


allwords <- df %>% stringr::str_glue_data("{rownames(.)} cdescription: {cdescription}")

# function to count words in a string #

countwords = function(strings){
  
  # remove extra spaces between words
  wr = gsub(pattern = " {2,}", replacement=" ", x=strings)
  
  # remove line breaks
  wn = gsub(pattern = '\n', replacement=" ", x=wr)
  
  # remove punctuations
  ws = gsub(pattern="[[:punct:]]", replacement="", x=wn)
  
  # split the words
  wsp =  strsplit(ws, " ")
  
  # sort words in table
  wst = data.frame(sort(table(wsp, exclude=""), decreasing=TRUE))
  wst
}
all_words <- countwords(allwords) 

For this one, two problems : it's not possible to don't take into account some words, and i have the following error message again and again :

Error in table(wsp, exclude = "") : all arguments must have the same length

Does someone have an idea ? Please be kind, it's my very first time with such a dataset, and data science is not my specialty at all !


Solution

  • If the text is stored in a data frame variable, to obtain word frequency and remove Spanish stopwords, you just need the third sequence of your first block of code.

    df <- data.frame(
    status_id = c("1377298096732958721", "1376773867805540360",  "1376627381994188802", "1376551216252076038", "1379254614898393091",  "1376551522746691588", "1377122148779655174", "1376518995508133888",  "1376675783775764486", "1377697100276842497"), 
    text = c("La protección de las mujeres defensoras de #DDHH es imprescindible para avanzar hacia la igualdad. Por este motivo, llamamos a los Estados y mecanismos internacionales presentes en el #ForoGeneraciónIgualdad a adoptar una serie de medidas urgentes para su protección. HILO<U+0001F447><U+0001F3FE>",  "Llaman a las feministas a no participar en la farsa conocida como Foro Generación Igualdad, anunciado como un acto donde es fundamental la sociedad civil feminista vía @SemMéxico",  "En el marco de la inauguración del Foro Generación Igualdad, el presidente @lopezobrador_ afirmó que trabajamos todos los días para combatir la discriminación, el clasismo y el racismo. #FelizLunes <U+270C><U+FE0F> #MJyEx4T <U+0001F1F2><U+0001F1FD> #MJE4T",  "Es un honor participar en el #ForoGeneraciónIgualdad que inauguró el presidente @lopezobrador_. Este encuentro mundial convocado por @ONUMujeres y co presidido por el gobierno de Francia del presidente @EmmanuelMacron busca acciones concretas a favor de las mujeres.",  "Queremos un mundo en el que las mujeres decidamos sobre nuestros cuerpos, la política y el medio ambiente. #GeneraciónIgualdad",  "<U+0001F5E3> Inauguración del Foro Generación Igualdad : \"En México como en Paris podremos contar con la movilización colectiva de los gobiernos\" - Emmanuel Macron. <U+0001F6BA>=<U+0001F6B9> @EmmanuelMacron @Elysee @GenEgaliteFR @ONUMujeresMX",  "Gran orgullo ser parte del #ForoGeneraciónIgualdad en el que también destaca el intercambio cultural. Un honor compartir este día con @nadgasman, @ONUMujeres y con mis compañeras del primer gabinete paritario en la historia de México.",  "Como nos recuerda @C2030Europe hoy empieza el #ForoGeneraciónIgualdad, cita mundial para impulsar los derechos sexuales y reproductivos y la igualdad de género. Más información, aquí:",  "En este #ForoGeneracionIgualdad escucharemos las voces de mujeres de todo el mundo en un diálogo horizontal para avanzar hacia la igualdad y nos hemos propuesto objetivos de interés general que atienda a las mujeres que menos tienen: @M_OlgaSCordero",  "<U+0001F4C4>El activismo y los compromisos para acelerar la igualdad de género marcan la clausura del Foro Generación Igualdad en la CDMX." )
    )
    
    df %>% 
        mutate(text = tolower(text)) %>% 
        unnest_tokens(output = word, input = text) %>% 
        filter(!word  %in% c(stopwords::stopwords(language = "es"), "cale","barrio","y","al","en","la","el","entre","del")) %>% 
        count(word, sort = TRUE)
    
                          word  n
    1                        u 13
    2                 igualdad  8
    3                  mujeres  5
    4                     foro  4
    5   forogeneraciónigualdad  4
    ...
    

    If this is still too much for your system's RAM, simply slice the source DF into smaller dfs, and then append and sum the resulting word counts.