10  Algoritmisk klassifikation af tekst med naive bayes

Dette kapitel præsenterer et eksperiment i at bygge en såkaldt naive bayes classifier - en algoritme, der kan klassificere tekst. Casen handler om at bestemme kønnet på efterlyste personer i 1700-tals avisannoncer. Det var en ganske almindelig praksis at efterlyse ens tyende, soldater eller arrestanter, der var løbet bort. Et sample på 925 sådanne efterlysninger fra de sidste to årtier af 1700-tallet udgør datagrundlaget. Dataene stammer fra avisen Københavns Alene Privilegerede Adressekontors Efterretninger - en såkaldt “adresseavis”, der i nogle henseender fungerede som et tidligt socialt medie for de øvre lag af det københavnske bysamfund. Dataene er skabt af Anders Dyrborg Birkemose. Den afprøvede tekstkategoriseringsalgoritme er relativt simpel. Fordelen herved er, at den let kan køres fra en ganske almindelig pc - og at den uden stort besvær kan benyttes på andre datasæt af andre forskere eller studerende. Desuden er den faktisk også ganske effektiv.

Øvelsen med at få en algoritme til at genkende kategorier på baggrund af rå tekst er åbenlyst nyttig i tilfælde, hvor vi er interesserede i at kunne kategorisere store mængder af tekststykker - men er begrænsede af tid, penge og/eller evnen til at fokusere på en monoton opgave. Hvis vores kategorier er entydige og tydeligt tilstede i selve vores tekstdata (i modsætning til egenskaber vi deducerer med udgangspunkt i domæneviden eller læser mellem linjer), burde vi kunne skabe en simpel model med en meningsfuld præcision. Med en trænet algoritme kan vi kategorisere så meget data, vi har (brug for).

Imidlertid er metoden måske mest interessant, når den fejler. I en nylig artikel har Anders Kristian Munk, Asger Gehrt Olesen og Mathieu Jacomy beskrevet potentialerne i at benytte kunstige intelligensers fejlkategoriseringer heuristisk til at “tykne” vores forståelse af kulturelle processer.1 Jill Walker Rettberg har, inspireret af Munk, Olesen og Jacomy, lavet et tilsvarende argument og beskrevet hvordan: “Algorithmic failure uses the mispredictions of machine learning to identify cases that are of interest for qualitative research.”2 For historikere, der husker de italienske mikrohistorikeres ide om den “normale undtagelse” - ekstraordinære kilder, der fortæller om både normalitet og afvigelse - synes denne metode særligt lovende.

Denne notebook er skrevet med henblik på studerende / begyndere. Den forsøger at holde sig til en begrænset mængde af pakker og at benytte så veldokumenterede funktioner som muligt. I praksis vil en højere præcision kunne etableres ved hjælp af mere avancerede, men også besværlige teknikker.

10.1 Setup

Først loades pakker.

library(tidyverse) 
library(readxl) 
library(tidymodels)

Herefter loades data. Du kan hente de to datasæt her. Det forudsættes at disse ligger i en mappe kaldet “data” i roden af dit projekt. Altså samme sted som din notebook eller dit script. Som et ekstra setup-element gøres datasættets kolonne “Gender” til en faktor. Dette er nødvendigt for det videre forløb.

avis_samples <- read_excel("data/sample.xlsx")
stopord <- read_excel("data/stopord2.xlsx") 
avis_samples$Gender <- as.factor(avis_samples$Gender) 
head(avis_samples)
# A tibble: 6 × 3
  ID    Gender Text                                                             
  <chr> <fct>  <chr>                                                            
1 ID-1  M      Da Jørgen Jensen, fød i Rønne paa Bornholm, der som kok var forh…
2 ID-2  F      Da min Tienestepige, navnlig Jacobine, uden Aarsag er bortgaaet;…
3 ID-3  F      Da en Pige haver fæstet sig i min Tieneste, og leveret mig hende…
4 ID-4  M      Da min Læredreng, navnlig Peter Ridel, er i Søndags Middag undvi…
5 ID-5  M      Da 2 svenske Drenge, den eene John, 16 Aar, undersætsig, klædt i…
6 ID-6  F      Den 30 December er Margarete Rebecca M. hemmelig undvigt fra hen…

