main
Roman Schöne 2026-05-02 21:28:41 +02:00
parent 4cee889722
commit 8f9314cddb
6 changed files with 143 additions and 258 deletions

View File

@ -1,212 +0,0 @@
# %% [markdown]
# Build the Lego Knowledge Graph using the sources in `/data`.
# %%
from rdflib import Graph, Namespace, XSD, OWL, RDF, RDFS, SKOS, URIRef, Literal
import pandas as pd
from datetime import datetime
# %% [markdown]
# Setup the requirements for building a knowledge graph
# %%
g = Graph()
thm = Namespace("https://thm.de/")
THM = Namespace("https://thm.de/ont/")
# %% [markdown]
# # Rebrickable
# %% [markdown]
# ![Rebrickable](\data\rebrickable\downloads_schema_v3.png)
# %%
re_colors = pd.read_csv("data/rebrickable/colors.csv")
re_elements = pd.read_csv("data/rebrickable/elements.csv")
re_inventories = pd.read_csv("data/rebrickable/inventories.csv")
re_inventory_minifigs = pd.read_csv("data/rebrickable/inventory_minifigs.csv")
re_inventory_parts = pd.read_csv("data/rebrickable/inventory_parts.csv")
re_inventory_sets = pd.read_csv("data/rebrickable/inventory_sets.csv")
re_minifigs = pd.read_csv("data/rebrickable/minifigs.csv")
re_part_categories = pd.read_csv("data/rebrickable/part_categories.csv")
re_part_relationships = pd.read_csv("data/rebrickable/part_relationships.csv")
re_parts = pd.read_csv("data/rebrickable/parts.csv")
re_sets = pd.read_csv("data/rebrickable/sets.csv")
re_themes = pd.read_csv("data/rebrickable/themes.csv")
# %% [markdown]
# Colors
# %%
for color in re_colors.itertuples(index=False):
color_ref = thm[f"colors/{color.id}"]
g.add((color_ref, RDFS.label, Literal(color.name, lang="en")))
g.add((color_ref, THM.color, Literal(color.rgb)))
g.add((color_ref, THM.is_transparent, Literal(color.is_trans, datatype=XSD.boolean)))
if not pd.isna(color.y1):
# First appearance
g.add((color_ref, THM.first_year, Literal(datetime(year = int(color.y1), month=1, day=1))))
if not pd.isna(color.y2):
# Last appearance
g.add((color_ref, THM.last_year, Literal(datetime(year = int(color.y2), month=1, day=1))))
# %% [markdown]
# Part Categories
# %%
for part_category in re_part_categories.itertuples(index=False):
part_category_ref = thm[f"part_category/{part_category.id}"]
g.add((part_category_ref, RDFS.label, Literal(part_category_ref, lang="en")))
# %% [markdown]
# Parts
# %%
for part in re_parts.itertuples(index=False):
part_ref = thm[f"part/{part.part_num}"]
g.add((part_ref, RDFS.label, Literal(part.name, lang="en")))
g.add((part_ref, THM.part_category, thm[f"part_category/{part.part_cat_id}"]))
g.add((part_ref, THM.part_material, Literal(part.part_material)))
# %% [markdown]
# Elements
# %%
for element in re_elements.itertuples(index=False):
part_ref = thm[f"part/{element.part_num}"]
color_ref = thm[f"colors/{element.color_id}"]
g.add((part_ref, THM.has_color, color_ref))
# %% [markdown]
# Part Relationships
# %%
for part_relationship in re_part_relationships.itertuples(index=False):
part_ref_parent = thm[f"part/{part_relationship.parent_part_num}"]
part_ref_child = thm[f"part/{part_relationship.child_part_num}"]
g.add((part_ref_parent, THM.has_child, part_ref_child))
# %% [markdown]
# Themes
# %%
for theme in re_themes.itertuples(index=False):
theme_ref = thm[f"theme/{int(theme.id)}"]
g.add((theme_ref, RDFS.label, Literal(theme.name, lang="en")))
if not pd.isna(theme.parent_id):
g.add((theme_ref, THM.parent_theme, thm[f"theme/{int(theme.parent_id)}"]))
# %% [markdown]
# Sets
# %%
for lego_set in re_sets.itertuples(index=False):
set_ref = thm[f"set/lego/{lego_set.set_num}"]
g.add((set_ref, RDFS.label, Literal(lego_set.name, lang="en")))
g.add((set_ref, THM.year, Literal(datetime(int(lego_set.year), 1, 1))))
g.add((set_ref, THM.theme, thm[f"theme/{int(lego_set.theme_id)}"]))
g.add((set_ref, THM.num_parts, Literal(int(lego_set.num_parts), datatype=XSD.integer)))
g.add((set_ref, THM.brand, Literal("Lego")))
# %% [markdown]
# Minifigures
# %%
for minifig in re_minifigs.itertuples(index=False):
minifig_ref = thm[f"minifig/{minifig.fig_num}"]
g.add((set_ref, RDFS.label, Literal(minifig.name, lang="en")))
g.add((set_ref, THM.num_parts, Literal(int(minifig.num_parts), datatype=XSD.integer)))
# %% [markdown]
# Now the ugly part: Inventories
# %%
for inventory in re_inventories.itertuples(index=False):
inventory_ref = thm[f"inventory/{inventory.id}"]
g.add((inventory_ref, THM.set, thm[f"sets/lego/{inventory.set_num}"]))
# %% [markdown]
# Inventories relate sets, minifigures and parts to each other, creating a kind of "top level set"
# (this takes a lot of time)
# %%
for inventory_part in re_inventory_parts.itertuples(index=False):
inventory_part_ref = thm[f"inventory_part/{inventory_part.inventory_id}/{inventory_part.part_num}"]
inventory_ref = thm[f"inventory/{inventory_part.inventory_id}"]
part_ref = thm[f"part/{inventory_part.part_num}"]
g.add((inventory_part_ref, RDFS.domain, inventory_ref))
g.add((inventory_part_ref, RDFS.range, part_ref))
g.add((inventory_part_ref, RDF.type, RDF.Property))
g.add((inventory_part_ref, THM.quantity, Literal(int(inventory_part.quantity), datatype=XSD.integer)))
g.add((inventory_part_ref, THM.is_spare, Literal(inventory_part.is_spare, datatype=XSD.boolean)))
g.add((inventory_part_ref, THM.color, thm[f"color/{inventory_part.color_id}"]))
# %%
for inventory_set in re_inventory_sets.itertuples(index=False):
inventory_set_ref = thm[f"inventory_set/{inventory_set.inventory_id}/{inventory_set.set_num}"]
inventory_ref = thm[f"inventory/{inventory_set.inventory_id}"]
set_ref = thm[f"set/lego/{inventory_set.set_num}"]
g.add((inventory_set_ref, RDFS.domain, inventory_ref))
g.add((inventory_set_ref, RDFS.range, set_ref))
g.add((inventory_set_ref, RDF.type, RDF.Property))
g.add((inventory_set_ref, THM.quantity, Literal(int(inventory_set.quantity), datatype=XSD.integer)))
# %%
for inventory_minifig in re_inventory_minifigs.itertuples(index=False):
inventory_minifig_ref = thm[f"inventory_minifig/{inventory_minifig.inventory_id}/{inventory_minifig.fig_num}"]
inventory_ref = thm[f"inventory/{inventory_minifig.inventory_id}"]
minifig_ref = thm[f"minifig/lego/{inventory_minifig.fig_num}"]
g.add((inventory_minifig_ref, RDFS.domain, inventory_ref))
g.add((inventory_minifig_ref, RDFS.range, minifig_ref))
g.add((inventory_minifig_ref, RDF.type, RDF.Property))
g.add((inventory_minifig_ref, THM.quantity, Literal(int(inventory_minifig.quantity), datatype=XSD.integer)))
# %% [markdown]
# Serialize the graph in turtle format
# %% [markdown]
# ```
# ___-------___
# _-~~ ~~-_
# _-~ /~-_
# /^\__/^\ /~ \ / \
# /| O|| O| / \_______________/ \
# | |___||__| / / \ \
# | \ / / \ \
# | (_______) /______/ \_________ \
# | / / \ / \
# \ \^\\ \ / \ /
# \ || \______________/ _-_ //\__//
# \ ||------_-~~-_ ------------- \ --/~ ~\ || __/
# ~-----||====/~ |==================| |/~~~~~
# (_(__/ ./ / \_\ \.
# (_(___/ \_____)_)
# ```
# %%
g.bind("thmont", THM)
g.serialize("lego_graph_rebrickable.ttl", format="turtle")

