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:
- historisch relevantes Dokument von Tim Berners-Lee: https://
www .w3 .org /DesignIssues /LinkedData .html - 5 star im Linked Data Glossary: https://
dvcs .w3 .org /hg /gld /raw -file /default /glossary /index .html #x5 -star -linked -open -data
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)
Suche auf https://
www .govdata .de / nach Abfallarten Münster (Juni 2023: 12 Treffer), führt u.a. auf Nach Abfallarten differenzierte erzeugte Abfallmengen Münster. Abfallmengen in Tonnen bezogen auf die Jahre ab 2013, erzeugt in der Stadt Münster. Datei: https://
opendata .stadt -muenster .de /sites /default /files /Erzeugte -Abfallmengen -MS _2 .csv (Moodle: Erzeugte Abfallmengen Sitzung 2023-06-07.csv)
aus csv einlesen¶
https://
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)