Dataene indeholder tre kolonner: Et Id, en kolonne, der angiver det kategoriserede køn og den fulde tekst. For at kunne måle præcisionen af vores algoritme, kan vi ikke bruge alle 925 annoncer til at træne algoritmen. Vi må holde en reserve af manuelt kategoriseret data tilbage til at teste modellen efter træning. Vi splitter derfor datasættet i to: træningsdata og testdata:

avis_split <- initial_split(avis_samples, strata = Gender) # Som default splitter initial_split() med proportionen 3/4
avis_train <- training(avis_split) 
avis_test <- testing(avis_split)

10.2 Træning af model

Næste skridt er at preppe selve teksten. I udgangspunktet har maskinlæringsalgoritmer altid brug for at forstå tekstdata som kvantificerede data. For at nå til et format, der giver mening for den teknik, der bruges her, definerer vi en opskrift for, hvordan teksterne omformes til talværdier. Opskriften indeholder følgende elementer:

  • Vi tokeniserer - altså opdeler - på ordniveau.

  • Vi fjerner stopord fra den manuelle stopordsliste, vi loadede ind tidligere.

  • Vi filtrerer, så vi kun beholder de 1000 mest hyppige ord. Den mest nyttige tærskel vil variere afhængigt af data.

  • Vi udregner en term-frequency, hvor vægtningen er binær. Det betyder at hvert ord er noteret med 0 hvis det ikke er tilstede og med 1 hvis det er tilstede, men at antallet af optrædener ikke er angivet.

  • Vi bruger denne struktur som udgangspunkt for en såkaldt PCA (principal components analysis), der reducerer antallet af dimensioner i data. Dette gøres fordi vores algoritme ikke kan håndtere den store mængde af forskellige ord, der nu optræder som kolonner, der skal bruges til at forudsige kønnet (“features”), men lettere kan forholde sig til disse, hvis de reduceres til et overskueligt antal “dimensioner”. I denne proces går noget af kompleksiteten i vores data tabt, imod at dataene bliver håndterbare for algoritmen. I andre kontekster er dette skridt måske ikke nødvendigt. Antallet af dimensioner, der er nyttige at bevare, vil variere afhængigt af data.

I mange kontekster ville det have været nyttigt at standardisere teksterne yderligere f.eks. ved at opstamme ord, så variationer i endelser kan ignoreres. Der findes imidlertid ikke pt. algoritmer der kan gøre dette tilfredsstillende på materiale fra denne periode.

library(textrecipes)

avis_rec <- recipe(Gender ~ Text, data = avis_train) %>% 
  step_tokenize(Text) %>% 
  step_stopwords(Text, 
                 custom_stopword_source = stopord$word) %>% 
  step_tokenfilter(Text, max_tokens = 1000) %>% 
  step_tf(Text, weight_scheme = "binary") %>% 
  step_normalize(all_predictors()) %>% 
  step_pca(all_predictors(), num_comp = 8, id = "pca")

avis_baked <- prep(avis_rec) %>% bake(new_data = NULL) # dette trin er udelukkende for at foretage en manuel vurdering om hvorvidt opskriften gør, hvad den skal

head(avis_baked)
# A tibble: 6 × 9
  Gender   PC1    PC2    PC3    PC4    PC5    PC6     PC7    PC8
  <fct>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>   <dbl>  <dbl>
1 F       4.41  0.879 -1.51   0.289  0.495 -0.654  0.245  -0.325
2 F       3.89 -0.562 -1.21  -0.328 -0.161 -1.58   1.26   -0.515
3 F       3.43 -0.209 -1.15   0.883  0.269 -2.83   0.945  -0.813
4 F       3.34 -0.419 -0.575  0.601  0.395 -1.41  -0.238   0.506
5 F       1.10 -5.33  -5.97  -8.73  -6.71  -5.05   1.22    0.138
6 F       4.34  0.215 -1.66  -0.365  0.244 -0.590  0.0296  0.101

Som næste skridt defineres vores model, der knyttes til vores opskrift i et workflow. Til sidst fittes/trænes modellen.

library(discrim) 

nb_spec <- naive_Bayes(Laplace = 0.5) %>% 
  set_mode("classification") %>% set_engine("naivebayes")

avis_wf <- workflow() %>% 
  add_recipe(avis_rec) %>% 
  add_model(nb_spec)

nb_fit <- avis_wf %>% fit(data = avis_train)

10.3 Hvad lærer maskinen - og hvad lærer vi?

