Skip to article frontmatterSkip to article content

3 Star 4 Star

Dieses Notebook: Wir explorieren technisch, wie man eine “Dreistern”-CSV-Datei in eine “Vierstern”-RDF-Datei übersetzen kann: Zuerst exemplarisch eine Zeile manuell, dann die komplette Datei automatisch.

Begriff Linked Open Data 5 Star:

Dieses Notebook: Wir schauen uns exemplarisch eine (3 star-) CSV-Tabelle an, und überführen sie in eine 4-star Repräsentation in RFD(S)

aus csv einlesen

https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html

import pandas as pd
import numpy as np
Abfall_df = pd.read_csv("../govdata/Erzeugte-Abfallmengen-MS_2.csv", 
                        thousands = ".", 
                        decimal = ",",
                        nrows = 3, # für unsere Demo hier nur die ersten 3 Zeilen
                        sep = ";")
Abfall_df.head(3)
Abfall_df.reset_index(inplace=True)
Abfall_df.head(3)
# https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.assign.html

manuell rekonstruieren

Wir wollen Erfahrung sammeln mit ttl und rdflib. Dazu codieren wir die Tabellenzeile 4 (im Pandas Dataframe der Dtaensatz mit Index 2) manuell als ttl, um es in rdflib einzulesen.

import rdflib
import owlrl

Graph a1 manuell in ttl bauen

abfall_ttl = """
@prefix ex: <http://jbusse/ex#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

# Sammlung
_:4 ex:AVV-Abfallart-Nr ex:160103 ;
    ex:Menge_in_Tonnen "166.1" .

# "AVV-Abfallart"
ex:160103 
   ex:hat_Bezeichnung "Altreifen" .
"""

# später ggf. hinzufügen:
# ex:AVV-Abfallart-Nr rdfs:range ex:AVV-Abfallart .

a1 = rdflib.Graph().parse(data= abfall_ttl)

a1 ist ein rdf-Graph. Anzahl der in ihm enthaltenen Tripel:

len(a1)

a1 läst sich wie eine Liste durchlaufen.

for x in a1:
    print(len(x), x)

oder auch so:

for s, p, o in a1:
    print(s, p, o)

Graph mit SPARQL anfragen

Ein librdf-Objekt hat eine SPARQL-Schnittstelle. aq sei unsere SPARL-Query:

q1 = """
PREFIX ex: <http://jbusse/ex#>
SELECT ?x ?y
WHERE { ?x ex:AVV-Abfallart-Nr ?y .}
"""
q1_result = a1.query(q1)
q1_result

Weil in unserer SPARQL-Query 2 Variablen erfragt werden, erhalten wir eine Liste aus 2-Tupeln:

for r1, r2 in q1_result:
    print(r1, r2)

Graph a2: CSV-Datei automatisch in RDF umwandeln

Oben haben wir die CSV-Datei mit Pandas eingelesen - das geht einfach, komfortabel und schnell. Würden wir Pandas gut kennen, würden wir mit vektorisierten Funktionen weiterabeiten.

Im folgenden gehen wir aber “zu Fuß” vor, arbeiten auf den Datenstrukturen, die wir aus der Python 1-Veranstaltung gut kennen: Verschachtelte Listen und Dicts.

Lesen:

Abfall_dict_dict = Abfall_df.to_dict("index")
Abfall_dict_dict
# konventionelle Technik: Repräsentiere Ausgabe als eine Liste von Strings, 
# die am Schluss mit join zusammengefügt werden
result_string_list = [ "@prefix ex: <http://jbusse/ex#> ."]

# Zeilen
for id, row in Abfall_dict_dict.items():
    result_string_list.append(f"\n# {id}")
    
    # Spalten
    for Spalte, Wert in row.items():
        
        # Resoures
        if Spalte in [ "Jahr", "AVV-Abfallart-Nr" ]:
            result_string_list.append(f"ex:Sammlung_{id} ex:{Spalte} ex:{Wert} .")
            
            
        # Zahl als Literal
        elif Spalte == "Menge in Tonnen":
            result_string_list.append(f"ex:Sammlung_{id} ex:Menge_in_Tonnen {Wert} .")
        
        # String als Literal
        elif Spalte == 'AVV-Abfallart Bezeichnung':
            result_string_list.append(f"ex:{row['AVV-Abfallart-Nr']} ex:hat_Bezeichnung '{Wert}' .")
result_string_list
result_string = "\n".join(result_string_list)
print(result_string)
a2 = rdflib.Graph().parse(data= result_string)
q2 = """
PREFIX ex: <http://jbusse/ex#>
SELECT ?s ?p ?o
WHERE { ?s ?p ?o .}
"""
for s, p, o in a2.query(q2):
    print(s.n3(), p.n3(), o.n3())

Alle Arten von zweifach verschachtelten Listen von Listen, Dicts, etc. lassen sich leicht in ein Pandas DataFrame umwandeln:

a2_df = pd.DataFrame(data=a2.query(q2), columns=["S", "P", "O"])
a2_df

Über dem automatisch übersetzten Datenatz jetzt nochmal die Query q1:

for s, o in a2.query(q1):
    print(s, o)