Text processing with R

Session 08 - Exercise

Published

03.07.2024

Quarto Document Link to source file

Ziel der Anwendung: Textanalyse in R kennenlernen
  • Auffrischung der Grundkenntnisse im Umgang mit R, tidyverse und ggplot2
  • Typische Schritte der Textanalyse mit tidytext kennenlernen, von der Tokenisierung bis zur Visualisierung.

Background

Todays’s data basis: OpenAlex
  • Via API bzw. openalexR (Aria et al. 2024) gesammelte “works” der Datenbank OpenAlex mit Bezug zu Literaturriews in den Sozialwissenschaften zwischen 2013 und 2023

  • Detaillierte Informationen und Ergebnisse zur Suchquery finden Sie hier.

Preparation

Wichtige Information
  • Bitte stellen Sie sicher, dass Sie das jeweilige R-Studio Projekt zur Übung geöffnet haben. Nur so funktionieren alle Dependencies korrekt.
  • Um den einwandfreien Ablauf der Übung zu gewährleisten, wird für die Aufgaben auf eine eigenständige Datenerhebung verzichtet und ein Übungsdatensatz zu verfügung gestelt.

Packages

if (!require("pacman")) install.packages("pacman")
pacman::p_load(
    here, qs, # file management
    magrittr, janitor, # data wrangling
    easystats, sjmisc, # data analysis
    gt, gtExtras, # table visualization
    ggpubr, ggwordcloud, # visualization
    tidytext, widyr, # text analysis    
    openalexR, 
    tidyverse # load last to avoid masking issues
  )

Import und Vorverarbeitung der Daten

# Import from local
review_works <- qs::qread(here("data/session-07/openalex-review_works-2013_2023.qs"))

# Create correct data
review_works_correct <- review_works %>% 
    mutate(
        # Create additional factor variables
        publication_year_fct = as.factor(publication_year), 
        type_fct = as.factor(type)
        )

🛠️ Praktische Anwendung

Achtung, bitte lesen!
  • Bevor Sie mit der Arbeit an den folgenden 📋 Exercises beginnen, stellen Sie bitte sicher, dass Sie alle Chunks des Abschnitts Preparation gerendert haben. Das können Sie tun, indem Sie den “Run all chunks above”-Knopf des nächsten Chunks benutzen.
  • Bei Fragen zum Code lohnt sich ein Blick in den Showcase (.qmd oder .html). Beim Showcase handelt es sich um eine kompakte Darstellung des in der Präsentation verwenden R-Codes. Sie können das Showcase also nutzen, um sich die Code-Bausteine anzusehen, die für die R-Outputs auf den Slides benutzt wurden.

📋 Exercise 1: Neues Subsample

Ziel der Aufgabe
  • Erstellung eines neuen Datensatzes review_subsample_new, der sich auf englischsprachig Bücher bzw. Buchrartikel beschränkt.
  1. Erstellen Sie einen neuen Datensatz review_subsample_new
    • Basierend auf dem Datensatzes review_works_correct:
      1. Nutzen Sie die filter()-Funktion, um
        • nur englischsprachige (language),
        • Bücher und Buchkapitel (type) herauszufiltern.
      2. Speichern Sie diese Umwandlung in einem neuen Datensatz mit dem Namen review_subsample_new
  2. Überprüfen Sie die Transformation mit Hilfe der glimpse()-Funktion.
  3. ✍️ Notieren Sie, wie viele Artikel im neuen Subsample enthalten sind.
Lösung anzeigen
# Erstellung Subsample
review_subsample_new <- review_works_correct %>% 
  # Eingrenzung: Sprache und Typ
  filter(language == "en") %>% 
  filter(type == "book" | type == "book-chapter")

