Notebooks
M
Microsoft
FamilyOntology

FamilyOntology

artificial-intelligencernnganmicrosoft-for-beginnerslessonsAImicrosoft-AI-For-Beginnersmachine-learningdeep-learningcomputer-visioncnn2-SymbolicNLP

Family Relationships Ontology

This example is a part of AI for Beginners Curriculum, and it has been inspired by this blog post.

I always find it difficult to remember different relationships between people in a family. In this example, we will take an ontology that defines family relationships, and the actual genealogical tree, and show how we can then perform automatic inference to find all relatives.

Getting the Genealogical Tree

As an example, we will take genealogical tree of Romanov Tsar Family. The most common format for describing family relationships is GEDCOM. We will take Romanov family tree in GEDCOM format:

[1]
0 HEAD
1 CHAR UTF8
1 GEDC
2 VERS 5.5
0 @0@ INDI
1 NAME Mihail Fedorovich /Romanov/
1 SEX M
1 BIRT
2 DATE 1613
1 DEAT 
2 DATE 1645
1 FAMS @41@
0 @1@ INDI
1 NAME Evdokija Lukjanovna /Streshneva/
1 SEX F

To use GEDCOM file, we can use python-gedcom library:

[2]
Collecting python-gedcom
  Downloading python_gedcom-1.0.0-py2.py3-none-any.whl (35 kB)
Installing collected packages: python-gedcom
Successfully installed python-gedcom-1.0.0

This library takes away some of the technical problems with file parsing, but it still gives us pretty low-level access to all individuals and families in the tree. Here is how we can parse the file, and show the list of all individuals:

[3]
[4]
[('@0@', ('Mihail Fedorovich', 'Romanov')),
, ('@1@', ('Evdokija Lukjanovna', 'Streshneva')),
, ('@2@', ('Aleksej Mihajlovich', 'Romanov')),
, ('@3@', ('Marija Ilinichna', 'Miloslavskaja')),
, ('@4@', ('Natalja Kirillovna', 'Naryshkina')),
, ('@5@', ('Marfa Matveevna', 'Apraksina')),
, ('@6@', ('Fedor Alekseevich', 'Romanov')),
, ('@7@', ('Sofja Aleksevna', 'Romanova')),
, ('@8@', ('Ivan V Alekseevich', 'Romanov')),
, ('@9@', ('Praskovja Fedorovna', 'Saltykova')),
, ('@10@', ('Ekaterina Ivanovna', 'Romanova')),
, ('@11@', ('Anna Ivanovna', 'Romanova')),
, ('@12@', ('Fridrih Vilgelm', 'Kurlandskij')),
, ('@13@', ('Karl Leopold', 'Meklenburg-Shverinskij')),
, ('@14@', ('Anna Leopoldovna', 'Meklenburg-Shverinskaja')),
, ('@15@', ('Anton Ulrih', 'Braunshvejg-Volfenbjuttelskij')),
, ('@16@', ('Ivan VI Antonovich', 'Braunshvejg-Volfenbjuttelskij')),
, ('@17@', ('Petr I Alekseevich', 'Romanov')),
, ('@18@', ('Evdokija Fedorovna', 'Lopuhina')),
, ('@19@', ('Ekaterina I Alekseevna', 'Mihajlova')),
, ('@20@', ('Aleksej Petrovich', 'Romanov')),
, ('@21@', ('Sharlotta Kristina', 'Braunshvejg-Volfenbjuttelskaja')),
, ('@22@', ('Petr II Alekseevich', 'Romanov')),
, ('@23@', ('Anna Petrovna', 'Romanova')),
, ('@24@', ('Elizaveta Petrovna', 'Romanova')),
, ('@25@', ('Karl Fridrih', 'Golshtejn-Gottorpskij')),
, ('@26@', ('Petr III Fedorovich', 'Romanov')),
, ('@27@', ('Ekaterina II', 'Alekseevna')),
, ('@28@', ('Pavel I Petrovich', 'Romanov')),
, ('@29@', ('Natalja Alekseevna', 'Gessen-Darmshtadskaja')),
, ('@30@', ('Marija Fedorovna', 'Vjurtembergskaja')),
, ('@31@', ('Aleksandr I Pavlovich', 'Romanov')),
, ('@32@', ('Elizaveta Alekseevna', 'Baden-Durlahskaja')),
, ('@33@', ('Nikolaj I Pavlovich', 'Romanov')),
, ('@34@', ('Aleksandra Fedorovna', 'Prusskaja')),
, ('@35@', ('Aleksandr II Nikolaevich', 'Romanov')),
, ('@36@', ('Marija Aleksandrovna', 'Gessenskaja')),
, ('@37@', ('Aleksandr III Aleksandrovich', 'Romanov')),
, ('@38@', ('Marija Fedorovna', 'Datskaja')),
, ('@39@', ('Nikolaj II Aleksandrovich', 'Romanov')),
, ('@40@', ('Aleksandra Fedorovna', 'Gessenskaja'))]

Here is how we can get information about families. Note that is gives us a list of identifiers, and we need to convert them to names if we want more clarity:

[5]
[('@41@', ['@0@', '@1@', '@2@']),
, ('@42@', ['@2@', '@3@', '@6@', '@7@', '@8@']),
, ('@43@', ['@8@', '@9@', '@10@', '@11@']),
, ('@44@', ['@13@', '@10@', '@14@']),
, ('@45@', ['@15@', '@14@', '@16@']),
, ('@46@', ['@2@', '@4@', '@17@']),
, ('@47@', ['@17@', '@18@', '@20@']),
, ('@48@', ['@20@', '@21@', '@22@']),
, ('@49@', ['@17@', '@19@', '@23@', '@24@']),
, ('@50@', ['@25@', '@23@', '@26@']),
, ('@51@', ['@26@', '@27@', '@28@']),
, ('@52@', ['@28@', '@30@', '@31@', '@33@']),
, ('@53@', ['@33@', '@34@', '@35@']),
, ('@54@', ['@35@', '@36@', '@37@']),
, ('@55@', ['@37@', '@38@', '@39@'])]

Getting Family Ontology

Next, let's have a look at family ontology defined as a set of Semantic Web triplets. This ontology defines such relationships as isUncleOf, isCousinOf, and many others. All those relationships are defined in terms of basic predicates isMotherOf, isFatherOf, isBrotherOf and isSisterOf. We will use automatic reasoning to deduce all other relationships using the ontology.

