TransWikia.com

How to identify gender and family roles of characters in novel excerpts?

Mathematica Asked by Matvei Kruglyak on April 19, 2021

I am playing with Natural language programming in Mathematica, and can’t figure out how to extract the entity classes (i.e. male, female) for the following example text:

"This was a pleasant summer afternoon. The hilly road crisscrossing the fields was a breezy ride for William Henry Hampton the Third, a boy of 8 years of age, and his cousin, Elizabeth-Ann Randall, a girl of 10 years of age. The Victorian English countryside was the perfect summer vacation setting for the cousins taking time off from a busy school in London. Their grandmother, Henriette Blake, who recently turned 57 years old, has been living in the countryside with her husband her entire life after her great-great grandparents left the city of Birmingham to try their hand in farming. Henriette’s husband passed on due to old age many years ago, and her days were enlightened with her grandkids visits during their summer vacations.";

Below is what I tried, with actual result and expected result noted inline; the goals to achieve on are outlined below the code:

novel = "This was a pleasant summer afternoon. The hilly road 
crisscrossing the fields was a breezy ride for William Henry Hampton 
the Third, a boy of 8 years of age, and his cousin, Elizabeth-Ann 
Randall, a girl of 10 years of age. The Victorian English countryside 
was the perfect summer vacation setting for the cousins taking time 
off from a busy school in London. Their grandmother, Henriette Blake, 
who recently turned 57 years old, has been living in the countryside 
with her husband her entire life after her great-great grandparents 
left the city of Birmingham to try their hand in farming. Henriette's 
husband passed on due to old age many years ago, and her days were 
enlightened with her grandkids visits during their summer vacations.";

EntityRegister[EntityStore["male" -> <|
     "Entities" -> <|"boy", "father", "grandfather", "son", "husband"|>
     |>]];
EntityRegister[EntityStore["female" -> <|
     "Entities" -> <|"girl", "mother", "grandmother", "daughter", "wife"|>
     |>]];

FindTextualAnswer[novel, "What are the names of the males?"]
(* Result: Elizabeth-Ann Randall, Expected: William Henry Hampton the Third *)
(* HOWEVER, is the above be better suited for TextCases? This is tested below. *)

FindTextualAnswer[novel, "What is the name of the boy?"]
(* Result: Elizabeth-Ann Randall, Expected: William Henry Hampton the Third *)

FindTextualAnswer[novel, "What is the name of the father?"]
(* Result: Elizabeth-Ann Randall, Expected: none *)

FindTextualAnswer[novel, "What is the name of the grandfather?"]
(* Result: Henriette Blake, Expected: not available *)

FindTextualAnswer[novel, "What are the names of the females?"]
(* Result: Elizabeth-Ann Randall, Expected: Elizabeth-Ann Randall, Henriette Blake *)
(* HOWEVER, is the above be better suited for TextCases? This is tested below. *)

FindTextualAnswer[novel, "What is the name of the girl?"]
(* Result: Elizabeth-Ann Randall, Expected: Elizabeth-Ann Randall *)

FindTextualAnswer[novel, "What is the name of the mother?"]
(* Result: Elizabeth-Ann Randall, Expected: none *)

FindTextualAnswer[novel, "What is the name of the grandmother?"]
(* Result: Elizabeth-Ann Randall, Expected: Henriette Blake *)

TextCases[novel, "male"]
(* Error result *)

TextCases[novel, "female"]
(* Error result *)

It seems, with further deep-dive needed, that spaCy combined with prodigy has a working approach to solve for these questions, however before taking the leap, I hope Mathematica would have one available too.

[Update in response to m_goldberg, with appreciation]
I see this as a named entity recognition (NER) problem. The goal is to receive a recommendation on approach (or a code) to train a model (e.g. a neural network) to accept input (a category) and, accounting for context (i.e. novel), provide output, such as:

Input: "male", Context: novel, Output: "William Henry Hampton the Third", "grandfather, unnamed"

Input: "boy", Context: novel, Output: "William Henry Hampton the Third"

Input: "father", Context: novel, Output: "No such character"

Input: "grandfather", Context: novel, Output: "Unnamed character"

Input: "female", Context: novel, Output: "Elizabeth-Ann Randall", "Henriette Blake"

Input: "girl", Context: novel, Output: "Elizabeth-Ann Randall"

