Denne vignet er er skrevet som baggrund til en artikel om sproglige forskelle mellem Bibelen og Koranen. Ideen var, at bruge nogle enkle, kvantitative teknikker til tekstanalyse af Bibelen og Koranen som afsæt for en diskussion af forskelle og ligheder mellem de to bøger … og religioner.
Formålet med teksten her er for det første at give noter, detaljer, tal og figurer til interesserede.
For det andet er dokumentet her tænkt som inspiration og ressource for folk som selv arbejder med, eller har lyst til at begynde på det, som kaldes Natural Language Processing, NLP. Det er en fascinerenede disciplin, hvor matematik og statistik møder tekst og sprog.
Tilhører du den første gruppe, som er nysgerrig på emnet, kan du bare læse teksten eller det af den, du nu har lyst til.
Tilhører du den anden gruppe, med appetit på programmering, kan du klikke på knapperne “Code” til højre og se den R-code som ligger bag de tal og figurer, du ser. Du kan fx klikke på Code-knappen nu, og se hvilke pakker jeg har brugt (plus et par linjer med generelle instillinger).
library(tidyverse) # Suite of nice packages
library(tidytext) # Text analysis the tidy way
library(quanteda) # A very stong package for text analytics
library(Hmisc) # Some useful functions
library(scales) # For scales in plots
library(openNLP) # For part-of-speach tagging
library(knitr) # For nice output
library(kableExtra) # For even nicer output
library(text2vec) # For word vectors
set.seed(1972) # For reproducibility
theme_set(theme_minimal()) # For nice, clean, plots
options(scipen=999) # To avoid scientific notation
Du er også velkommen til at klone det repository, hvor jeg opbevarer al data og kode, jeg har skrevet til dette projekt. (Inklusive den tekst du læser nu.)
Jeg har brugt i alt fem tekster til analysen, alle sammen konverteret til analyserbare datafiler. Først og fremmest:
Bibelen, den autoriserede oversættelser fra 1992, Det Danske Bibelselskab. 2011.
Koranen, Den Klare Koran, Dansk koranoversættelse af Amér Majid, Forlaget Tronen, 2015.
Hist og pist (især til sentiment analyse, se senere) har jeg inddraget de tilsvarende engelske versioner:
Bibelen på engelsk, King James Version, fra Project Gutenberg.
Koranen på engelsk, klargjort til analyse af ZuhaibAli på Kaggle.
Endelig har jeg et par enkelte steder brugt Harry Potter-serien til sammenligning. Disse tekster findes i en særlig pakke til R her.
Hvis man gerne vil have endnu flere detaljer, kan man se programmerne code/01_get_data.R og code/02_clean_data.R i projektets repository. Sidstnævnte indeholder den præcise syntax, der er brugt til at rense teksterne, så de er klar til analyse.
Se navne på de analyseklare filer, og hvordan de kombineres, under “Code”.
# The Bible in Danish
bib <- readRDS("../data/bibelen_cleaned.rds") %>%
select(text, era = testament, book, chapter, verse)
# The Quran in Danish
kor <- readRDS("../data/koranen_cleaned.rds") %>%
select(text, era = time, book = part, chapter = surano, verse) %>%
mutate(book = as.character(book))
# King James version of the Bible
kjv <- readRDS("../data/bib_kjv_cleaned.rds") %>%
select(text, era = testament, book, chapter, verse)
# The Quran in English
qur <- readRDS("../data/quran_cleaned.rds") %>%
select(text, era = time, book = part, chapter = surano, verse) %>%
mutate(book = as.character(book))
# Combine the Danish Bible and Quran into one dataframe
holy <- bind_rows(bib, kor) %>%
mutate(collection = ifelse(str_detect(era, "Testamente"), "Bibelen", "Koranen"))
# Same thing for the English equivalents
holy_en <- bind_rows(kjv, qur) %>%
mutate(collection = ifelse(str_detect(era, "Testament"), "The Bible", "The Quran"))
# Housekeeping: We no longer need those
remove(bib, kor, kjv, qur)
Generelt er tilgangen til kvantitativ tekstanalyse (Natural Language Processing) den, at splitte teksten op i mindre bidder, som fx ord, som man så kan tælle og på anden vis analysere.
Nogle gange er det ikke ord, der er den relevante enhed, men måske ordpar eller tre-ordskombinationer, hvis man er interesseret i bestemte udtryk. Det kan også være, at man vil se på sætninger, eller vers – den sidste enhed er særlig relevant for tekster som Bibelen og Koranen.
Jeg har dannet en række forskellige tabeller af denne type.
# Various metrics in "tidy" format: doc x term (including tfidf and more)
tfidf <- holy %>%
unnest_tokens(output = word, text) %>%
anti_join(tibble(word = tm::stopwords(kind = "da")), by = "word") %>%
mutate(stem = SnowballC::wordStem(word, language = "da")) %>%
group_by(stem, word) %>%
mutate(n = n()) %>%
group_by(stem) %>%
mutate(n_total = n(),
common_origin = first(word, order_by = -n),
no_origins = n_distinct(word)) %>%
count(era, collection, stem, name = "n_doc",
n_total, common_origin, no_origins) %>%
group_by(stem) %>%
mutate(doc_count = n()) %>%
group_by(era, collection) %>%
mutate(doc_total = sum(n_doc)) %>%
ungroup() %>%
bind_tf_idf(term = stem, document = era, n = n_doc)
# words x stem x era (for checking how stemming works)
# "Era" = new/old testament; Quran Mekkan/Medinan
word_era <- holy %>%
unnest_tokens(word, text) %>%
mutate(stem = SnowballC::wordStem(word, language = "da")) %>%
count(era, word, stem) %>%
group_by(era) %>%
mutate(pct = n/sum(n) * 100) %>%
ungroup() %>%
arrange(-pct) %>%
mutate(word = factor(word, levels = rev(unique(word))))
word_era_en <- holy_en %>%
unnest_tokens(word, text) %>%
mutate(stem = SnowballC::wordStem(word, language = "en")) %>%
count(collection, era, word, stem) %>%
group_by(collection, era) %>%
mutate(pct = n/sum(n) * 100) %>%
ungroup() %>%
arrange(-pct) %>%
mutate(word = factor(word, levels = rev(unique(word))))
# bigram x era
bigram_era <- holy %>%
unnest_tokens(ngram, input = text, token = "ngrams", n = 2) %>%
count(era, ngram) %>%
group_by(era) %>%
mutate(pct = n/sum(n) * 100) %>%
ungroup() %>%
arrange(-pct) %>%
bind_tf_idf(term = ngram, document = era, n = n) %>%
mutate(ngram = factor(ngram, levels = rev(unique(ngram))))
# Create book numbers for Bible. For plotting some metrics by book number.
bib_book_no <- holy %>%
filter(collection == "Bibelen") %>%
distinct(book) %>%
mutate(bookno = row_number())
# words x stem x book/sura number
word_book <- holy %>%
left_join(bib_book_no) %>%
mutate(book_sura_no = coalesce(bookno, as.integer(chapter))) %>%
unnest_tokens(word, text) %>%
mutate(stem = SnowballC::wordStem(word, language = "da")) %>%
count(collection, book_sura_no, word, stem) %>%
group_by(collection, book_sura_no) %>%
mutate(pct = n/sum(n) * 100) %>%
ungroup() %>%
arrange(-pct) %>%
mutate(word = factor(word, levels = rev(unique(word))))
# Group text in verses
verses <- holy %>%
unite(doc_id, book, chapter, verse, remove = FALSE) %>%
group_by(doc_id) %>%
mutate(text = paste0(text, collapse = " ")) %>%
distinct(doc_id, .keep_all = TRUE) %>%
ungroup() %>%
mutate(nchar = nchar(text))
Lad os som eksempel se på en bid af én af disse tabeller. Den indeholder en særlige vægt, nemlig inverse document frequency, opfundet af Karen Spärck Jones.
Her er en bid af tabellen:
tfidf %>%
select(era, stem, n_total, n_doc, tf, idf, tf_idf) %>%
filter(tf_idf > 0) %>%
arrange(-n_total) %>%
mutate_if(is.numeric, round, digits = 3)
## # A tibble: 15,957 x 7
## era stem n_total n_doc tf idf tf_idf
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Medina allâh 2709 1689 0.066 0.693 0.046
## 2 Mekka allâh 2709 1020 0.024 0.693 0.017
## 3 Det Nye Testamente jesus 1067 1038 0.013 0.288 0.004
## 4 Medina jesus 1067 24 0.001 0.288 0
## 5 Mekka jesus 1067 5 0 0.288 0
## 6 Det Gamle Testamente israelit 802 789 0.003 0.288 0.001
## 7 Det Nye Testamente israelit 802 12 0 0.288 0
## 8 Mekka israelit 802 1 0 0.288 0
## 9 Det Gamle Testamente juda 758 708 0.003 0.693 0.002
## 10 Det Nye Testamente juda 758 50 0.001 0.693 0
## # … with 15,947 more rows
Hver række i tabellen repræsenterer én kombination af ordstamme og dokument. (Ordene er opdannet til små bogstaver og ordstamme, så “folk” og “folket” regnes for samme ord, ligesom “Landet” og “land” behandles ens.)
Første række i tabellen viser oplysninger om ordet “allâh” i dokumentet “Medina” (altså den del af Koranen, der omhandler åbenbaringer i Medina, ikke Mekka).
Kolonnerne i tabellen er som følger:
era: Teksten som ordstammen optræder i. Jeg har opdelt de to værker i fire tekster:
stem: Ordstammen
n_total: Hvor mange gange ordstammen optræder i alle teksterne. “Allâh” ses i alt 2.709 gange.
n_doc: Hvor mange gange ordstammen optræder i den specifikke tekst altså fx Medina-koranen. Her ses “allâh” 1.689 gange.
tf, term frequency: Hvor stor en andel ordstammen udgør ud af alle ordstammer i dokumentet. I Medina-koranen står “allâh” for 6,6 procent af alle ord.
idf, inverse document frequency, et mål for et ords sjældenhed, udregnet efter hvor mange dokumenter vi i alt arbejder med (her fire) og hvor mange dokumenter, ordet optræder i. Vi tager logaritmen til forholdet mellem de to. Fordi ordet “allâh” optræder i to af vores fire dokumenter (Medina- og Mekka-koranen) bliver \(idf_{allâh} = log{(\frac{4}{2})}\approx 0,693\). Et ord som “dåb” optræder kun i Bibelens Det Nye Testamente og får dermed en tungere vægt: \(idf_{dåb} = log{(\frac{4}{1})}\approx 1,386\). Omvendt, ord der optræder i alle fire tekster, som “herren”, får en vægt på nul og tæller derfor slet ikke med: \(idf_{herren} = log{(\frac{4}{4})} = 0\)
tf_idf: Er blot \(if \cdot idf\) Sagt på en anden måde: Ikke alle ord tæller lige meget; de sjældne ord bærer mere betydning og tælles derfor flere gange, mens de almindelige ord ignoreres.
Når vi har tabeller af denne type, er det let at foretage de optællinger, vi har lyst til.
Her er fx antal ord i alt, antal unikke (forskellige) ord samt den procentuelle fordeling af de to.
word_era %>%
group_by(era) %>%
summarise(n = sum(n),
n_distinct = n_distinct(word)) %>%
ungroup() %>%
mutate(pct_n = n / sum(n) * 100,
pct_distinct = n_distinct / sum(n_distinct) * 100) %>%
mutate_if(is.numeric, round, digits = 1)
## # A tibble: 4 x 5
## era n n_distinct pct_n pct_distinct
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Det Gamle Testamente 491318 17621 60.8 49.4
## 2 Det Nye Testamente 168634 8560 20.9 24
## 3 Medina 54999 4183 6.8 11.7
## 4 Mekka 92762 5320 11.5 14.9
Til sammenlingning antal ord i Harry Potter-serien, bind for bind, (den engelske version):
# Compare with Harry Potter
read_rds("../data/all_hp_books.rds") %>%
unnest_tokens(word, text) %>%
count(bookno)
## # A tibble: 7 x 2
## bookno n
## <int> <int>
## 1 1 77875
## 2 2 85401
## 3 3 105275
## 4 4 191882
## 5 5 258763
## 6 6 171284
## 7 7 198906
Hvis vi vil se på antal af unikke ord i Bibelen og Koranen, uden at dele op i Nye/Gamle Testamente og Mekka/Medina, kan det gøres sådan her:
word_era %>%
group_by(Bog = ifelse(str_detect(era, "Testamente"), "Bibelen", "Koranen")) %>%
summarise(n = sum(n),
n_distinct = n_distinct(word)) %>%
ungroup()
## # A tibble: 2 x 3
## Bog n n_distinct
## <chr> <int> <int>
## 1 Bibelen 659952 20684
## 2 Koranen 147761 6898
Bibelen har mange flere unikke ord, altså et større ordforråd, men er også meget længere, så noget af forskellen kan skyldes, at Bibelen har mere plads til at introducere nye ord i. En enkel måde at tage højde for forskelle i længden mellem Bibelen og Koranen, er ved blot at tage en tilfældig bid af Bibelen svarende til Koranens længde. Det giver selvfølgelig ikke præcist samme resultat hver gang, men tæt på.
# Experiment: Compare random sample of equal sizes:
holy %>%
unnest_tokens(word, text) %>%
group_by(Bog = ifelse(str_detect(era, "Testamente"), "Bibelen", "Koranen")) %>%
sample_n(147761) %>%
summarise(n = n(),
n_distinct = n_distinct(word)) %>%
ungroup()
## # A tibble: 2 x 3
## Bog n n_distinct
## <chr> <int> <int>
## 1 Bibelen 147761 11177
## 2 Koranen 147761 6898
En måde at se på, hvilke bøger/sura som har et vokabularium der adskiller sig fra de andre, er ved at tælle, hvor mange ord der kun optræder i den enkelte bog/sura. (“Sura” er de 114 kapitler som Koranen er delt op i.) Første Krønikebog stikker helt af, målt på denne måde.
unique_words <- word_book %>%
group_by(collection, book_sura_no, stem) %>%
summarise(n = sum(n)) %>%
group_by(stem) %>%
mutate(n_books = n()) %>%
filter(n_books == 1) %>%
ungroup() %>%
count(collection, book_sura_no) %>%
ungroup() %>%
left_join(mutate(bib_book_no, collection = "Bibelen", book_sura_no = bookno)) %>%
arrange(-n)
unique_words %>% select(collection, book, n_distinct = n)
## # A tibble: 166 x 3
## collection book n_distinct
## <chr> <chr> <int>
## 1 Bibelen Første Krønikebog 441
## 2 Bibelen Apostlenes Gerninger 275
## 3 Bibelen Fjerde Mosebog 267
## 4 Bibelen Første Mosebog 227
## 5 Bibelen Esajas' Bog 215
## 6 Bibelen Ezekiels Bog 189
## 7 Bibelen Josvabogen 171
## 8 Bibelen Jobs Bog 157
## 9 Bibelen Jeremias' Bog 151
## 10 Bibelen Salmernes Bog 146
## # … with 156 more rows
Ordskyer som den herunder er ret populære, fordi de har en vis visuel appel, men er egentlig ikke så gode til analyse, fordi det er lidt vilkårligt, hvordan ordene arrangeres og skaleres. Det er svært undersøge bestemte ordhyppigheder mere præcist i figurerr af denne type. På den anden side inviterer de ligesom til, at man leder efter interessante ord i “skyen”.
# Create corpus class
holy_corpus <- corpus(data.frame(verses),
docid_field = "doc_id",
text_field = "text")
# Create document-feature matrix
dfm <- dfm(holy_corpus,
remove = stopwords("da"),
remove_punct = TRUE,
remove_numbers = TRUE,
ngrams = 1:3)
dfm_stem <- dfm_wordstem(dfm, language = "da")
# Word cloud
dfm_col <- dfm(holy_corpus, groups = "collection",
remove = stopwords("da"),
remove_punct = TRUE,
remove_numbers = TRUE)
textplot_wordcloud(dfm_col, min_count = 10, random_order = FALSE,
rotation = .5,
min_size = 1,
color = RColorBrewer::brewer.pal(8, "Dark2"),
comparison = TRUE)
remove(dfm, dfm_col)
(Jeg har brugt R-pakken quantada til at danne ordskyen. Det er en formiddabel pakke til tekstanalyse. Se her.)
Her er nogle flere plot med almindelige ord:
# Most common words (no stemming)
word_era %>%
group_by(era) %>%
top_n(15, pct) %>%
ungroup() %>%
ggplot(aes(word, pct, fill = era)) +
geom_col(show.legend = FALSE) +
labs(x = NULL, y = "Procent") +
facet_wrap(~era, ncol = 2, scales = "free") +
coord_flip() +
labs(title = "Ordhyppigheder, alle ord, alle bøjningsformer",
subtitle = "Det er ikke særligt informativt blot at tælle alt. Uvigtige småord dominerer")
# Words with highest tf_idf (stemmed)
tfidf %>%
arrange(-tf_idf) %>%
mutate(label = capitalize(stem),
label = ifelse(stem != common_origin,
paste0(label, " (", common_origin, ")"),
label),
label = factor(label, levels = rev(unique(label)))) %>%
group_by(era) %>%
top_n(15, tf_idf) %>%
ungroup() %>%
ggplot(aes(label, tf_idf, fill = era)) +
geom_col(show.legend = FALSE) +
facet_wrap(~era, ncol = 2, scales = "free") +
coord_flip() +
scale_y_continuous(breaks = pretty_breaks(n = 3)) +
labs(x = NULL,
y = "Vægtet frekvens",
title = "Ordstammehyppigheder, vægtet efter inverse document frequency",
subtitle = "Metoden giver et mere sigende billede",
caption = "Grafen viser ordstammer. Hvor ordet forekommer i flere bøjningsformer, er den mest almindelige form vist i parentes")
# Export some data for plotting in datawrapper
tfidf_plot <- tfidf %>%
#filter(stem != "allâh") %>%
arrange(-tf_idf) %>%
mutate(label = capitalize(common_origin),
label = factor(label, levels = rev(unique(label)))) %>%
group_by(era) %>%
top_n(5, tf_idf) %>%
ungroup() %>%
select(label, era, tf_idf) %>%
arrange(era, -tf_idf)
tfidf_plot %>%
write_csv2("../output/tfidf_plot.csv")
# Bigrams with highest tf_idf (stemmed)
bigram_era %>%
arrange(-tf_idf) %>%
group_by(era) %>%
top_n(15, tf_idf) %>%
ungroup() %>%
ggplot(aes(ngram, tf_idf, fill = era)) +
geom_col(show.legend = FALSE) +
labs(x = NULL, y = "tf-idf") +
facet_wrap(~era, ncol = 2, scales = "free") +
coord_flip() +
scale_y_continuous(breaks = pretty_breaks(n = 3)) +
labs(x = NULL,
y = "Vægtet frekvens",
title = "Ordpar-hyppigheder, vægtet efter inverse document frequency",
subtitle = "Tilfører de hyppige ord en smule kontekst")
Man kan også se lidt nærmere på konteksten for særligt interessante ord; her 10 eksempler på brug af ordet sværd “sværd” og “straf”:
# Example of context
sword <- kwic(holy_corpus, pattern = c("sværd", "sværdet"))
punish <- kwic(holy_corpus, pattern = c("straf", "straffe", "straffen"))
head(sword, 10)
##
## [Første Mosebog_27_40, 3] Ved dit | sværd | skal du leve, og
## [Første Mosebog_34_25, 23] Dinas brødre, hver sit | sværd | og trængte uhindret ind i
## [Første Mosebog_34_26, 9] søn Sikem dræbte de med | sværd | , og så hentede de
## [Første Mosebog_48_22, 17] tog fra amoritterne med mit | sværd | og min bue.«
## [Anden Mosebog_5_3, 41] ramme os med pest eller | sværd | .«
## [Anden Mosebog_5_21, 31] og har givet dem et | sværd | i hånden, så de
## [Anden Mosebog_15_9, 23] dem; jeg trækker mit | sværd | , min hånd tilintetgør dem
## [Anden Mosebog_17_13, 5] Sådan besejrede Josva med | sværd | amalekitterne og deres hær.
## [Anden Mosebog_18_4, 20] og reddede mig fra Faraos | sværd | .«
## [Anden Mosebog_22_23, 13] og jeg dræber jer med | sværd | , så jeres koner bliver
head(punish, 10)
##
## [Første Mosebog_4_13, 8] til Herren:» Min | straf | er for stor at bære
## [Anden Mosebog_21_19, 12] ham, gå fri af | straf | , hvis den anden er
## [Anden Mosebog_21_28, 29] ejer skal gå fri af | straf | .
## [Anden Mosebog_32_34, 34] dag, da jeg vil | straffe | dem for deres synd.
## [Tredje Mosebog_5_1, 31] , skal han bære sin | straf | .
## [Tredje Mosebog_5_17, 29] skyld og må bære sin | straf | .
## [Tredje Mosebog_7_18, 45] det, må bære sin | straf | .
## [Tredje Mosebog_17_16, 15] , må han bære sin | straf | .
## [Tredje Mosebog_19_8, 10] det, må bære sin | straf | , for han har vanhelliget
## [Tredje Mosebog_20_17, 56] . Han skal bære sin | straf | .
Det er nemt at se nærmere på statistikken for udvalgte ord. Her er nogle af de ord, der i figuren over idf-vægtet ordstamme-hyppighed, stak ud som særligt sigende. Vi ser fx at ordstammen “døb”, hyppigst kommmer fra ordet “døber” som optræder 52 gange i Det Nye Testamente (og kun der).
# Check selected words
selected_stems <- c("Sværd", "Tempel", "Præst", "Ypperstepræst",
"Helligånd", "Døb", "Allâh", "O", "Troen",
"Jesus", "Kong")
tfidf %>%
filter(stem %in% tolower(selected_stems)) %>%
select(era, stem, common_origin, n_total, tf_idf) %>%
arrange(stem, era) %>%
mutate_if(is.numeric, round, digits = 3) %>%
data.frame()
## era stem common_origin n_total tf_idf
## 1 Medina allâh allâh 2709 0.046
## 2 Mekka allâh allâh 2709 0.017
## 3 Det Nye Testamente døb døber 52 0.001
## 4 Det Nye Testamente helligånd helligånden 89 0.002
## 5 Det Nye Testamente jesus jesus 1067 0.004
## 6 Medina jesus jesus 1067 0.000
## 7 Mekka jesus jesus 1067 0.000
## 8 Det Gamle Testamente kong konge 2697 0.000
## 9 Det Nye Testamente kong konge 2697 0.000
## 10 Medina kong konge 2697 0.000
## 11 Mekka kong konge 2697 0.000
## 12 Det Nye Testamente o o 350 0.000
## 13 Medina o o 350 0.002
## 14 Mekka o o 350 0.001
## 15 Det Gamle Testamente præst præsten 735 0.001
## 16 Det Nye Testamente præst præsten 735 0.000
## 17 Medina præst præsten 735 0.000
## 18 Det Gamle Testamente sværd sværd 432 0.001
## 19 Det Nye Testamente sværd sværd 432 0.000
## 20 Det Gamle Testamente tempel tempel 330 0.001
## 21 Det Nye Testamente tempel tempel 330 0.000
## 22 Det Nye Testamente troen troen 489 0.000
## 23 Medina troen troen 489 0.003
## 24 Mekka troen troen 489 0.001
## 25 Det Gamle Testamente ypperstepræst ypperstepræsterne 156 0.000
## 26 Det Nye Testamente ypperstepræst ypperstepræsterne 156 0.001
Zipf’s lov er interessant. Den siger, at et ords hyppighed er omvendt proportional med ordets plads, når ordene rangordnes efter hyppighed. Hvis det hyppigste ord fx forekommer som 1 procent af alle ord, kan det forventes, at det næsthyppigste ord forekommer ½ procent af gangene og så fremdeles. Det sjove er, at lovmæssigheden gælder for næsten en hvilken som helst tekst.
Den nemmeste måde at se dette i praksis på, er ved at plotte ordene efter rangorden og frekvens i et dobbelt logaritmisk koordinatsystem.
theme_set(theme_minimal())
word_era %>%
group_by(era) %>%
mutate(rank = row_number()) %>%
ungroup() %>%
ggplot(aes(rank, pct, color = era)) +
geom_line(size = 1.1, alpha = 0.8) +
scale_x_log10() +
scale_y_log10() +
labs(x = "Rang (log-skala)",
y = "Procent (log-skala)",
title = "Alle fire tekster følger nogenlunde Zipf's lov",
subtitle = "Ord plottet efter rangordning og hyppighed") +
theme(legend.title = element_blank())
Hvis vi leder mere grundigt efter ord relateret fx til enten vold eller kærlighed, opstår et interessant mønster: Mest vold i Bibelen, mest kærlighed i Koranen. En svaghed ved denne optælling er, at jeg ikke fandt nogen god, objektiv, statistisk måde at vælge de to grupper af ord på, så i sidste ende blev det et subjektivt valg, hvilke ord der er voldsorienterede, og hvilke der er kærlighedsorienterede. (De præcise lister fremgår af koden.)
# Violence related stems (list compiled subjectively):
violence <- c("sværd", "våb", "krig", "krigsbyt", "kamp", "kampråb",
"vold", "voldsmænd", "hævn", "slå", "slået", "drab", "dræb",
"mord", "blod", "blodskyld", "blodhævn", "død", "dø", "ihjel",
"fjend", "ødelæg", "tilintetgør", "soldat", "hær", "hærskar")
violence_terms <- word_era %>%
filter(stem %in% violence) %>%
distinct(word) %>%
pull(word) %>%
as.character()
# Love related stems
love <- c("kær", "tilgiv", "omsorg", "beskyt", "hjælp", "støt",
"trøst", "troskab", "elsk")
love_terms <- word_era %>%
filter(stem %in% love) %>%
distinct(word) %>%
pull(word) %>%
as.character()
# The tidy text way: word counts by era
love_table <- word_era %>%
mutate(violence = stem %in% violence,
love = stem %in% love) %>%
group_by(era, violence, love) %>%
summarise(n = sum(n)) %>%
gather(dict, value, violence, love) %>%
group_by(era) %>%
mutate(pct = n / sum(n) * 100) %>%
ungroup() %>%
filter(value)
# Chart
love_table %>%
ggplot(aes(x = era, y = pct, fill = dict)) +
geom_col() +
coord_flip() +
scale_fill_discrete(breaks = c("love", "violence"),
labels = c("Kærlighed", "Krig/vold")) +
labs(title = "Forekomst af ord relateret til krig/vold og til kærlighed",
y = "Procent",
x = NULL) +
theme(legend.title = element_blank())
# Output for datawrapper
love_table %>% select(era, dict, pct) %>%
spread(dict, pct) %>%
mutate(era = str_replace(era, "Medina", "Koranen (Medina)")) %>%
mutate(era = str_replace(era, "Mekka", "Koranen (Mekka)")) %>%
rename(Vold = violence, `Kærlighed` = love) %>%
write_csv2("../output/love_chart.csv")
# Most common love/violence words by era
special_words <- word_era %>%
mutate(violence = stem %in% violence,
love = stem %in% love) %>%
filter(violence|love) %>%
group_by(era, violence, love) %>%
top_n(5, n) %>%
ungroup() %>%
arrange(violence, love, era, -n)
De to tabeller herunder viser de hyppigste ord relateret til henholdsvis vold og kærlighed. Denne gang har jeg dannet tabeller, hvor hver række repræsenterer én kombination af dokument/ord/ordstamme. Så kan vi se eksempler på dannelsen af ordstammer (som jeg har brugt algoritmen fra SnowballC::wordStem() til). Ordstammen “død”, ses fx i tabellen afledt af tre forskellige former: død, døde og døden.
special_words %>%
filter(violence) %>%
select(-violence, -love) %>%
mutate_if(is.numeric, round, digits = 3) %>%
head(10)
## # A tibble: 10 x 5
## era word stem n pct
## <chr> <fct> <chr> <dbl> <dbl>
## 1 Det Gamle Testamente hærskarers hærskar 282 0.057
## 2 Det Gamle Testamente sværd sværd 236 0.048
## 3 Det Gamle Testamente fjender fjend 230 0.047
## 4 Det Gamle Testamente døde død 223 0.045
## 5 Det Gamle Testamente blod blod 214 0.044
## 6 Det Nye Testamente døde død 160 0.095
## 7 Det Nye Testamente død død 93 0.055
## 8 Det Nye Testamente blod blod 89 0.053
## 9 Det Nye Testamente døden død 73 0.043
## 10 Det Nye Testamente ihjel ihjel 68 0.04
special_words %>%
filter(love) %>%
select(-violence, -love) %>%
mutate_if(is.numeric, round, digits = 3) %>%
head(10)
## # A tibble: 10 x 5
## era word stem n pct
## <chr> <fct> <chr> <dbl> <dbl>
## 1 Det Gamle Testamente hjælp hjælp 146 0.03
## 2 Det Gamle Testamente elsker elsk 122 0.025
## 3 Det Gamle Testamente troskab troskab 82 0.017
## 4 Det Gamle Testamente hjælpe hjælp 39 0.008
## 5 Det Gamle Testamente hjælper hjælp 29 0.006
## 6 Det Nye Testamente kærlighed kær 100 0.059
## 7 Det Nye Testamente elsker elsk 63 0.037
## 8 Det Nye Testamente kære kær 56 0.033
## 9 Det Nye Testamente hjælp hjælp 43 0.025
## 10 Det Nye Testamente elske elsk 40 0.024
Den nemmeste måde at få et indtryk af, hvilke af teksterne der er mest påskrivende, er at se på forkomsten af ord og ordpar som “skal”, “du skal” og “må ikke”.
Her ser vi først en liste over de fem hyppigste ordpar, fra hver tekst, som indeholder ordet “skal”:
bigram_era %>%
filter(str_detect(ngram, "skal")) %>%
group_by(era) %>%
top_n(5, pct) %>%
ungroup() %>%
arrange(era, -pct)
## # A tibble: 20 x 7
## era ngram n pct tf idf tf_idf
## <chr> <fct> <int> <dbl> <dbl> <dbl> <dbl>
## 1 Det Gamle Testamente du skal 649 0.139 0.00139 0 0
## 2 Det Gamle Testamente skal du 568 0.121 0.00121 0 0
## 3 Det Gamle Testamente de skal 438 0.0936 0.000936 0 0
## 4 Det Gamle Testamente skal i 409 0.0874 0.000874 0 0
## 5 Det Gamle Testamente skal være 340 0.0726 0.000726 0 0
## 6 Det Nye Testamente skal i 122 0.0759 0.000759 0 0
## 7 Det Nye Testamente i skal 119 0.0741 0.000741 0 0
## 8 Det Nye Testamente de skal 82 0.0510 0.000510 0 0
## 9 Det Nye Testamente skal være 79 0.0492 0.000492 0 0
## 10 Det Nye Testamente ikke skal 75 0.0467 0.000467 0 0
## 11 Medina skal de 50 0.0936 0.000936 0 0
## 12 Medina skal i 43 0.0805 0.000805 0 0
## 13 Medina deri skal 37 0.0693 0.000693 0.693 0.000480
## 14 Medina de skal 36 0.0674 0.000674 0 0
## 15 Medina i skal 32 0.0599 0.000599 0 0
## 16 Mekka skal de 38 0.0431 0.000431 0 0
## 17 Mekka skal i 33 0.0375 0.000375 0 0
## 18 Mekka skal være 28 0.0318 0.000318 0 0
## 19 Mekka deri skal 26 0.0295 0.000295 0.693 0.000205
## 20 Mekka de skal 22 0.0250 0.000250 0 0
Her er forekomsten af ordparret “må ikke”. Det forekommer langt hyppigere i Bibelen, især i Det Gamle Testamente.
bigram_era %>%
filter(str_detect(ngram, "må ikke"))
## # A tibble: 4 x 7
## era ngram n pct tf idf tf_idf
## <chr> <fct> <int> <dbl> <dbl> <dbl> <dbl>
## 1 Det Gamle Testamente må ikke 401 0.0857 0.000857 0 0
## 2 Det Nye Testamente må ikke 52 0.0324 0.000324 0 0
## 3 Medina må ikke 4 0.00749 0.0000749 0 0
## 4 Mekka må ikke 1 0.00114 0.0000114 0 0
Eftersom brugen af ordet “skal” oftest sker i formen “du skal” og “skal du”, giver det mening blot at tælle det ord, som et groft udtryk for, hvor imperative teksterne er. Eller vi kan se på ordparret “må ikke”.
word_era %>%
filter(word == "skal") %>%
group_by(era, word) %>%
summarise(pct = sum(pct)) %>%
ggplot(aes(era, pct)) +
geom_col() +
coord_flip() +
labs(title = "Bibelen har klart flest påbud i form af ordet 'skal'",
y = "Ordet 'skal' i procent",
x = NULL)
bigram_era %>%
filter(ngram == "må ikke") %>%
group_by(era, ngram) %>%
summarise(pct = sum(pct)) %>%
ungroup() %>%
ggplot(aes(era, pct)) +
geom_col() +
coord_flip() +
labs(title = "Bibelen har klart flest forbud i form af 'må ikke'",
y = "Ordparret 'må ikke' i procent af alle ordpar",
x = NULL)
Lidt flere optællinger af interessante ord, som vi er stødt på undervejs. Én bestemt bog i Bibelen har fx en stærk forkærlighed for ordet “møggud”. (Vi undersøger her alle bøjningsformerne.)
word_book %>%
filter(stem == "møggud") %>%
left_join(bib_book_no, by = c("book_sura_no" = "bookno")) %>%
mutate_if(is.numeric, round, digits = 3)
## # A tibble: 9 x 7
## collection book_sura_no word stem n pct book
## <chr> <dbl> <fct> <chr> <dbl> <dbl> <chr>
## 1 Bibelen 26 møgguder møggud 36 0.117 Ezekiels Bog
## 2 Bibelen 12 møgguder møggud 2 0.011 Anden Kongebog
## 3 Bibelen 12 møgguderne møggud 2 0.011 Anden Kongebog
## 4 Bibelen 26 møgguderne møggud 3 0.01 Ezekiels Bog
## 5 Bibelen 3 møgguder møggud 1 0.005 Tredje Mosebog
## 6 Bibelen 11 møgguder møggud 1 0.005 Første Kongebog
## 7 Bibelen 11 møgguderne møggud 1 0.005 Første Kongebog
## 8 Bibelen 5 møgguder møggud 1 0.004 Femte Mosebog
## 9 Bibelen 24 møgguderne møggud 1 0.003 Jeremias' Bog
Et centralt, religiøst ord som “tilgivelse” forekommer langt hyppigst i Koranen. (Vi finder ordstammen “tilgiv” og tæller alle bøjningsformerne):
# Tilgivelse
word_era %>%
filter(stem == "tilgiv") %>%
group_by(era, stem) %>%
summarise(n = sum(n), pct = sum(pct)) %>%
mutate_if(is.numeric, round, digits = 3)
## # A tibble: 4 x 4
## # Groups: era [4]
## era stem n pct
## <chr> <chr> <dbl> <dbl>
## 1 Det Gamle Testamente tilgiv 75 0.015
## 2 Det Nye Testamente tilgiv 58 0.034
## 3 Medina tilgiv 154 0.28
## 4 Mekka tilgiv 105 0.113
Ordet “bryst” forekommer hyppigst i Højsangen i Bibelen som er ret erotisk. Ordet også i nogle af Koranens suraer, fx i nummer 94. Her kommer den relative hyppighed, i procent af kapitles ord, til at virke uforholdsmæssig høj, fordi det er et kort kapitel. (Ordet bruges iøvrigt ikke i en erotisk betydning her.)
word_book %>%
filter(stem == "bryst") %>%
group_by(book_sura_no, stem) %>%
summarise(n = sum(n), pct = sum(pct)) %>%
left_join(bib_book_no, by = c("book_sura_no" = "bookno")) %>%
arrange(-pct) %>%
mutate_if(is.numeric, round, digits = 3)
## # A tibble: 24 x 5
## # Groups: book_sura_no [24]
## book_sura_no stem n pct book
## <int> <chr> <dbl> <dbl> <chr>
## 1 94 bryst 1 1.61 <NA>
## 2 22 bryst 9 0.405 Højsangen
## 3 25 bryst 3 0.11 Klagesangene
## 4 34 bryst 1 0.103 Nahums Bog
## 5 28 bryst 3 0.072 Hoseas' Bog
## 6 20 bryst 2 0.044 Ordsprogenes Bog
## 7 33 bryst 1 0.041 Mikas Bog
## 8 6 bryst 2 0.034 Josvabogen
## 9 18 bryst 5 0.032 Jobs Bog
## 10 16 bryst 1 0.029 Nehemias' Bog
## # … with 14 more rows
En mere systematisk måde at indfange tonen eller “ladningen” i en tekst, er ved at bruge sentiment analyse, som grundlæggende slår ordene op i en tabel, som rummer værdier for, hvorvidt ordet er positivt eller negativt ladet. Værdierne er dannet ved hjælp af en statisisk model, og altås ikke et rent subjektivt valg. Her bruger vi AFINN, udviklet af Finn Årup Nielsen.
Denne gang bruger vi de engelske versioner, da jeg ikke kunne finde AFINN i en dansk verison, som jeg umiddelbart kunne bruge.
Her er en stikprøve fra AFINN med eksempler på værdier. Negative tal betyder at et ord er negativt ladet, positive tal … gæt selv.
word_era_en_sent <- word_era_en %>%
left_join(get_sentiments("afinn"))
# Examples
word_era_en_sent %>%
select(word, value) %>%
filter(!is.na(value)) %>%
sample_n(10)
## # A tibble: 10 x 2
## word value
## <chr> <dbl>
## 1 enemy -2
## 2 jewels 1
## 3 granted 1
## 4 peace 2
## 5 committed 1
## 6 greatest 3
## 7 kill -3
## 8 retreat -1
## 9 smart 1
## 10 guilt -3
Et lille problem er, at “God” og “Jesus” er positivt ladede, og da de to ord i sagens natur er overrepræsenterede i Bibelen, skævrider de billedet lidt. Derfor sorterer vi dem fra.
get_sentiments("afinn") %>% filter(word %in% c("god", "jesus"))
## # A tibble: 2 x 2
## word value
## <chr> <dbl>
## 1 god 1
## 2 jesus 1
Sentimentanalysen herunder er simpelthen gennemsnitlige ladninger fra de fire tekster. Det Gamle Testamente lader til at være klart mest negativt ladet, Det Nye Testamente mest positivt.
word_era_en_sent %>%
filter(!is.na(value)) %>%
# Since "god" and "jesus" has positive sentiment, we exclude this
filter(!word %in% c("god", "jesus")) %>%
group_by(era) %>%
summarise(sentiment = sum(n * value) / sum(n))
## # A tibble: 4 x 2
## era sentiment
## <chr> <dbl>
## 1 Medina -0.0572
## 2 Mekka -0.0455
## 3 New Testament 0.284
## 4 Old Testament -0.106
Topfem eksempler på ord fra de fire tekster, der især bidrager med positiv ladning til sentiment-analysen:
# Examples of words that contribute the most to sentiment
word_era_en_sent %>%
filter(!is.na(value)) %>%
# Since "god" and "jesus" has positive sentiment, we exclude this
filter(!word %in% c("god", "jesus")) %>%
group_by(era, word) %>%
summarise(sentiment_sum = sum(n * value)) %>%
group_by(era) %>%
top_n(5, sentiment_sum) %>%
arrange(era, -sentiment_sum)
## # A tibble: 20 x 3
## # Groups: era [4]
## era word sentiment_sum
## <chr> <chr> <dbl>
## 1 Medina good 351
## 2 Medina faith 177
## 3 Medina best 138
## 4 Medina reward 126
## 5 Medina great 105
## 6 Mekka good 483
## 7 Mekka best 324
## 8 Mekka mercy 232
## 9 Mekka like 222
## 10 Mekka reward 190
## 11 New Testament great 762
## 12 New Testament good 744
## 13 New Testament love 537
## 14 New Testament heaven 510
## 15 New Testament glory 354
## 16 Old Testament great 2124
## 17 Old Testament good 1416
## 18 Old Testament like 1150
## 19 Old Testament praise 660
## 20 Old Testament heaven 654
Lidt mere kompliceret er det at finde ordklasser, altså hvorvidt et ord er et substantiv, et verbum etc. Til det formål bruger vi pakken OpenNLP, der indeholder en dansk algoritme til formålet.
# # Get tagset with descriptions
tagset <- read_delim("../data/tagset for Danish.txt", delim = "\t", skip = 2)
# Set annotators for danish
sent_token_annotator <- Maxent_Sent_Token_Annotator(language = "da")
word_token_annotator <- Maxent_Word_Token_Annotator(language = "da")
pos_tag_annotator <- Maxent_POS_Tag_Annotator(language = "da")
# Function to annotate text and aggregates POS counts:
pos_count <- function (s, f) {
# To avoid memory issues when annotating a large text,
# this function will aggregate annotation to counts
# of part-of-speech (word classes)
pc <- NLP::annotate(s, f) %>%
as.data.frame() %>%
unnest() %>%
filter(type == "word") %>%
mutate(Tag = as.character(features)) %>%
filter(Tag != "XP") %>% # Ignore punctuation tags
count(Tag)
return(pc)
}
# We create count of pos-values in smaller chunks to avoid
# running out of memory
pos_stat <- holy %>%
mutate(id = paste(era, book, sep = "_")) %>%
split(.$id) %>%
map(~ pos_count(.$text, list(sent_token_annotator,
word_token_annotator,
pos_tag_annotator)))
# Combine the df's and aggregate to the level we want:
pos_stat <- pos_stat %>%
bind_rows(pos_stat, .id = "id") %>%
separate(id, into = c("era", "book"), sep = "_") %>%
group_by(era, Tag) %>%
summarise(n = sum(n)) %>%
group_by(era) %>%
mutate(pct = n / sum(n) * 100) %>%
ungroup() %>%
left_join(select(tagset, Tag, Danish, Description))
# Plot the result
pos_stat %>%
ungroup() %>%
arrange(-pct) %>%
mutate(Danish = factor(Danish, levels = rev(unique(Danish)))) %>%
ggplot(aes(x = Danish, y = pct, color = era, group = era)) +
geom_point() +
geom_line() +
labs(title = "Det Gamle Testamente: Mange navneord og egennavne",
subtitle = "Fordelingen af ordklasser i procent",
x = NULL, y = "Procent") +
coord_flip() +
theme(legend.title = element_blank())
En interessant øvelse er, at finde sætninger fra Bibelen og Koranen som minder om hinanden. Kan man finde helt eller næsten identiske sætninger i de to bøger?
Tabellen herunder er skabt ved:
# We tokenize by sentences like this: First collapse text into
# two big character stringa, then split up by sentences with tokens()
holy_sents <- holy %>%
group_by(collection = if_else(str_detect(era, "Testament"), "Bibelen", "Koranen")) %>%
summarise(text = paste(text, collapse = " ")) %>%
corpus(text_field = "text", docid_field = "collection") %>%
tokens(what = "sentence") %>%
unlist() %>%
tibble(text = ., collection = names(.)) %>%
mutate(id = row_number(),
collection = str_extract(collection, "[:alpha:]+"))
# Convert sentences to dfm
holy_dfm <- holy_sents %>%
corpus(text_field = "text", docid_field = "id") %>%
dfm(remove = stopwords("danish"), remove_punct = TRUE) %>%
dfm_wordstem(language = "danish") %>%
dfm_trim(min_termfreq = 2) %>%
dfm_tfidf()
# Subset rows: Only consider sentences with at least X terms
holy_dfm <- holy_dfm %>% dfm_subset(rowSums(holy_dfm != 0) >= 11)
# Find similar sentences, using cosine similarity and tfidf
holy_simil <- textstat_simil(holy_dfm, method = "cosine", min_simil = 0.4)
# Convert to symetrical matrix and remove redundant triangle (and diagonal)
holy_simil_m <- as.matrix(holy_simil)
holy_simil_m[lower.tri(holy_simil_m, diag = TRUE)] <- NA
# Line up as a long df, joined with actual sentences
holy_simil_df <- holy_simil_m %>%
reshape2::melt(value.name = "cosine") %>%
as_tibble() %>%
filter(!is.na(cosine)) %>%
arrange(-cosine) %>%
left_join(holy_sents, by = c("Var1" = "id")) %>%
left_join(holy_sents, by = c("Var2" = "id"), suffix = c("1", "2"))
# We want to look at similar sentences *between* the two books
similar_sentences <- holy_simil_df %>%
filter(collection1 != collection2)
# Housekeeping: This one takes up a lot of memory, so remove
remove(holy_simil_m)
similar_sentences %>%
head(5) %>%
select(-starts_with("Var")) %>%
knitr::kable(digits = 2) %>%
kableExtra::kable_styling(bootstrap_options = "striped", full_width = F) %>%
column_spec(2, width = "30em") %>%
column_spec(4, width = "30em")
| cosine | text1 | collection1 | text2 | collection2 |
|---|---|---|---|---|
| 0.62 | Den fjerde engel blæste i sin basun, og en tredjedel af solen og en tredjedel af månen og en tredjedel af stjernerne blev ramt, så en tredjedel af dem formørkedes, og dagen mistede en tredjedel af sit lys og natten ligeså. | Bibelen | Din Herre ved bestemt at du, og en del af dem der er med dig, står op (i bøn) hen ved to tredjedele af natten, halvdelen af den eller en tredjedel af den. | Koranen |
| 0.59 | Deraf kan vi vide, at vi er af sandheden, og over for ham kan vi bringe vort hjerte til ro, hvad end vort hjerte fordømmer os for; thi Gud er større end vort hjerte og kender alt. | Bibelen | De sagde: "Vi ønsker at spise deraf, så vort hjerte kan finde ro, og for at vi kan vide at du har fortalt os sandheden, så vi kan være vidner derpå. | Koranen |
| 0.56 | Sådan skal I gøre: Den tredjedel af jer, de præster og levitter, der kommer på sabbatten, skal være portvagter; den anden tredjedel skal være i kongens palads og den sidste tredjedel ved Jesod-porten, mens hele folkemængden skal være i forgårdene til Herrens tempel. | Bibelen | Din Herre ved bestemt at du, og en del af dem der er med dig, står op (i bøn) hen ved to tredjedele af natten, halvdelen af den eller en tredjedel af den. | Koranen |
| 0.54 | Forordning om sabbatten Herren sagde til Moses: Sig til israelitterne: I skal holde mine sabbatter, for sabbatten er et tegn mellem mig og jer, slægt efter slægt, for at I skal vide, at det er mig, Herren, som helliger jer. | Bibelen | Spørg dem om byen der lå ved havet, da de begik overtrædelser på sabbatten: da deres fisk kom til dem i synlige stimer på sabbatten, mens de ikke kom den dag hvor de ikke holdt sabbat. | Koranen |
| 0.52 | En tredjedel skal dø af pest eller omkomme af sult i dig; en tredjedel skal falde for sværd rundt om dig; en tredjedel vil jeg sprede for alle vinde, og dem vil jeg forfølge med draget sværd. | Bibelen | Din Herre ved bestemt at du, og en del af dem der er med dig, står op (i bøn) hen ved to tredjedele af natten, halvdelen af den eller en tredjedel af den. | Koranen |
Som vi kan se, kan vi ikke finde sætninger af denne længde, som minder ret meget om hinanden på tværs af Bibelen og Koranen. De største ligheder opstår, når to sætninger deler sjældne ord som “tredjedel”.
Det er dog værd at bemærke, at begrebet “sabbat”, som mange nok mest forbinder med jødedommen, både optræder i den kristne og muslimske tekst.
En sidste form for sproglig lighed vi undersøger, er på ordniveau, idet vi bruger den berømte word2vec metode. Ideen er at repræsentere hvert ord som en vektor udledt af, hvor ofte forskellige ord optræder sammen. Til det formål bruger vi en såkaldt feature co-occurence-matrix, fcm, som viser, hvor ofte hvert ord optræder i samme kontekst som andre ord.
Ideen er, at vektor-repræsentationen af ord kan have nogle nyttige egenskaber, som for eksempel at ord som har sematisk lighed, ligger relativt tæt på hinanden i ordvektor-rummet.
Normalt ville man foretrække et større korpus end Bibelen og Koranen, men for eksemplets skyld udleder vi her ordvektorer udelukkende på baggrund af disse to bøger.
Det lader til at give en vis mening; tabellen herunder viser hvilke ord, der ligger “tæt” på hinanden, når man bruger ordvektor-modellen.
Man bidder mærke i nogle oplagte ligheder: “gud” minder om “herren”, “jesu” minder om “kristi”, for eksempel. Der er også nogle knap så oplagte, som at “venstre” og “højre” er semantisk relaterede.
Den sidste tabel viser hvilke ord, der er tættest relateret til ordet “Gud”. Man kan blandet andet se, at Gud er ret snakkesagelig og godt kan lide at forklare ting. Ordene “siger” og “derfor” er semantisk relateret til “gud”.
related <- textstat_simil(holy_vectors, margin = "documents",
method = "cosine", min_simil = 0.3)
most_related <- related %>%
data.frame() %>%
as_tibble() %>%
arrange(-cosine)
most_related %>% head(30)
## # A tibble: 30 x 3
## document1 document2 cosine
## <fct> <fct> <dbl>
## 1 fornægter troen 0.914
## 2 venstre højre 0.829
## 3 dette siger 0.822
## 4 gud herren 0.806
## 5 ikke men 0.788
## 6 sagde svarede 0.785
## 7 jesu kristi 0.780
## 8 men hvis 0.769
## 9 sagde da 0.762
## 10 så men 0.758
## # … with 20 more rows
most_related %>% filter(document1 == "gud") %>% head(10)
## # A tibble: 10 x 3
## document1 document2 cosine
## <fct> <fct> <dbl>
## 1 gud herren 0.806
## 2 gud herre 0.707
## 3 gud derfor 0.645
## 4 gud siger 0.631
## 5 gud du 0.625
## 6 gud jeg 0.605
## 7 gud israels 0.604
## 8 gud har 0.604
## 9 gud din 0.599
## 10 gud dig 0.595
Efter således at have brugt statistiske teknikker fra Natural Language Processing til at blive klogere på Gud, er det på tide at takke af.
Men der er naturligvis mange flere muligheder for analyser; her har vi blot kradset i overfladen. Forhåbentlig kan disse eksempler og kode-stumper være med til at inspirere andre til at grave dybere i de hellige tekster – med analyse.
Hvis du har spørgsmål, forslag, rettelser eller kommentarer, er du mere end velkommen til at bruge projektets repository, for eksempel til at oprette et issue eller en pull request.