View File

@ -10,13 +10,14 @@
},
{
"cell_type": "code",
"execution_count": 105,
"execution_count": 257,
"id": "90209948",
"metadata": {},
"outputs": [],
"source": [
"from rdflib import Graph, Namespace, XSD, OWL, RDF, RDFS, SKOS, URIRef, Literal\n",
"import pandas as pd"
"import pandas as pd\n",
"import numpy as np"
]
},
{
@ -29,7 +30,7 @@
},
{
"cell_type": "code",
"execution_count": 106,
"execution_count": 258,
"id": "8e573135",
"metadata": {},
"outputs": [],
@ -57,7 +58,7 @@
},
{
"cell_type": "code",
"execution_count": 107,
"execution_count": 259,
"id": "d8a1fe84",
"metadata": {},
"outputs": [],
@ -86,7 +87,7 @@
},
{
"cell_type": "code",
"execution_count": 108,
"execution_count": 260,
"id": "ae505704",
"metadata": {},
"outputs": [],
@ -117,7 +118,7 @@
},
{
"cell_type": "code",
"execution_count": 109,
"execution_count": 261,
"id": "fb9e17d6",
"metadata": {},
"outputs": [],
@ -139,7 +140,7 @@
},
{
"cell_type": "code",
"execution_count": 110,
"execution_count": 262,
"id": "8fdb080e",
"metadata": {},
"outputs": [],
@ -163,7 +164,7 @@
},
{
"cell_type": "code",
"execution_count": 111,
"execution_count": 263,
"id": "579b1d67",
"metadata": {},
"outputs": [],
@ -193,7 +194,7 @@
},
{
"cell_type": "code",
"execution_count": 112,
"execution_count": 264,
"id": "00db079a",
"metadata": {},
"outputs": [],
@ -216,7 +217,7 @@
},
{
"cell_type": "code",
"execution_count": 113,
"execution_count": 265,
"id": "1a529aae",
"metadata": {},
"outputs": [],
@ -241,7 +242,7 @@
},
{
"cell_type": "code",
"execution_count": 114,
"execution_count": 266,
"id": "29b357ef",
"metadata": {},
"outputs": [],
@ -267,7 +268,7 @@
},
{
"cell_type": "code",
"execution_count": 115,
"execution_count": 267,
"id": "a67b3e70",
"metadata": {},
"outputs": [],
@ -290,7 +291,7 @@
},
{
"cell_type": "code",
"execution_count": 116,
"execution_count": 268,
"id": "0c97dc4d",
"metadata": {},
"outputs": [],
@ -313,7 +314,7 @@
},
{
"cell_type": "code",
"execution_count": 117,
"execution_count": 269,
"id": "dc2ba03e",
"metadata": {},
"outputs": [
@ -323,7 +324,7 @@
"'\\nfor inventory_part in re_inventory_parts.itertuples(index=False):\\n inventory_part_ref = thm[f\"inventory_part/{inventory_part.inventory_id}/{inventory_part.part_num}\"]\\n\\n inventory_ref = thm[f\"inventory/{inventory_part.inventory_id}\"]\\n part_ref = thm[f\"part/{inventory_part.part_num}\"]\\n\\n g.add((inventory_part_ref, RDF.type, THM.PartInv))\\n g.add((inventory_part_ref, RDF.type, RDF.Property))\\n\\n g.add((inventory_part_ref, RDFS.domain, THM.Inventory))\\n g.add((inventory_part_ref, RDFS.range, THM.Part))\\n\\n g.add((inventory_ref, THM.contains, inventory_part_ref))\\n g.add((part_ref, THM.belongs, inventory_part_ref))\\n\\n g.add((inventory_part_ref, THM.quantity, Literal(int(inventory_part.quantity), datatype=XSD.integer)))\\n g.add((inventory_part_ref, THM.is_spare, Literal(inventory_part.is_spare, datatype=XSD.boolean)))\\n g.add((inventory_part_ref, THM.color, thm[f\"color/{inventory_part.color_id}\"]))\\n'"
]
},
"execution_count": 117,
"execution_count": 269,
"metadata": {},
"output_type": "execute_result"
}
@ -353,7 +354,7 @@
},
{
"cell_type": "code",
"execution_count": 118,
"execution_count": 270,
"id": "8715a1cf",
"metadata": {},
"outputs": [],
@ -378,7 +379,7 @@
},
{
"cell_type": "code",
"execution_count": 119,
"execution_count": 271,
"id": "08c2c580",
"metadata": {},
"outputs": [],
@ -419,7 +420,7 @@
},
{
"cell_type": "code",
"execution_count": 120,
"execution_count": 272,
"id": "1e0ac437",
"metadata": {},
"outputs": [],
@ -438,7 +439,7 @@
},
{
"cell_type": "code",
"execution_count": 121,
"execution_count": 273,
"id": "fd944ccb",
"metadata": {},
"outputs": [],
@ -468,7 +469,7 @@
},
{
"cell_type": "code",
"execution_count": 122,
"execution_count": 274,
"id": "307a3210",
"metadata": {},
"outputs": [],
@ -479,9 +480,9 @@
" \n",
" if (element_ref, None, None) in g:\n",
" if not pd.isna(bs_element.BrickLinkSoldPriceNew):\n",
" g.add((element_ref, THM.price_new, Literal(bs_element.BrickLinkSoldPriceNew)))\n",
" g.add((element_ref, THM.price_new, Literal(bs_element.BrickLinkSoldPriceNew, datatype=XSD.float)))\n",
" if not pd.isna(bs_element.BrickLinkSoldPriceUsed):\n",
" g.add((element_ref, THM.price_used, Literal(bs_element.BrickLinkSoldPriceNew)))"
" g.add((element_ref, THM.price_used, Literal(bs_element.BrickLinkSoldPriceUsed, datatype=XSD.float)))"
]
},
{
@ -496,7 +497,7 @@
},
{
"cell_type": "code",
"execution_count": 123,
"execution_count": 275,
"id": "a8beb593",
"metadata": {},
"outputs": [],
@ -508,7 +509,7 @@
},
{
"cell_type": "code",
"execution_count": 124,
"execution_count": 276,
"id": "bbf5462b",
"metadata": {},
"outputs": [],
@ -527,7 +528,7 @@
},
{
"cell_type": "code",
"execution_count": 125,
"execution_count": 277,
"id": "ef52582e",
"metadata": {},
"outputs": [
@ -537,7 +538,7 @@
"'\\nfor bl_part in bl_parts.itertuples(index=False):\\n part_ref = thm[f\"part/{bl_part.part_id}\"]\\n\\n if not (part_ref, None, None) in g:\\n additional_entries += 1\\n g.add((part_ref, RDFS.label, Literal(bl_part.part_name, lang=\"en\")))\\n'"
]
},
"execution_count": 125,
"execution_count": 277,
"metadata": {},
"output_type": "execute_result"
}
@ -555,17 +556,17 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 278,
"id": "8bf0ffeb",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'\\nfor bl_minifig in bl_minifigs.itertuples(index=False):\\n minifig_ref = thm[f\"minfig/{bl_minifig.minifig_id}\"]\\n\\n if not (minifig_ref, None, None) in g:\\n additional_entries += 1\\n g.add((minifig_ref, RDFS.label, Literal(bl_minifig.minifig_name, lang=\"en\")))\\n'"
"'\\nfor bl_minifig in bl_minifigs.itertuples(index=False):\\n minifig_ref = thm[f\"minfig/{bl_minifig.minifig_id}\"]\\n\\n if not (minifig_ref, None, None) in g:\\n g.add((minifig_ref, RDFS.label, Literal(bl_minifig.minifig_name, lang=\"en\")))\\n'"
]
},
"execution_count": 126,
"execution_count": 278,
"metadata": {},
"output_type": "execute_result"
}
@ -590,7 +591,7 @@
},
{
"cell_type": "code",
"execution_count": 127,
"execution_count": 279,
"id": "ab1ec488",
"metadata": {},
"outputs": [],
@ -600,13 +601,54 @@
},
{
"cell_type": "code",
"execution_count": 128,
"execution_count": 293,
"id": "9bcd2956",
"metadata": {},
"outputs": [],
"source": [
"t = me_sets[me_sets[\"brand\"] == \"Pantasy\"]"
]
},
{
"cell_type": "code",
"execution_count": 294,
"id": "9ab21460",
"metadata": {},
"outputs": [],
"source": [
"t[\"ratio\"] = t[\"price_eur\"] / t[\"num_parts\"]"
]
},
{
"cell_type": "code",
"execution_count": 295,
"id": "459c3a4c",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"np.float64(0.43016261640379705)"
]
},
"execution_count": 295,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"t[\"ratio\"].mean()"
]
},
{
"cell_type": "code",
"execution_count": 282,
"id": "bfcf2840",
"metadata": {},
"outputs": [],
"source": [
"for me_set in me_sets.itertuples(index=False):\n",
" if not pd.isna(me_set.brand) or not pd.isna(me_set.id):\n",
" if not pd.isna(me_set.brand) and not pd.isna(me_set.id):\n",
" set_ref = thm[f\"set/{me_set.brand}/{me_set.id}\"]\n",
"\n",
" g.add((set_ref, RDF.type, THM.Set))\n",
@ -617,6 +659,7 @@
" if not pd.isna(me_set.num_parts):\n",
" g.add((set_ref, THM.num_parts, Literal(int(me_set.num_parts), datatype=XSD.integer)))\n",
" g.add((set_ref, THM.brand, Literal(me_set.brand)))\n",
" if not pd.isna(me_set.price_eur):\n",
" g.add((set_ref, THM.price_new, Literal(me_set.price_eur, datatype=XSD.float)))"
]
},
@ -654,17 +697,17 @@
},
{
"cell_type": "code",
"execution_count": 129,
"execution_count": 283,
"id": "1a30bff8",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<Graph identifier=Nd2a4a6354de049cc955729248a1f3472 (<class 'rdflib.graph.Graph'>)>"
"<Graph identifier=Naee4bab906a6444290a3659ffe0fbd45 (<class 'rdflib.graph.Graph'>)>"
]
},
"execution_count": 129,
"execution_count": 283,
"metadata": {},
"output_type": "execute_result"
}