Hvordan klarer modellen sig? Fordi vi har tilbageholdt noget data kan vi teste modellen på netop dette data, der altså er ukendt for modellen. For hver gang vi kører denne notebook splittes dataene forskelligt, og præcisionen vil tilsvarende svinge. Generelt får vi dog en præcision, på den fornuftige side af 90. Algoritmen har med andre ord, i langt de fleste tilfælde, succes med at identificere den efterlyste persons køn på baggrund af teksten.

avis_nb_final_fit <- last_fit(avis_wf, split = avis_split)
avis_predictions <- collect_predictions(avis_nb_final_fit)
collect_metrics(avis_nb_final_fit)
# A tibble: 2 × 4
  .metric  .estimator .estimate .config             
  <chr>    <chr>          <dbl> <chr>               
1 accuracy binary         0.961 Preprocessor1_Model1
2 roc_auc  binary         0.986 Preprocessor1_Model1

Men hvad med de tekster, hvor algoritmen fejler? Lad os identificere de annoncer, hvor modellen læser forkert. Er der noget særligt ved dem?

avis_prediction_fail <- avis_predictions %>% 
  mutate(success = .pred_class == Gender) %>% 
  mutate(ID = as.character(.row)) %>% 
  select(ID, success) %>%
  filter(success == FALSE)

avis_prediction_fail_text <- avis_samples %>%
  mutate(ID = str_remove(avis_samples$ID, 
                         pattern = "ID-")) %>%
  right_join(avis_prediction_fail)

avis_prediction_fail_text$Text
[1] "Et svensk Qvindemenneske navnlig Ingeborg Niels Datter, som en Tid lang for begangen Tyverie har siddet arresteret paa denne Byes Raadhuus, er igiennem Arrestforvarererens Efterladenhed og Forsømmelse den 26 December af sin Arrest undvigt. Ved Undvigelsen var hun iklædt en hvid ulden Trøye, eller en rød og hvid Sirtses, hvilken sidste hun formodes ved sin Bortgang paa ny at have stiaalet, et gammelt grønt Stoffes Skiørt, og et Par gamle Tøfler, samt sluttet i Jern fra Høyre Haand til venstre Fod; er ellers maadelig af Statur, tyk og feedladen, omtrent mod 30 Aar gammel. Hvo bemeldte Qvindemenneske maatte forekomme, vilde behage at anholde hende, og lade hende hidbringe, eller til Magistraten hersteds give Underretning, da ey alene alle paagaaende Omkostninger skal vorde erstattede, men angiveren desuden gives en Douceur for Umagen. Helsingøers Raadstue den 27 December 1785."
[2] "En Bondepige, 7 Aar gammel, er i Mandags Eftermiddag bortgaaet fra Kielderen i Pustervig No. 68."                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
[3] "Jeg Underskrevne advarer at ingen betroer min Kone Marthe Pernille Christians Datter noget paa mine Vegne, da hun er bortløben fra mig. Ole Pedersen Mollerup."                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
[4] "Da min Pige Hanne Jensdatter, født i Jylland, 15 Aar gl., liden af Vext, rødladen af Ansigt, er undvigt; ombedes enhver som maatte vide hendes Opholdssted, at give mig det tilkiende. H*** ***, boende i den hvide Svane i sotre Grønnegade No. 255."                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
[5] "Da Pigen Karen Hans Datter af Ockeløse Bye paa Friderichsborg Amt er Natten imellem den 8 og 9 huj. undvigt af sin Tieneste uden Skyld og Brøde fra Gientofte Bye, saa advares enhver, ikke at huse eller hæle hende, da de derved underkaster sig Lovens Tiltale, men derimod at give mig hendes Opholdssted tilkiende. Brockdorff."                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
[6] "Da min Dreng er bortløbet uden mindste Aarsag Søndags Aftes Kl. 9, og medtaget sit Tøi uden mit Vidende; saa ombedes de, somhaver imodtaget ham, at give mig det tilkiende paa Hiørnet af Klareboderne og Pilestræde No. 1 og 2. Thomas Hvidt, Skoemagermester."                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
[7] "En Jødinde, navnlig Lea, som for Barnefødsel i Dølgsmaal var arresteret og indlagt til Cuur paa Tugthusets Sygestue, har funden Leilighed at undvige. Hun er maadelig af Vext, mager af Ansigt og meget koparret samt sortladen, har brune Øine og sort Haar, hun var iklædt en lys Cattuns Trøie og Skiørt, havde et stort Cattuns Tørklæde om Halsen, hvid Nattøi paa Hovedet og Pampusser paa Fødderne. De som maatte forekomme bemeldete Jødinde, bedes at anholde og indsende hende til Kiøbenhavns Tugthuus, hvorfra de medgaaede Omkostninger og en Douceur for Opbringelsen skal blive betalte. Kiøbenhavns Tugthuus d. 18. Septbr. 1793."                                                                                                                                                                                                                                                                     
[8] "Da min Mand Haarskierer Schieldern har forladt mig Mandagen den 9 November med 4 Børn vil jeg bede enhver retfindig Menneske som veed hans Opholdssted, at give mig det tilkiende, da jeg har ikke det ringeste i min Fattigdom at forsørge mine Børn med; boer i Nellikegangen No. 150."                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
[9] "Da min Hustrue Bolette Jansen ibladnt andre mig udviste Utroskaber den 19 Novbr. sidstleden har absenteret sig fra mit Huus, uden nogen af mig dertil given Anledning; saa advares enhver, ikke at betroe hende noget i mit Navn, og det saa meget mindre, som jeg nu er i den ubehagelige Nødvendighed, at maa legge hendes og Medhielperes Forhold for Dagen .Khavn den 26 Novbr. 1793. Odmesen, Friseur hos Hds. Majestæt Enkedronningen."                                                                                                                                                                                                                                                                                                                                                                                                                                                                          