Input: "mother", Context: novel, Output: "No such character"

Input: "grandmother", Context: novel, Output: "Henriette Blake"

In the meantime, this Mathematica tutorial regretfully does not suggest a solution:
https://reference.wolfram.com/language/tutorial/NeuralNetworksSequenceLearning.html
The closest approach is under the tutorial section "Simple RNN Trained on the bAbI QA Dataset", where the neural net accepts Context and a question about Context, and returns a classifier. From here, I am unable to envision how to tweak the NN architecture to accept Context and a classifier to return an answer from the Context based on the classifier.

There are also examples, regretfully not relevant, under individual neural networks in Wolfram Neural Net Repository such as here:
https://resources.wolframcloud.com/NeuralNetRepository/resources/BERT-Trained-on-BookCorpus-and-Wikipedia-Data
(Note: for other models see Browse by Task Type->(Feature Extraction, Language Modeling))

One Answer

All functions attempted by OP are experimental. That said, the particular workflow of OP using EntityRegister / EntityStore probably should be expected to work. (Meaning maybe or maybe not...)

Text data

Here is the text from OP:

novel = "This was a pleasant summer afternoon. The hilly road 
crisscrossing the fields was a breezy ride for William Henry Hampton 
the Third, a boy of 8 years of age, and his cousin, Elizabeth-Ann 
Randall, a girl of 10 years of age. The Victorian English countryside 
was the perfect summer vacation setting for the cousins taking time 
off from a busy school in London. Their grandmother, Henriette Blake, 
who recently turned 57 years old, has been living in the countryside 
with her husband her entire life after her great-great grandparents 
left the city of Birmingham to try their hand in farming. Henriette's 
husband passed on due to old age many years ago, and her days were 
enlightened with her grandkids visits during their summer vacations.";

Different workflow

It seems that one of OP’s wants can be achieved with “proper” use of TextCases combined with one of Classify's pre-built classifiers:

(We use Named Entity Recognition to get person names and then use classification to get the corresponding genders.)

TextCases[novel, "Person", "AcceptanceThreshold" -> 0.2]

(*{"William Henry Hampton the Third", "Elizabeth-Ann Randall", "Victorian", "Henriette Blake", "Henriette"}*)
Association@Map[# -> Classify["NameGender", #] &, %]

(*<|"William Henry Hampton the Third" -> "Male", 
 "Elizabeth-Ann Randall" -> Indeterminate, 
 "Victorian" -> Indeterminate, 
 "Henriette Blake" -> "Female", 
 "Henriette" -> "Female"|>*)

Using better options and more comprehensive parameters

Better results are obtained using PerformanceGoal->”Quality” for FindTextualAnswer.

Additionally, using probabilities and an acceptance threshold produces results OP expects. (The association aQAs below is made using OP's posted comments of the results by FindTextualAnswer.)

opts = {PerformanceGoal -> "Quality"};
args = Sequence @@ {3, {"String", "Probability"}};
aQAs = <|
   "What are the names of the males?" -> "William Henry Hampton the Third",
   "What is the name of the boy?" -> "William Henry Hampton the Third",
   "What is the name of the father?" -> None,
   "What is the name of the grandfather?" -> None,
   "What are the names of the females?" -> "Elizabeth-Ann Randall,Henriette Blake",
   "What is the name of the girl?" -> "Elizabeth-Ann Randall",
   "What is the name of the mother?" -> None,
   "What is the name of the grandmother?" -> "Henriette Blake"
   |>;
threshold = 0.1;
res = 
  KeyValueMap[
    <|"Question" -> #1, 
      "Result" -> Select[Association[Rule @@@ FindTextualAnswer[novel, #1, args, opts]], # >= threshold &], 
      "Expected" -> #2|> &, 
    aQAs
  ];
ResourceFunction["GridTableForm"][Values /@ res, TableHeadings -> Keys[res[[1]]]]

enter image description here

For the question “What are the names of the females?” expected results are obtained if no threshold filtering is done:

FindTextualAnswer[novel, "What are the names of the females?", args, opts]

(*{
{"cousin, Elizabeth-Ann Randall, a girl",  1.32598*10^-6}, 
{"Henriette Blake", 6.72097*10^-8}, {"grandmother", 1.01825*10^-9}
}*)

Correct answer by Anton Antonov on April 19, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP