pythonpython-3.xowlontologyowlready

Add new Individuals to an existing ontology from a dataframe using owlready 2


I have the following dataframe:

import pandas as pd
    
data = [['onto.modify', 'onto.ModificationAction1']]
df = pd.DataFrame(data, columns=['queries', 'corpus'])

       queries                corpus
0      onto.modify            onto.ModificationAction1

The elements of corpus column are Individuals of a particular Class of an ontology called ontology2.

I want to add the elements of the queries column as individuals to the same Class that the elements of the corpus column belong to.

For example, if the onto.ModificationAction1 belong to the ontology2.Thing class the same must be for the ontology2.modify.

Initially, I loop over the corpus columns to find in which Class each Individual belongs to:

for elements in df["corpus"]:
    print (element.is_a)

However, I get back:

AttributeError: 'str' object has no attribute 'is_a'

So how do I solve this error and eventually perform what I am describing above in the example?


Solution

  • Error happens because values in your dataframe are strings, not individuals. You have to look up an individual based on its name using search() or search_one() (see documentation). This code should do the job:

    import pandas as pd
    import owlready2
    
    data = [['onto.modify', 'onto.ModificationAction1']]
    df = pd.DataFrame(data, columns=['queries', 'corpus'])
    
    onto = owlready2.get_ontology("http://test.org/onto.owl")
    
    
    class Action(owlready2.Thing):
        namespace = onto
    
    
    modification_action = Action(name="ModificationAction1")
    
    for row in df.iterrows():
        row_series = row[1]
        # Trow away ontology name, get only individual name
        corpus_individual_name = row_series['corpus'].split('.', 1)[1]
        # Find individual
        corpus_individual = onto.search_one(iri=onto.base_iri + corpus_individual_name)
        # Get individual classes
        corpus_classes = corpus_individual.is_a
        # Trow away ontology name, get only individual name
        query_individual_name = row_series['queries'].split('.', 1)[1]
        # Create new individual with first class of old individual
        new_individual = corpus_classes[0](name=query_individual_name)
        # In case old individual is multiclass, add remaining classes to new individual
        for corpus_class in corpus_classes[1:]:
            new_individual.is_a.append(corpus_class)
    
    for i in onto.individuals():
        print(i, i.is_a)
    
    

    You can see the new individual in the output along with its class.

    onto.ModificationAction1 [onto.Action]
    onto.modify [onto.Action]
    

    P.S.: I'm assuming here that you have only one ontology -- onto. If not, you should either 1) Have a lookup dictionary for ontologies to map "onto" into actual ontology object/IRI, or 2) instead of “onto.” prefix specify full IRI in your dataframe and lookup ontology by IRI.