Search code examples
rquanteda

Detect pattern matches within a corpus


I would like to check if the text of a variable contains some geographical reference. I have created a dictionary with all the municipalities I'm interested in. My goal would be to have a dummy variable capturing whether the text of the variable includes any word included in the dictionary. Can you help me with that? I know it isprobably very easy but I'm struggling to do it.

This is my MWE

require(quanteda)

mun <- structure(list(`Codice Regione` = c("01", "01", "01", "01", "01"
), `Codice Comune formato alfanumerico` = c("001001", "001002", "001003", "001004", "001006"), `Denominazione in italiano` = c("Cantù", 
"Airasca", "Ala di Stura", "Albiano d'Ivrea", "Almese"), `Ripartizione geografica` = c("Nord-ovest", "Nord-ovest", 
"Nord-ovest", "Nord-ovest", "Nord-ovest"), `Denominazione Regione` = c("Lombardia", 
"Piemonte", "Piemonte", "Piemonte", "Piemonte")),  row.names = c(NA, -5L), class = c("tbl_df", "tbl", "data.frame"))

pq <- structure(list(date = c("20180323", "20180323", "20180323", "20180323", "20180323-20180507"), numero = c("4/00007", 
"4/00004", "4/00008", "4/00003", "4/00001"), description = c("Atto Camera Interrogazione a risposta scritta 4-00007 presentato da PATASSINI Tullio testo di Venerdì 23 marzo 2018, seduta n. 1  PATASSINI , LATINI , PAOLINI , CAPARVI , MARCHETTI , BELLACHIOMA , D'ERAMO , DURIGON , GERARDI , SALTAMARTINI , DE ANGELIS e ZICCHIERI . &#8212; Al Presidente del Consiglio dei ministri . &#8212; Per sapere &#8211; premesso che: ad un anno e mezzo dagli straordinari eventi sismici che, a decorrere dal 24 agosto 2016, hanno colpito il centro Italia e l'Abruzzo.", 
 "Atto Camera Interrogazione a risposta scritta 4-00004 presentato da MOLTENI Nicola testo di Venerdì 23 marzo 2018, seduta n. 1  MOLTENI . &#8212; Al Ministro dello sviluppo economico . &#8212; Per sapere &#8211; premesso che: i continui problemi relativi al recapito della posta in alcune zone del comune di Cantù, che si protraggono ormai da anni, stanno esasperando i cittadini che vedono regolarmente leso il proprio diritto ad usufruire di un diritto universale, come quello postale, di qualità", 
"Atto Camera Interrogazione a risposta scritta 4-00008 presentato da FIDANZA Carlo testo di Venerdì 23 marzo 2018, seduta n. 1  FIDANZA , OSNATO , FRASSINETTI . &#8212; Al Ministro delle politiche agricole alimentari e forestali . &#8212; Per sapere &#8211; premesso che: è grave la Situazione di crisi che sta vivendo il mondo vitivinicolo dell'Oltrepò Pavese", 
 "Atto Camera Interrogazione a risposta scritta 4-00003 presentato da RUSSO Paolo testo di Venerdì 23 marzo 2018, seduta n. 1  PAOLO RUSSO . &#8212; Al Ministro della salute . &#8212; Per sapere &#8211; premesso che: con il termine maculopatia o degenerazione maculare si indica qualsiasi patologia che comporti una degenerazione della macula, che è la parte centrale della retina.", 
"Atto Camera Interrogazione a risposta scritta 4-00001 presentato da CATTOI Vanessa testo di Venerdì 23 marzo 2018, seduta n. 1  VANESSA CATTOI , BINELLI , FUGATTI e SEGNANA . &#8212; Al Ministro delle infrastrutture e dei trasporti, al Ministro dell'interno . &#8212; Per sapere &#8211; premesso che: nella prima serata di ieri, 22 marzo 2018, si è consumato l'ennesimo episodio di violenza su un treno, quando alla stazione di Ala, sul convoglio regionale diretto a Verona proveniente da Rovereto, è stata aggredita la capotreno.")), row.names = c(NA, 5L), class = "data.frame")

corpus_pq <- corpus(pq, text_field = "description")
corpus_mun <- corpus(mun, text_field = "Denominazione in italiano")
corpus_munl <- as.list(corpus_mun)
dict_geo <- dictionary(corpus_munl)
geo_dfm <- dfm(corpus_pq, dictionary = dict_geo)
contains_geo <- as.logical(geo_dfm[, "dictGeo"])

Thank you very much


Solution

  • You don't need to create your dictionary from the corpus - instead, create a single dictionary entry for your locality list, and look that up to generate a count of each locality. You can then count them by compiling the dfm, and then converting the feature of that dictionary key into a logical to get the vector you want.

    require(quanteda)
    ## Loading required package: quanteda
    ## Package version: 3.0
    ## Unicode version: 13.0
    ## ICU version: 69.1
    ## Parallel computing: 12 of 12 threads used.
    ## See https://quanteda.io for tutorials and examples.
    
    ##
    ## repeat steps above
    ##
    
    corpus_pq <- corpus(pq, text_field = "description")
    

    Now, create the dictionary of your localities:

    dict_geo <- dictionary(list(localities = mun[["Denominazione in italiano"]]))
    dict_geo
    ## Dictionary object with 1 key entry.
    ## - [localities]:
    ##   - cantù, airasca, ala di stura, albiano d'ivrea, almese
    
    geo_toks <- tokens(corpus_pq)
    
    kwic(geo_toks, pattern = dict_geo)
    ## Keyword-in-context with 1 match.                                                                           
    ##  [text2, 59] alcune zone del comune di | Cantù | , che si protraggono ormai
    

    We can see here that there is only one match.

    To compile the dfm, use this method, then coerce that feature column of the dfm into a logical:

    geo_dfm <- tokens_lookup(geo_toks, dictionary = dict_geo) %>%
      dfm()
    
    geo_dfm
    ## Document-feature matrix of: 5 documents, 1 feature (80.00% sparse) and 2 docvars.
    ##        features
    ## docs    localities
    ##   text1          0
    ##   text2          1
    ##   text3          0
    ##   text4          0
    ##   text5          0
    
    contains_geo <- as.logical(geo_dfm[, "localities"])
    contains_geo
    ## [1] FALSE  TRUE FALSE FALSE FALSE