# Überprüfung
review_subsample_new %>% glimpse
Rows: 2,994
Columns: 41
$ id                          <chr> "https://openalex.org/W2899962821", "https…
$ title                       <chr> "Introduction to systematic reviews", "Cha…
$ display_name                <chr> "Introduction to systematic reviews", "Cha…
$ author                      <list> [<data.frame[2 x 12]>], NA, [<data.frame[…
$ ab                          <chr> "A systematic review is a vital part of th…
$ publication_date            <chr> "2018-10-01", "2020-01-01", "2019-01-01", …
$ relevance_score             <dbl> 300.1405, 255.6323, 248.6059, 231.0026, 22…
$ so                          <chr> "Manchester University Press eBooks", "JBI…
$ so_id                       <chr> "https://openalex.org/S4306463591", "https…
$ host_organization           <chr> "Winchester University Press", NA, NA, NA,…
$ issn_l                      <chr> NA, NA, NA, NA, "0302-9743", NA, NA, NA, N…
$ url                         <chr> "https://doi.org/10.7765/9781526136527.000…
$ pdf_url                     <chr> "https://www.manchesteropenhive.com/downlo…
$ license                     <chr> "cc-by-nc-nd", NA, NA, NA, NA, NA, NA, "cc…
$ version                     <chr> "publishedVersion", "publishedVersion", "p…
$ first_page                  <chr> NA, NA, NA, NA, "214", "48", NA, "3", "85"…
$ last_page                   <chr> NA, NA, NA, NA, "227", "78", NA, "22", "94…
$ volume                      <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ issue                       <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ is_oa                       <lgl> TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRU…
$ is_oa_anywhere              <lgl> TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRU…
$ oa_status                   <chr> "hybrid", "bronze", "bronze", "closed", "c…
$ oa_url                      <chr> "https://www.manchesteropenhive.com/downlo…
$ any_repository_has_fulltext <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ language                    <chr> "en", "en", "en", "en", "en", "en", "en", …
$ grants                      <list> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ cited_by_count              <int> 423, 496, 421, 547, 274, 64, 247, 189, 136…
$ counts_by_year              <list> [<data.frame[8 x 2]>], [<data.frame[6 x 2…
$ publication_year            <int> 2018, 2020, 2019, 2013, 2014, 2015, 2020, …
$ cited_by_api_url            <chr> "https://api.openalex.org/works?filter=cit…
$ ids                         <list> <"https://openalex.org/W2899962821", "htt…
$ doi                         <chr> "https://doi.org/10.7765/9781526136527.000…
$ type                        <chr> "book-chapter", "book-chapter", "book-chap…
$ referenced_works            <list> NA, NA, NA, <"https://openalex.org/W11488…
$ related_works               <list> <"https://openalex.org/W4385987771", "htt…
$ is_paratext                 <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ is_retracted                <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ concepts                    <list> [<data.frame[16 x 5]>], [<data.frame[7 x …
$ topics                      <list> [<tbl_df[4 x 5]>], [<tbl_df[4 x 5]>], [<t…
$ publication_year_fct        <fct> 2018, 2020, 2019, 2013, 2014, 2015, 2020, …
$ type_fct                    <fct> book-chapter, book-chapter, book-chapter, …
Lösung anzeigen
# Notiz:
# Subsample enthält 2994 Einträge

📋 Exercise 2: Umwandlung zu ‘tidy text’

  1. Erstellen Sie einen neuen Datensatz subsample_new_tidy,
    • Basierend auf dem Datensatz review_subsample_new, mit folgenden Schritten:
      1. Tokenisierung der Abstracts (ab) mit der Funktion unnest_tokens.
      2. Ausschluss von Stoppwörter mit filter und stopwords$words heraus.
      3. Speichern Sie diese Umwandlung, indem Sie einen neuen Datensatz mit dem Namen subsample_new_tidy erstellen.
  2. Prüfen Sie, ob die Umwandlung erfolgreich war (z.B. mit der Funktion glimpse())
  3. ✍️ Notieren Sie, wie viele Token im neuen Datensatz subsample_new_tidy enthalten sind.
Lösung anzeigen
# Erstellung des neuen Datensatzes `subsample_new_tidy`
subsample_new_tidy <- review_subsample_new %>% 
  tidytext::unnest_tokens("text", ab) %>% 
   filter(!text %in% tidytext::stop_words$word)

# Überprüfung
subsample_new_tidy %>% print()
# A tibble: 182,776 × 41
   id     title display_name author publication_date relevance_score so    so_id
   <chr>  <chr> <chr>        <list> <chr>                      <dbl> <chr> <chr>
 1 https… Intr… Introductio… <df>   2018-10-01                  300. Manc… http…
 2 https… Intr… Introductio… <df>   2018-10-01                  300. Manc… http…
 3 https… Intr… Introductio… <df>   2018-10-01                  300. Manc… http…
 4 https… Intr… Introductio… <df>   2018-10-01                  300. Manc… http…
 5 https… Intr… Introductio… <df>   2018-10-01                  300. Manc… http…
 6 https… Intr… Introductio… <df>   2018-10-01                  300. Manc… http…
 7 https… Intr… Introductio… <df>   2018-10-01                  300. Manc… http…
 8 https… Intr… Introductio… <df>   2018-10-01                  300. Manc… http…
 9 https… Intr… Introductio… <df>   2018-10-01                  300. Manc… http…
10 https… Intr… Introductio… <df>   2018-10-01                  300. Manc… http…
# ℹ 182,766 more rows
# ℹ 33 more variables: host_organization <chr>, issn_l <chr>, url <chr>,
#   pdf_url <chr>, license <chr>, version <chr>, first_page <chr>,
#   last_page <chr>, volume <chr>, issue <chr>, is_oa <lgl>,
#   is_oa_anywhere <lgl>, oa_status <chr>, oa_url <chr>,
#   any_repository_has_fulltext <lgl>, language <chr>, grants <list>,
#   cited_by_count <int>, counts_by_year <list>, publication_year <int>, …
Lösung anzeigen
# Notiz:
# Der neue Datensatz enthält 182776 Token. 

📋 Exercise 3: Auswertung der Token

  1. Erstellen Sie einen neuen Datensatz subsample_new_summarized,
    • Fassen Sie auf der Grundlage des Datensatzes subsample_new_tidy die Häufigkeit der einzelnen Token zusammen, indem Sie die Funktion count() auf die Variable text anwenden. Verwenden Sie das Argument sort = TRUE, um den Datensatz nach absteigender Häufigkeit der Token zu sortieren.
    • Speichern Sie diese Transformation, indem Sie einen neuen Datensatz mit dem Namen subsample_new_summarized erstellen.
  2. Prüfen Sie, ob die Umwandlung erfolgreich war, indem Sie die Funktion print() verwenden.
    • Verwenden Sie das Argument n = 50, um die 50 wichtigsten Token anzuzeigen (nur möglich, wenn das Argument sort = TRUE bei der Ausführung der Funktion count() verwendet wurde)
  3. Verteilung der Token prüfen
    • Verwenden Sie die Funktion datawizard::describe_distribution(), um verschiedene Verteilungsparameter des neuen Datensatzes zu überprüfen
    • ✍️ Notieren Sie, wie viele Token ein Abstract durchschnittlich enthält.
  • Optional: Ergebnisse mit einer Wortwolke überprüfen
    • Basierend auf dem sortierten Datensatz subsample_new_summarized
      1. Auswahl der 50 häufigsten Token mit Hilfe der Funktion top_n()
      2. Erstellen Sie eine ggplot()-Basis mit label = text und size = n als aes() und
      3. Benutze ggwordcloud::geom_text_wordclout() um die Wortwolke zu erstellen.
      4. Verwenden Sie scale_size_are(), um die Skalierung der Wortwolke zu übernehmen.
      5. Verwenden Sie theme_minimal() für eine saubere Visualisierung.
Lösung anzeigen
# Erstellung des neuen Datensatzes `subsample_new_summmarized`
subsample_new_summmarized <- subsample_new_tidy %>% 
  count(text, sort = TRUE) 

# Preview Top 50 token
subsample_new_summmarized %>% 
    print(n = 50)
# A tibble: 14,959 × 2
   text            n
   <chr>       <int>
 1 research     2761
 2 literature   2539
 3 review       2466
 4 studies      1478
 5 systematic   1231
 6 study        1206
 7 <NA>          936
 8 social        903
 9 analysis      881
10 chapter       851
11 data          824
12 management    788
13 based         786
14 paper         695
15 articles      686
16 learning      666
17 development   627
18 future        622
19 results       596
20 information   581
21 knowledge     572
22 reviews       545
23 education     518
24 factors       516
25 process       498
26 related       491
27 business      483
28 health        454
29 technology    452
30 findings      449
31 digital       437
32 methods       424
33 main          421
34 design        417
35 provide       410
36 field         400
37 quality       396
38 context       384
39 identify      382
40 current       380
41 performance   369
42 published     367
43 approach      356
44 identified    356
45 impact        347
46 relevant      344
47 systems       334
48 role          331
49 model         328
50 conducted     327
# ℹ 14,909 more rows
Lösung anzeigen
# Check distribution parameters 
subsample_new_summmarized %>%
  datawizard::describe_distribution()
Variable |  Mean |    SD | IQR |           Range | Skewness | Kurtosis |     n | n_Missing
------------------------------------------------------------------------------------------
n        | 12.22 | 57.24 |   5 | [1.00, 2761.00] |    24.32 |   925.44 | 14959 |         0
Lösung anzeigen
# Notiz:
# Ein Absatz enthält durchschnittlich 22 Token. 

# Optional: Check results with a wordcloud
subsample_new_summmarized %>% 
    top_n(50) %>% 
    ggplot(aes(label = text, size = n)) +
    ggwordcloud::geom_text_wordcloud() +
    scale_size_area(max_size = 15) +
    theme_minimal()

📋 Exercise 4: Wortbeziehungen im Fokus

4.1 Couting word pairs

  1. Zählen von häufigen Wortpaaren
    • Zählen Sie auf der Grundlage des Datensatzes subsample_new_tidy Wortpaare mit widyr::pairwise_count(), mit den Argumenten item = text, feature = id und sort = TRUE.
    • Speichern Sie diese Transformation, indem Sie einen neuen Datensatz mit dem Namen subsample_new_word_pairs erstellen.
  2. Prüfen Sie, ob die Umwandlung erfolgreich war, indem Sie die Funktion print() verwenden.
    • Verwenden Sie das Argument n = 50, um die 50 wichtigsten Token anzuzeigen (nur möglich, wenn bei der Ausführung der Funktion count() das Argument sort = TRUE verwendet wurde)
Lösung anzeigen
# Couting word pairs among sections
subsample_new_word_pairs <- subsample_new_tidy %>% 
  widyr::pairwise_count(
    item = text,
    feature = id,
    sort = TRUE)

# Check 
subsample_new_word_pairs %>% print(n = 50)
# A tibble: 7,286,586 × 3
   item1      item2          n
   <chr>      <chr>      <dbl>
 1 literature review      1160
 2 review     literature  1160
 3 research   review       947
 4 review     research     947
 5 literature research     915
 6 research   literature   915
 7 review     systematic   795
 8 systematic review       795
 9 literature systematic   642
10 systematic literature   642
11 studies    review       588
12 review     studies      588
13 research   systematic   561
14 systematic research     561
15 study      literature   555
16 literature study        555
17 study      review       549
18 review     study        549
19 literature studies      510
20 studies    literature   510
21 studies    research     508
22 research   studies      508
23 study      research     505
24 research   study        505
25 based      review       420
26 review     based        420
27 future     research     417
28 research   future       417
29 analysis   review       408
30 review     analysis     408
31 literature chapter      404
32 chapter    literature   404
33 paper      review       394
34 review     paper        394
35 future     review       391
36 review     future       391
37 results    review       385
38 review     results      385
39 literature paper        382
40 paper      literature   382
41 future     literature   381
42 literature future       381
43 literature analysis     379
44 analysis   literature   379
45 based      literature   379
46 literature based        379
47 chapter    review       377
48 review     chapter      377
49 studies    systematic   371
50 systematic studies      371
# ℹ 7,286,536 more rows

4.2 Pairwise correlation

  1. Ermittlung der paarweisen Korrelation
    • Basierend auf dem Datensatz subsample_new_tidy,
    • gruppieren Sie die Daten mit der Funktion group_by() nach der Variable text und
    • verwenden Sie filter(n() >= X), um nur Token zu verwenden, die mindestens in einer bestimmte Anzahl (X) vorkommen; Sie können für X einen Wert Ihrer Wahl wählen, ich würde jedoch dringend empfehlen, ein X > 100 zu wählen, da die folgende Funktion sonst möglicherweise nicht in der Lage ist, die Berechnung durchzuführen.
    • Erstellen Sie Wortkorrelationen mit widyr::pairwise_cor(), mit den Argumenten item = text,feature = id und sort = TRUE.
    • Speichern Sie diese Transformation, indem Sie einen neuen Datensatz mit dem Namen subsample_new_corr erstellen.
  2. Prüfen Sie die Paare mit der höchsten Korrelation mit der Funktion print()..
Lösung anzeigen
# Getting pairwise correlation 
subsample_new_corr <- subsample_new_tidy %>% 
  group_by(text) %>% 
  filter(n() >= 250) %>% 
  pairwise_cor(text, id, sort = TRUE)

# Check pairs with highest correlation
subsample_new_corr %>% print(n = 50)
# A tibble: 8,372 × 3
   item1          item2          correlation
   <chr>          <chr>                <dbl>
 1 chain          supply               0.886
 2 supply         chain                0.886
 3 literature     review               0.614
 4 review         literature           0.614
 5 review         systematic           0.561
 6 systematic     review               0.561
 7 sustainability sustainable          0.467
 8 sustainable    sustainability       0.467
 9 research       review               0.462
10 review         research             0.462
11 literature     research             0.446
12 research       literature           0.446
13 future         research             0.373
14 research       future               0.373
15 media          social               0.368
16 social         media                0.368
17 literature     systematic           0.354
18 systematic     literature           0.354
19 learning       education            0.330
20 education      learning             0.330
21 studies        review               0.330
22 review         studies              0.330
23 research       systematic           0.319
24 systematic     research             0.319
25 study          research             0.309
26 research       study                0.309
27 study          literature           0.307
28 literature     study                0.307
29 studies        research             0.306
30 research       studies              0.306
31 articles       published            0.297
32 published      articles             0.297
33 articles       systematic           0.280
34 systematic     articles             0.280
35 models         model                0.280
36 model          models               0.280
37 study          review               0.279
38 review         study                0.279
39 results        review               0.278
40 review         results              0.278
41 results        systematic           0.272
42 systematic     results              0.272
43 based          review               0.269
44 review         based                0.269
45 articles       review               0.268
46 review         articles             0.268
47 studies        systematic           0.266
48 systematic     studies              0.266
49 theory         theoretical          0.266
50 theoretical    theory               0.266
# ℹ 8,322 more rows

📋 Exercise 5: Inhaltlicher Vergleich

  • Vergleichen Sie die Ergebnisse der Übung mit den Auswertungen der Folien:
    • Wie unterscheiden sich die Ergebnisse?
    • Würden Sie die Bücher bzw. Buchabschnitte mit in die Untersuchung integrieren?

References

Aria, Massimo, Trang Le, Corrado Cuccurullo, Alessandra Belfiore, and June Choe. 2024. “openalexR: An R-Tool for Collecting Bibliometric Data from OpenAlex.” The R Journal 15 (4): 167–80. https://doi.org/10.32614/rj-2023-089.