Here is a sample definition of isAuntOf property, which is defined as a composition of isSisterOf and isParentOf (Aunt is a sister of one's parent).

fhkb:isAuntOf a owl:ObjectProperty ;
    rdfs:domain fhkb:Woman ;
    rdfs:range fhkb:Person ;
    owl:propertyChainAxiom ( fhkb:isSisterOf fhkb:isParentOf ) .
[6]
@prefix fhkb: <http://www.example.com/genealogy.owl#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xml: <http://www.w3.org/XML/1998/namespace> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

<http://www.example.com/genealogy.owl#> a owl:Ontology .

fhkb:DomainEntity a owl:Class .

fhkb:Man a owl:Class ;
    owl:equivalentClass [ a owl:Class ;
            owl:intersectionOf ( fhkb:Person [ a owl:Restriction ;
                        owl:onProperty fhkb:hasSex ;
                        owl:someValuesFrom fhkb:Male ] ) ] .

fhkb:Woman a owl:Class ;
    owl:equivalentClass [ a owl:Class ;
            owl:intersectionOf ( fhkb:Person [ a owl:Restriction ;

Constructing Ontology for Inference

For simplicity, we will create one ontology file that will include original rules from family ontology, and facts about individuals from our GEDCOM file. We will go through the GEDCOM file and extract information about families and individuals, and convert them to triplets.

[7]
[8]
    fhkb:hasFemalePartner fhkb:i34 ;
    fhkb:hasMalePartner fhkb:i33 .
fhkb:i54 a owl:NamedIndividual, owl:Thing ;
    fhkb:hasFemalePartner fhkb:i36 ;
    fhkb:hasMalePartner fhkb:i35 .
fhkb:i55 a owl:NamedIndividual, owl:Thing ;
    fhkb:hasFemalePartner fhkb:i38 ;
    fhkb:hasMalePartner fhkb:i37 .
[] a owl:AllDifferent ;
    owl:distinctMembers (    fhkb:i0    fhkb:i1    fhkb:i2    fhkb:i3    fhkb:i4    fhkb:i5    fhkb:i6    fhkb:i7    fhkb:i8    fhkb:i9    fhkb:i10    fhkb:i11    fhkb:i12    fhkb:i13    fhkb:i14    fhkb:i15    fhkb:i16    fhkb:i17    fhkb:i18    fhkb:i19    fhkb:i20    fhkb:i21    fhkb:i22    fhkb:i23    fhkb:i24    fhkb:i25    fhkb:i26    fhkb:i27    fhkb:i28    fhkb:i29    fhkb:i30    fhkb:i31    fhkb:i32    fhkb:i33    fhkb:i34    fhkb:i35    fhkb:i36    fhkb:i37    fhkb:i38    fhkb:i39    fhkb:i40    fhkb:i41    fhkb:i42    fhkb:i43    fhkb:i44    fhkb:i45    fhkb:i46    fhkb:i47    fhkb:i48    fhkb:i49    fhkb:i50    fhkb:i51    fhkb:i52    fhkb:i53    fhkb:i54    fhkb:i55    ) .

Doing Inference

Now we want to be able to use this ontology for inference and for querying. We will use RDFLib, library for reading RDF Graph in different formats, querying it, etc.

For logical inference, we will use OWL-RL library, which allows us to build Closure of the RDF Graph, i.e. add all possible concepts and relations that can be inferred.

[10]
Requirement already satisfied: rdflib in /home/rg/anaconda3/envs/ai4beg/lib/python3.11/site-packages (6.3.2)
Requirement already satisfied: isodate<0.7.0,>=0.6.0 in /home/rg/anaconda3/envs/ai4beg/lib/python3.11/site-packages (from rdflib) (0.6.1)
Requirement already satisfied: pyparsing<4,>=2.1.0 in /home/rg/anaconda3/envs/ai4beg/lib/python3.11/site-packages (from rdflib) (3.0.9)
Requirement already satisfied: six in /home/rg/anaconda3/envs/ai4beg/lib/python3.11/site-packages (from isodate<0.7.0,>=0.6.0->rdflib) (1.16.0)
Collecting git+https://github.com/RDFLib/OWL-RL.git
  Cloning https://github.com/RDFLib/OWL-RL.git to /tmp/pip-req-build-lbfzwi3m
  Running command git clone --filter=blob:none --quiet https://github.com/RDFLib/OWL-RL.git /tmp/pip-req-build-lbfzwi3m
  Resolved https://github.com/RDFLib/OWL-RL.git to commit a77e1791b88b54aace609bc6000aac14c7add4ff
  Preparing metadata (setup.py) ... done
Requirement already satisfied: rdflib>=6.0.2 in /home/rg/anaconda3/envs/ai4beg/lib/python3.11/site-packages (from owlrl==6.0.2) (6.3.2)
Requirement already satisfied: isodate<0.7.0,>=0.6.0 in /home/rg/anaconda3/envs/ai4beg/lib/python3.11/site-packages (from rdflib>=6.0.2->owlrl==6.0.2) (0.6.1)
Requirement already satisfied: pyparsing<4,>=2.1.0 in /home/rg/anaconda3/envs/ai4beg/lib/python3.11/site-packages (from rdflib>=6.0.2->owlrl==6.0.2) (3.0.9)
Requirement already satisfied: six in /home/rg/anaconda3/envs/ai4beg/lib/python3.11/site-packages (from isodate<0.7.0,>=0.6.0->rdflib>=6.0.2->owlrl==6.0.2) (1.16.0)

Let's open the ontology file and see how many triplets it contains:

[11]
Triplets found:669

Now let's build the closure, and see how the number of triplets increase:

[12]
Triplets after inference:4246

Querying for Relatives

Now we can query the graph to see different relations between people. We can use SPARQL language together with query method. In our case, let's see all uncles in our family tree:

[13]
Fedor Alekseevich Romanov is uncle of Ekaterina Ivanovna Romanova
Aleksandr I Pavlovich Romanov is uncle of Aleksandr II Nikolaevich Romanov
Fedor Alekseevich Romanov is uncle of Anna Ivanovna Romanova

Feel free to experiment with different other family relations. For example, you can have a look at isAncestorOf relation, which recurrently defines all ancestors of a given person.

Finally, let's clean up!

[14]
[ ]