View File

@ -49,7 +49,7 @@
%... then configure it.
\fancyhead{} % clear all header fields
\fancyhead[L]{Lego}
\fancyhead[R]{KGR - Knowledgegraphen}
\fancyhead[R]{KGR - Knowledge Graphen}
\fancyfoot{} % clear all footer fields
\fancyfoot[LE,RO]{\thepage}
@ -83,7 +83,7 @@
\subsection{Nutzen}
Wird ein Set an Klemmbausteinen nicht mehr vertrieben und man möchte das Set dennoch haben, so ergeben sich mehrere Möglichkeiten:
Wird ein Set an Klemmbausteinen nicht mehr vertrieben, an welchem dennoch Nachfrage besteht, existieren folgende Möglichkeiten:
\begin{itemize}
\item Man kauft das Set von einem Zweitanbieter
\item Man stellt sich die benötigten Teile des Sets selbst zusammen. Dies geschieht entweder indem die Teile einzeln von Zweitanbietern gekauft werden oder durch den Erwerb von anderen Sets, welche die benötigten Teile enthalten. Siehe Fragen: \ref{item:min_set_count} und \ref{item:min_set_price}.
@ -211,17 +211,15 @@ https://thm.de/set/{brand}/{id}
\label{fig:pipeline}
\end{figure}
\section{Evaluation}
\subsection{Ergebnis}
Das Projekt kann unter der URL: \url{https://gitty.informatik.hs-mannheim.de/2211275/kgr} betrachtet werden.
Der resultierende Knowledge-Graph ist über 300 MB gross.
Der resultierende Knowledge-Graph ist über 300 MB gross. Die Dateigrösse lässt sich auf die Zuordnungen von Teilen zu Inventaren zurückführen.
\subsection{Beispiel-Queries}
Erhalten der Gesamtheit aller Lego Star Wars Minifiguren:
\begin{verbatim}
SELECT DISTINCT ?name
WHERE {
@ -237,7 +235,7 @@ WHERE {
?minifig rdfs:label ?name.
}
\end{verbatim}
Welche Minifiguren kommen am häufigsten vor?
Anzahl aller Minifiguren enthalten in allen Lego-Sets gruppiert nach Figur.
\begin{verbatim}
SELECT
(SUM(?quantity) as ?sum) ?minifig ?name
@ -251,7 +249,7 @@ WHERE {
GROUP BY ?minifig ?name
ORDER BY DESC(?sum)
\end{verbatim}
Durchschnittliche Anzahl an Teilen je Set gruppiert nach Jahren
Durchschnittliche Anzahl an Teilen je Set gruppiert nach Jahren.
\begin{verbatim}
SELECT ?year (AVG(?part_count) as ?avgp)
WHERE {
@ -259,18 +257,68 @@ WHERE {
?set thm:num_parts ?part_count.
}
GROUP BY ?year
ORDER BY DESC(?avgp
)
ORDER BY DESC(?avgp)
\end{verbatim}
Durchschnittlicher Teilepreis gruppiert nach Marken. \label{verb:ppp_query}
\begin{verbatim}
SELECT ?brand (AVG(?price)/AVG(?num) as ?t)
WHERE {
?set thm:num_parts ?num.
?set rdfs:label ?name.
?set rdf:type thm:Set.
?set thm:brand ?brand.
?set thm:price_new ?price.
FILTER (?num > 0)
}
GROUP BY ?brand
ORDER BY DESC(?t)
\end{verbatim}
\subsection{Abdeckung}
Tabelle \ref{tab:coverage} zeigt einen Überblick welche der Prädikate (Graph, Name, Kategorie, Preise, Jahr) der Knowledge Graph für Minifiguren (Figs), Teile und Sets abdeckt (X=enthalten,-=Fehlt). Das Prädikat \textit{Graph} spiegelt wider, ob das Prädikat im Graph vorhanden ist.
\begin{table}[H]
\centering
\begin{tabular}{@{}lllllll@{}}
\toprule
& \multicolumn{3}{l}{Lego} & \multicolumn{3}{l}{Andere Marken} \\ \midrule
& Figs & Teile & Sets & Figs & Teile & Sets \\ \midrule
Graph & X & X & X & - & - & X \\
Name & X & X & X & - & - & X\\
Kateg. & - & X & X & - & - & - \\
Preise & - & X & X & - & - & X \\
Jahr & - & - & X & - & - & X \\ \bottomrule
\end{tabular}
\caption{Abdeckung des Graphen für Lego und weitere Klemmbausteinmarken}
\label{tab:coverage}
\end{table}
Da Lego keine IDs für Minifiguren vergibt ist das erkennen zweier gleichartiger Figuren schwieriger. Die Preise von \textit{Brickset} konnten nicht den Minifiguren aus \textit{Rebrickable} zugeordnet werden. Da \textit{Rebrickable} die Zuordnung von Minifiguren zu Sets liefert, wurde die Entscheidung getroffen auf die Preiszuordnung zu verzichten. Für Figuren und Teile weiterer Marken, waren eine Zuordnung nur schwer bis gar nicht möglich. Diese Zuordnung wäre beispielsweise durch Bilderkennung, anhand vom Hersteller bereitgestellte Bauanleitungen in Form von .PDF-Dateien möglich.
\subsection{Konsistenz}
\subsection{Qualität}
Es wird betrachtet, ob die ursprünglichen Fragestellungen mithilfe des Knowledge Graphen beantwortet werden können.
\begin{enumerate}
\item Was ist die minimale Anzahl an Sets, die benötigt wird um ein anderes Set zusammenzubauen?
\item Was ist der geringste Preis einer Auswahl an Sets um ein anderes Set zusammenzubauen?
\item Sind Sets von anderen Herstellern im Vergleich zu Lego Sets, auf den durchschnittlichen Teilepreis betrachtet billiger?\\
\textit{Diese Frage kann mithilfe der letzten Beispiel-Query \ref{verb:ppp_query} beantwortet werden.
\begin{figure}[H]
\centering
\includegraphics[width=\columnwidth]{./bilder/diagram_avg_part_price_brand.png}
\caption{Hersteller sortiert nach durchschnittlichem Teile-Preis}
\label{fig:ppp}
\end{figure}
}
\item Haben neuere Sets im Vergleich zu älteren Sets eine geringere Teileanzahl, da auf eine grössere Anzahl an speziell angefertigten Teilen zugegriffen werden kann?
\item Haben Sets mit höherer Teileanzahl eine höhere Anzahl an Minifiguren?
\item Welche anderen Sets, können mit Sets, die sich schon im eigenen Besitz befinden zusammengebaut werden?
\item Welche Lego-Teile besitzen äquivalente Teile von anderen Marken?\\
\textit{Der Knowledge Graph bietet keine Möglichkeit dies zu beantwortet, da keine Datensätze über Teile, die nicht von Lego produziert worden sind, in die Erstellung des Graph eingeflossen sind.}
\end{enumerate}
\section{Ausblick}
\section*{Abkürzungsverzeichnis}

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,6 @@
"brand","t"
"Lego","0.09687904"
"Cobi","0.07586302"
"Pantasy","0.05728256"
"MouldKing","0.05323224"
"BlueBrixx","0.043733075"
1 brand t
2 Lego 0.09687904
3 Cobi 0.07586302
4 Pantasy 0.05728256
5 MouldKing 0.05323224
6 BlueBrixx 0.043733075

Binary file not shown.