Her ser vi råteksten på de af test-dataenes 232 annoncer, hvor algoritmen giver en forkert angivelse af kønnet. Dette kan gøre os klogere på dataenes tekstur. Hvor machine learning og datavisualiseringsteknikker ofte kritiseres for at repræsentere data som homogene, uproblematiske og glatte, kan algoritmens fejl pege os i retning af mønstre, hvor dataene er tvetydige. Den kan derved berige vores forståelse af dataene. Fordi vi selv læser efter et navn, når vi søger at kategorisere et køn, men computeren ikke kan kende forskel på navne og andre ord, peger den således på annoncer, hvor kvinder omtales i termer, mænd normalt omtales i - og omvendt.

Et gennemgående træk, der står frem er, at possessive pronomener tilsyneladende kønner genren. “Min” og “mit” er hyppige i annoncer om kvinder, der efterlyses af en husbond. Når disse pronomener optræder i annoncer om mænd forvirres modellen i nogle tilfælde. Husstanden som en juridisk sfære knyttes dermed til et sprog struktureret af køn. Fordi annoncer om kvinder ofte er mindre deskriptive ifht. udseende, forvirres modellen ydermere, når kvinders udseende eller tøj beskrives detaljeret. Kvinder der har begået noget kriminelt eller udgør et problem grundet gæld, kønnes ligeledes af og til som mænd af algoritmen. Måske påvirkes algoritmen her også af, at annoncer om kvinder generelt er kortere end dem om mænd, men at dette mønster brydes netop i annoncer om mænd (ofte “drenge”) indrykket af private arbejdsgivere - og af annoncer, hvor omstændigheder betyder, at kvinderne efterlyses med flere narrative og/eller beskrivende elementer.

Algoritmens fejllæsninger fortæller os således om materialet som en del af en fundamentalt kønnet genre. Dette kan udgøre et supplement eller et korrektiv til vores øvrige analyser - uanset om disse sigter på kvalitativ eller kvantitativ brug af materialet. Det kan kort sagt hjælpe os til at stille mere kvalificerede spørgsmål til vores data.

10.4 Forudsigelse af kategorier i nye data

nye_data <- read_excel("data/Nye_avis_data.xlsx")

nye_data <- nye_data %>% 
  mutate(Forudsagt_køn = predict(nb_fit, nye_data))

  1. Anders Kristian Munk, Asger Gehrt Olsen og Mathieu Jacomy, “The Thick Machine: Anthropological AI between explanation and explication”, *Big Data & Society* 9:1, 2022. https://doi.org/10.1177/20539517211069891.↩︎

  2. Jill Walker Rettberg, “Algorithmic failure as a humanities methodology: Machine learning’s mispredictions identify rich cases for qualitative analysis”, *Big Data & Society* 9:2, 2022, https://doi.org/10.1177/20539517221131290.↩︎