Lernen von Prototypen über Baumstrukturen Entwicklung und

Werbung
Lernen von Prototypen über
Baumstrukturen
Entwicklung und Evaluation
eines Verfahrens zum
Structural Incident Mining
Bachelorarbeit
im Studiengang Wirtschaftsinformatik der Fakultät
Wirtschaftsinformatik und Angewandte Informatik der
Otto-Friedrich-Universität Bamberg
Verfasser:
Gutachter:
Stefan Betzmeir
Prof. Dr. Ute Schmid
Zusammenfassung
Verschiedenste Data Mining Verfahren sind seit langem bewährte Werkzeuge, um aus einer Menge von Datensätzen Muster und damit neue
Erkenntnisse abzuleiten. Dabei sind die Quellen dieser Daten ebenso vielfältig wie deren Auswertungsmöglichkeiten. Standardverfahren
zur Datenaufbereitung und Analyse sind daher längst in nahezu allen
Bereichen von Forschung und Wirtschaft im Einsatz.
Typischerweise geht man dabei von Daten auf Basis eines festen
Datenschemas aus, deren Ausprägungen sich durch einen einfachen
Merkmalsvektor darstellen lassen, wie es z.B. bei einer Kundenadresskartei der Fall ist. Sobald jedoch Beziehungen zwischen verschiedenen
Entitäten abgebildet werden, entsteht dadurch strukturelle Dynamik.
Ein Kunde muss beispielsweise mit beliebig vielen Aufträgen und diese wiederum mit einer variablen Anzahl von Artikeln in Beziehung
gesetzt werden können. Um auf derartigen Daten Analysen mit den
eingangs genannten Verfahren durchführen zu können, ist es daher
gängige Praxis diese in eine flache und damit von Strukturinformationen bereinigte Darstellung zu bringen. Das ist nur dann möglich,
wenn die Semantik der Strukturellen Beziehungen bekannt, bzw. nicht
von Interesse bezüglich des Untersuchungsziels ist. In diesen Strukturinformationen verbirgt sich jedoch implizites Wissen über relationale
und kausale Zusammenhänge.
Deutlich wird dieser Aspekt am Beispiel des Customer-Supports einer Softwarefirma. Sie könnte ihre Software derart gestalten, dass beim
Auftreten eines Fehlers ein strukturiertes Abbild der Zustände ihrer
Komponenten gespeichert wird. Aufgabe des Service-Mitarbeiters ist
es dann, die Ursache eines Fehlers anhand dieser Daten zu lokalisieren.
In diesen Informationen, in Kombination mit dem Wissen über kausale
Zusammenhänge innerhalb der Software, kann der Service-Mitarbeiter
Muster erkennen, die ursächlich für den Fehler sind und einen Lösungsvorschlag anbieten. Derartige Geschäftsprozesse, die von Expertenwissen abhängig sind und manueller Datenverarbeitung bedürfen,
sind sehr Kostenintensiv und schlecht skalierbar, da sie üblicherweise
nicht automatisierbar sind. Mit Hilfe von Data Mining Verfahren könnte daher versucht werden Gemeinsamkeiten zwischen Fehlerprotokollen zu entdecken, denen der selbe Fehler zugrunde liegt. Da gängige
Verfahren, wie das Lernen von Entscheidungsbäumen oder das Trainieren neuronaler Netze, strukturelle Informationen ignorieren, wird
die Qualität der Analyse dadurch jedoch stark beeinträchtigt.
In der vorliegenden Arbeit soll daher ein bestehender Ansatz von
Schmid, Hofmann, Bader, Häberle und Schneider (2010), zum Erlernen
von Prototypen aus strukturierten Daten, erweitert werden. Ein solcher
Prototyp bildet strukturelle und merkmalsbezogene Eigenschaften einer Menge von Datensätzen ab, die vorher durch einen Experten als
ähnlich, im Bezug auf eine bestimmte Fragestellung, identifiziert wurden. Ein so gewonnener Prototyp kann anschließend verwendet werden, um neue Datensätze automatisch zu Klassifizieren. Dabei wird
ein Datensatz mit allen Prototypen verglichen und der Klasse zugeordnet, deren Prototyp den Datensatz am besten, hinsichtlich der Struktur
und den Merkmalen, beschreibt. Die Prototypentheorie ahmt dabei eine erfolgreiche kognitive Fähigkeit des Menschen nach, aus Objekten
mit übereinstimmenden Merkmalen, Konzepte abzuleiten.
I N H A LT S V E R Z E I C H N I S
Abbildungsverzeichnis
v
Algorithmenverzeichnis
vi
1
2
3
4
einführung
1.1 Bisheriger Ansatz . . . . . . . . . .
1.1.1 Case-Based Reasoning . . .
1.1.2 Lernen von Prototypen . .
1.1.3 Data Mining . . . . . . . . .
1.1.4 Structural Incident Mining
1.2 Aufbau der Arbeit . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
1
1
1
2
2
2
analyse
2.1 Modellorientierter Ansatz . . . . . . . . . . . . .
2.1.1 Anti-Unifikation . . . . . . . . . . . . . .
2.1.2 Structure Dominance Tree Generalisation
2.1.3 Absolute Positionierung im Modell . . .
2.2 Instanzorientierter Ansatz . . . . . . . . . . . . .
2.2.1 Hierarchisch gewichtete Ähnlichkeit . . .
2.2.2 Ähnlichkeitsbasierte Alignierung . . . .
2.3 Multiple Sequence Alignment . . . . . . . . . . .
2.3.1 MSA in der Bioinformatik . . . . . . . . .
2.3.2 Progressive Alignierung . . . . . . . . . .
2.4 Paarweise Ähnlichkeit und Alignierung . . . . .
2.4.1 Needleman-Wunsch Algorithmus . . . .
2.4.2 Yangs Tree-Matching-Algorithmus . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4
4
4
4
4
7
7
8
10
10
11
12
12
16
design
3.1 Definitionen . . . . . . . . . . . . . . . . . . . . . . . . .
3.1.1 Datenstrukturen . . . . . . . . . . . . . . . . . .
3.1.2 Funktionen . . . . . . . . . . . . . . . . . . . . .
3.2 Prototypextraktion . . . . . . . . . . . . . . . . . . . . .
3.2.1 Einstiegspunkt . . . . . . . . . . . . . . . . . . .
3.2.2 Rekursion . . . . . . . . . . . . . . . . . . . . . .
3.2.3 Prototypisierungsstrategie . . . . . . . . . . . . .
3.3 Progressive Alignierung . . . . . . . . . . . . . . . . . .
3.3.1 Hierarchisches Clustering . . . . . . . . . . . . .
3.3.2 Berechnung der Clusterdistanz . . . . . . . . . .
3.4 Alignierung . . . . . . . . . . . . . . . . . . . . . . . . .
3.4.1 Erzeugen der Vereinigungssequenz . . . . . . .
3.4.2 Alignierung assoziierter Sequenzelemente . . .
3.4.3 Übernahme nicht assoziierter Sequenzelemente
3.5 Tree-Matching . . . . . . . . . . . . . . . . . . . . . . . .
3.5.1 Parametrisiertes Tree-Matching . . . . . . . . . .
3.5.2 Backtracking . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
18
18
18
21
22
22
23
23
25
26
27
28
28
29
30
31
31
34
.
.
.
.
.
.
.
.
.
35
35
36
37
37
39
39
41
41
42
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
implementierung
4.1 Umgang mit generischen Datentypen . . . . . . . .
4.1.1 Datenschnittstelle . . . . . . . . . . . . . . . .
4.1.2 Prototypschnittstelle . . . . . . . . . . . . . .
4.1.3 Typspezifische Strategien . . . . . . . . . . .
4.2 Prototypextraktion . . . . . . . . . . . . . . . . . . .
4.2.1 Prototypextraktion aus strukturierten Daten
4.2.2 Prototypingstrategie . . . . . . . . . . . . . .
4.3 Alignierung . . . . . . . . . . . . . . . . . . . . . . .
4.4 Clustering . . . . . . . . . . . . . . . . . . . . . . . .
iii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4.4.1 Hierarchisches Clustering . . . .
4.4.2 Linkage . . . . . . . . . . . . . .
4.4.3 Cluster . . . . . . . . . . . . . . .
Sequence-Matching . . . . . . . . . . . .
4.5.1 Hierarchical Sequence-Matching
4.5.2 Caching von Ergebnissen . . . .
4.5.3 Hierarchical Tree-Matching . . .
4.5.4 Sequenz . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
42
43
44
46
46
47
47
47
resümee und ausblick
5.1 Evaluation . . . . . . . . . . . . . . . . .
5.2 Anknüpfungspunkte . . . . . . . . . . .
5.2.1 Empirische Ergebnisse . . . . . .
5.2.2 Iterative Alignierung . . . . . . .
5.2.3 Automatisches Clustering . . . .
5.2.4 Globale Alignierung . . . . . . .
5.2.5 Neuer modellorientierter Ansatz
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
49
49
49
49
50
50
50
50
4.5
5
Literaturverzeichnis
51
iv
ABBILDUNGSVERZEICHNIS
Abbildung 1
Abbildung 2
Abbildung 3
Abbildung 4
Abbildung 5
Abbildung 6
Abbildung 7
Abbildung 8
Abbildung 9
Abbildung 10
Abbildung 11
Abbildung 12
Abbildung 13
Abbildung 14
Abbildung 15
Abbildung 16
Abbildung 17
Abbildung 18
Abbildung 19
Abbildung 20
Abbildung 21
Abbildung 22
Abbildung 23
Abbildung 24
Abbildung 25
Abbildung 26
Abbildung 27
Modell als reguläre Grammatik . . . . . . . . . .
Modell in Baumdarstellung . . . . . . . . . . . . .
Instanzen eines Modells . . . . . . . . . . . . . . .
Ein SDTG Prototyp . . . . . . . . . . . . . . . . . .
Alignierung von Knoten . . . . . . . . . . . . . . .
Lokal optimale Alignierung von Knoten . . . . .
Initialzustand der Matrizen . . . . . . . . . . . . .
Alternative Pfade einer Alignierung . . . . . . . .
Matching zweier Sequenzelemente . . . . . . . . .
Fertig errechnete Matrizen . . . . . . . . . . . . .
Komponenten einer Sequenz . . . . . . . . . . . .
Unterschiedliche Datendarstellung . . . . . . . . .
Datenschnittstelle ITreeNode . . . . . . . . . . . . .
Prototypenschnittstelle IPrototype . . . . . . . . .
Typspezifische Strategien . . . . . . . . . . . . . .
Extraktionsschnittstelle IPrototypeExtraction . . .
Prototypextraktion aus Baumstrukturen . . . . .
Prototypingstrategien . . . . . . . . . . . . . . . .
Alignierungsschnittstelle IAlignment . . . . . . . .
Beziehung zwischen den Komponenten der Alignierung . . . . . . . . . . . . . . . . . . . . . . . .
Clusteringschnittstelle IClusterManager . . . . . .
ILinkage als Schnittstelle zur Berechnung der Clusterdistanz . . . . . . . . . . . . . . . . . . . . . . .
AbstractCluster als Cluster-Supertyp . . . . . . . .
LeafCluster, der einelementige Cluster . . . . . . .
LinkCluster als Verbindung zwischen zwei Clustern
Hierarchical Sequence-Matching . . . . . . . . . .
Die Sequenz als Komposition aus drei Datenstrukturen . . . . . . . . . . . . . . . . . . . . . . . . . .
v
5
5
6
6
9
9
14
14
15
15
20
36
36
37
38
39
40
40
41
42
43
43
45
45
45
46
48
ALGORITHMENVERZEICHNIS
1
2
Needleman-Wunsch Algorithmus . . . . . . . . . . . . .
Yangs Tree-Matching-Algorithmus . . . . . . . . . . . . .
12
17
3
4
5
6
7
8
9
10
11
12
13
14
Einstiegspunkt der Prototypenextraktion . . . .
Rekursive Prototypenextraktion . . . . . . . . . .
Prototypingstrategie “Anti-Unifikation” . . . . .
Prototypingstrategie “SDTG” . . . . . . . . . . .
Einstiegspunkt der progressiven Alignierung . .
Hierarchisches Clustering . . . . . . . . . . . . .
Berechnung der Distanz zweier Cluster . . . . .
Globale Alignierung der Sequenzen . . . . . . .
Assoziierte Sequenzelemente alignieren . . . . .
Nicht-Assoziierte Sequenzelemente hinzufügen
Hierarchical Tree-Matching-Algorithmus . . . .
Backtracking . . . . . . . . . . . . . . . . . . . . .
23
23
24
25
26
27
28
29
30
31
33
34
vi
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
EINFÜHRUNG
1.1
bisheriger ansatz
Die vorliegende Arbeit setzt auf den Ergebnissen einer Zusammenarbeit zwischen dem Lehrstuhl für Kognitive Systeme der Otto-FriedrichUniversität Bamberg und der Firma SAP auf, die im Rahmen der Masterarbeit von Bader (2009) stattgefunden hat. Dabei sollten Lösungen
erarbeitet werden, um Geschäftsprozesse im Kundenservice, bezüglich der Software ByDesign, durch maschinelle Lernverfahren zu automatisieren. Diese Software bietet dem Benutzer, beim Auftreten eines
Softwarefehlers, einen Dialog an, um eine Störungsmeldung an das
Service-Center zu schicken. Dort kann der Benutzer Informationen angeben, die für die Fehlerbehebung von Nutzen sein könnten. Zusätzlich wird der Zustand des Anwendungssystems, zum Zeitpunkt des
Fehlers, gespeichert. Mit Hilfe dieser Daten kann der Service-Mitarbeiter
feststellen, welche Ursachen den Fehler ausgelöst haben und dem Kunden entsprechend Hilfestellung leisten. Alle gelösten Störungsmeldungen werden zudem in einer Datenbank gespeichert, so dass bei ähnlichen Fällen in der Zukunft auf bereits ermittelte Lösungen zurückgegriffen werden kann. Das Bestreben war es nun, ein Verfahren zu
finden, mit dessen Hilfe man die Klassifikation neu eintreffender Störungsmeldungen, auf Basis bereits gefundener Lösungen, automatisieren kann, um so den personalintensiven Support zu entlasten und Kosten zu sparen.
1.1.1
Case-Based Reasoning
Als Grundlage diente hierfür der von Agnar und Plaza (1994) entwickelte Rahmen für das fallbasierte Schließen (case-based reasoning). Entsprechend dem case-based resoning Zyklus (Agnar & Plaza, 1994, S. 7 f.)
wird dabei zunächst für einen neu eintreffenden Fall in der Datenbank
nach einem bereits gelösten Fall gesucht, der dem neuen am ähnlichsten ist. Daraufhin wird die damit assoziierte Information wiederverwendet, die vorgeschlagene Lösung an den neuen Fall angepasst und
daraus resultierende Erkenntnisse wiederum für zukünftige Abfragen
gespeichert. Der Vorteil und zugleich der Nachteil eines case-based reasoning Verfahrens ist der Umfang der Datenbank, der mit jedem gelösten Fall zunimmt. Zwar nimmt so die Wahrscheinlichkeit zu, für
ein neues Problem eine bereits vorhandene Lösung zu finden, jedoch
dauert auch die Klassifikation eines neu eintreffenden Falles dadurch
immer länger.
1.1.2
Lernen von Prototypen
Da die ByDesign Störungsmeldungen von den SAP Service-Mitarbeitern
sogenannten “Master-Incidents” zugeordnet werden, also bereits gelösten Störungsmeldungen die von der Fehlerursache her ähnlich waren, wurde hierdurch bereits die Grundgesamtheit der Störungsmeldungen in Cluster ähnlicher Fälle unterteilt. Anstatt nun eine neu eintreffende Störungsmeldung mit allen Störungsmeldungen eines Clusters zu vergleichen, könnte sie stattdessen mit einem Clusterprototypen verglichen werden, der die gemeinsamen Merkmale der Clusterelemente repräsentiert, was die Laufzeit der Abfrage deutlich reduzieren würde.
1
1.1.3
Data Mining
Beispielsweise könnte für jedes Cluster von Daten, ein Entscheidungsbaum gelernt oder ein neuronales Netz trainiert werden. Eine neu eintreffende Störungsmeldung könnte dann automatisch der passendsten
Kategorie zugeordnet werden. Als Grundlage dieser und vieler anderer Data Mining Verfahren dienen hierzu Merkmalsvektoren. Prinzipiell könnte man die Störungsmeldungen, die im XML-Format vorliegen
und demnach eine Baumstruktur aufweisen, in eine “flache” Darstellung bringen. Dadurch würden jedoch implizite Strukturinformationen der Baumstruktur, wie Relationen und Abhängigkeiten, verlorengehen.
1.1.4
Structural Incident Mining
Um diese Strukturinformationen zu erhalten wurden verschiedene Verfahren zur Generalisierung gemeinsamer Strukturen, aus einer Menge
strukturierter Datensätze, evaluiert.
Anti-Unifikation
Mit der Anti-Unifikation wurde ein Verfahren ausgewertet, das ursprünglich zur Generalisierung von Termen entwickelt wurde. Die
Anti-Unifikation erzeugt aus einem Cluster strukturierter Datensätze deren Schnittmenge, d.h. nur die Strukturelemente, die in jedem
Datensatz an der selben Stelle vorkommen, werden Teil des so extrahierten Prototyps. Da dieses Vorgehen sehr empfindlich im Hinblick
auf verrauschte Daten ist, eignet es sich nur bedingt für die Prototypisierung von Störungsmeldungen, da die manuelle Klassifikation der
Daten durch Menschen fehlerbehaftet ist.
Structure Dominance Tree Generalisation
Darum wurde ein Ansatz auf Basis der Unifikation, also der Vereinigungsmenge der Strukturelemente aller Datensätze, entwickelt, in
dem sich dominante Strukturen ausprägen können, auch wenn diese
nicht in allen Instanzen vorhanden sind. Hierzu wird die Häufigkeit
des Auftretens eines Strukturelements relativ zu seinem Elternelement
gespeichert.
Modellorientierter Instanzvergleich
Der Vergleich zwischen den Datensätzen findet bei beiden Verfahren
mit Hilfe des Modells statt. Das Modell ist hierbei als ein Satz von Regeln zu verstehen, der die möglichen Merkmals- und Strukturausprägungen in den Instanzen bestimmt. Dabei muss das Modell als endlicher Baum darstellbar sein, da der Vergleich auf absoluten Positionen
innerhalb des Modells basiert. Diese Einschränkung bezüglich des Modells hat zur Folge, dass das bisherige Verfahren lediglich auf solche
strukturierten Daten angewendet werden kann, denen ein entsprechendes Modell zugrunde liegt, das diesen Anforderungen genügt.
1.2
aufbau der arbeit
Auf den bisherigen Ergebnissen aufbauend, wird in der vorliegenden
Arbeit ein modifizierter Ansatz zur Prototypextraktion aus strukturierten Daten entwickelt. Das Ziel ist es dabei die Restriktionen des modellorientierten Ansatzes aufzuheben, um die Prototypextraktion auf
jegliche Art baumartig strukturierter Daten anwenden zu können.
Dazu wird im Kapitel “Analyse” zunächst der bisherige, modellorientierte Ansatz analysiert, um die Gründe für dieser Restriktionen
2
Aufzudecken. Anschließend werden Verfahren aus der Bioinformatik,
zum Vergleich und zur Alignierung multipler Sequenzen, vorgestellt
und hinsichtlich der Eignung für die Prototypextraktion evaluiert. Um
das gewählte Verfahren für Baumstrukturen nutzbar zu machen, wird
zunächst dessen zentraler Algorithmus vorgestellt und mit einer für
Bäume geeigneten Variante verglichen.
Die Erkenntnisse aus der Analyse bilden das Fundament für den
Entwurf des neuen Verfahrens im Kapitel “Design”. Zunächst werden
die nötigen Datenstrukturen und Rahmenbedingungen definiert. Anschließend wird das gesamte Verfahren in Teilaufgaben zerlegt, in algorithmischer Form dargestellt und erläutert.
Im darauffolgenden Kapitel “Implementierung” wird die konkrete
Umsetzung des Verfahrens in der Programmiersprache Java erläutert.
Da der gesamte Ablauf bereits im Kapitel “Design” dargestellt wird,
liegt der Fokus bei der Implementierung auf den Designentscheidungen die getroffen wurden um die Software erweiterbar und wartbar
zu gestalten.
Abschließend folgt eine kritische Bewertung des entwickelten Ansatzes. Dabei werden Anknüpfungspunkte identifiziert die als Basis für
zukünftige Verbesserungen und Erweiterungen genutzt werden können.
3
2
A N A LY S E
Um das bisherigen Verfahre zum Lernen von Prototypen dahingehend
zu erweitern, um es potentiell auf jegliche Art baumartig strukturierter
Daten anwenden zu können, muss es zunächst analysiert und anschließend entsprechend angepasst werden.
2.1
modellorientierter ansatz
Die vorgestellten Lernverfahren, zur Erzeugung eines Prototypen aus
einem Cluster strukturierter Daten, setzen ein als Baum darstellbares
Modell voraus, das den Daten als Schema zugrunde liegt und damit
die Form seiner Instanzen vorgibt, wenn es heißt, “The incident model
– also called model tree – represents the general structure which is underlying each possible incident report and thereby restricts the form
of incident trees” (Schmid et al., 2010, S. 3). Die Funktion des Modells,
im Bezug auf die Prototyperstellung, zeigt sich, wenn man die Algorithmen au (Schmid et al., 2010, S. 4), auf Basis der Anti-Unifikation,
und sdtg (Schmid et al., 2010, S. 5), die Structure Dominance Tree Generalisation, näher betrachtet. Beide Algorithmen haben die Gemeinsamkeit, dass das Modell “top-down”, also bei der Wurzel beginnend,
traversiert und dabei jedes besuchte Modellelement M.p mit dem entsprechenden Element eines jeden Baumes I1 .p, ..., In .p im Cluster verglichen wird. Die Algorithmen unterscheiden sich jedoch in der Art
und Weise, wie sie aus den Korrespondierenden Elementen des Baumes das Prototypelement extrahieren.
2.1.1
Anti-Unifikation
Im Falle von au fließen die Merkmale eines Elements nur dann in den
Prototypen ein, wenn für die aktuell betrachtete Modellposition M.p
in jedem Baum des Clusters, an entsprechender Stelle, eine Übereinstimmung gefunden werden kann. Ist dies der Fall, wird der Algorithmus rekursiv mit den Kindknoten dieser Modellposition, sowie den
Kindknoten der entsprechenden Instanzelemente, fortgesetzt. Dieses
Verhalten führt jedoch zu einer hohen Anfälligkeit für verrauschte Daten, da für jede Position bereits eine Abweichung im Cluster zu einem
Ausschluss aus dem Prototypen führt (“Syntactic anti-unification is not
robust with respect to noise” (Schmid et al., 2010, S. 5)).
2.1.2
Structure Dominance Tree Generalisation
Im sdtg Algorithmus werden alle Elemente in den Prototypen aufgenommen. Dabei werden zusätzlich in jedem Prototypelement die Auftretenshäufigkeiten der repräsentierten Elemente, in Relation zu deren
Elternelementen, gespeichert. Der Algorithmus wird auch hier an jeder Position rekursiv mit den Kindknoten fortgesetzt. Somit erzeugt
der sdtg Algorithmus eigentlich eine Vereinigungsmenge der Instanzen eines Clusters, jedoch werden anhand der relativen Häufigkeiten
der Prototypelemente dominante Strukturen erkennbar.
2.1.3
Absolute Positionierung im Modell
Aus dem Vergleich der Algorithmen au und sdtg ist ersichtlich, dass
das Modell eine zentrale Rolle spielt, indem es anhand der Positio-
4
nen seiner Elemente festlegt, welche Elemente der Bäume miteinander
verglichen werden. Damit eine solche absolute Positionsbestimmung
möglich ist, wird in Definition 1 des model tree (Schmid et al., 2010, S.
3) gefordert, dass das Modell M als Baum fester Größe, mit Elementen
e des Typs τ, darstellbar sein muss. Dafür müssen im Modell folgende
Voraussetzungen erfüllt sein:
1. Für jeden Typ τ ist die Anzahl seiner Attribute, sowie deren Typ
fest
2. Ein Typ τ darf als Attribut nicht sich selbst enthalten
Zur Veranschaulichung dieser Gedanken soll ein einfaches Beispiel dienen.
Beispiel “Haustierbesitzer”
Es gilt das Datenmodell zur Speicherung von Haustierbesitzern zu
konzipieren. Von Interesse bezüglich der Person sind dabei der Name
sowie das Alter. Für das Haustier sind lediglich die Subklassen Hund
und Papagei zulässig. Die Klasse Hund erhält die Attribute Name und
Rasse. Ein Papagei soll die relevanten Attribute Name sowie Wörter – für
den Umfang des von ihm beherrschten Wortschatzes – enthalten. Als
Repräsentation des so definierten Modells bieten sich die Produktionen einer regulären Grammatik an.
σ → <BESITZER>
<BESITZER> → <NAME> <HAUSTIER> <ALTER>
<NAME> → [a-Z]+
<ALTER> → [0-9]+
<HAUSTIER> → <HUND>|<PAPAGEI>
<HUND> → <NAME> <RASSE>
<RASSE> → [a-Z]+
<PAPAGEI> → <NAME> <WÖRTER>
<WÖRTER> → [0-9]+
Abbildung 1: Modell als Produktionen einer regulären Grammatik
Diese Grammatik lässt sich als Baum fester Größe, d.h. als endlicher
Modellbaum darstellen (s. Abbildung 2). Zwei der daraus ableitbaren
Instanzen wären somit Instanz 1 und Instanz 2 (s. Abbildung 3).
Besitzer
Name
Haustier
Hund
Alter
Papagei
Name Rasse Name Wörter
Abbildung 2: Modell in Baumdarstellung
5
Besitzer
Besitzer
Name
Haustier
Alter
Name
Haustier
Alter
“Tim”
Hund
18
“John”
Papagei
40
Name
Rasse
“Struppi” “Terrier”
Instanz 1
Name
Wörter
“Captain Flint”
42
Instanz 2
Abbildung 3: Zwei Instanzen des Modells
Wendet man nun den sdtg Algorithmus auf den Cluster bestehend aus
Instanz 1 und Instanz 2 an, so ergibt sich der in Abbildung 4 dargestellte Prototyp.
Besitzer [2/2]
Name [2/2]
Tim [1/2]
John [1/2]
Haustier [2/2]
Hund [1/2]
Name [1/1]
Struppi [1/1]
Rasse [1/1]
Terrier [1/1]
Papagei [1/2]
Name [1/1]
Captain Flint [1/1]
Wörter [1/1]
42 [1/1]
Alter [2/2]
18 [1/2]
40 [1/2]
Abbildung 4: Der aus Instanz 1 und Instanz 2 abgeleitete Prototyp
Der bisherige sdtg Algorithmus ist somit in der Lage nicht nur relative Häufigkeiten in den Blättern zu zählen, was in einem Merkmalsvektor ohne Strukturinformationen ebenfalls möglich wäre, sondern
er bewahrt gleichzeitig strukturabhängige Informationen im Bezug
auf Merkmalsausprägungen die sich aus dem Auftreten verschiedener
Subtypen, wie im Beispiel Hund und Papagei als Subtypen von Haustier,
ergeben.
Einschränkungen des Modells
Die eingangs genannten Voraussetzungen bezüglich des Modells lassen sich nun leicht nachvollziehen, indem man neue Anforderungen
an unser Datenmodell stellt.
variable anzahl von attributen Beispielsweise könnte es interessant sein, nicht nur die Anzahl, sondern auch die konkreten Wörter zu speichern, die ein Papagei sprechen kann. Das könnte man beispielsweise durch folgende Produktionen ausdrücken:
6
<PAPAGEI> → <NAME> <WORT>*
<WORT> → [a-Z]+
Durch die Kleene’sche Hülle wären somit für jeden Papagei null bis beliebig viele Worte aufzählbar. Dadurch wäre das Modell jedoch nicht
mehr als Baum darstellbar, da dieser, um den Elementvergleich anleiten zu können, sozusagen für null bis beliebig viele Wortinstanzen
einen “Platz” vorsehen müsste. Der Baum würde sich an dieser Stelle
unendlich in die Breite ausdehnen und das Modell hiermit Voraussetzung 1 verletzen.
rekursive attribute Es könnte auch ein weiterer interessanter
Aspekt hinsichtlich der Datenanalyse sein, wie sich die Haustierhaltung innerhalb einer Familie über mehrere Generationen entwickelt
hat. Dazu könnte man jeder Person die Attribute Mutter und Vater verleihen, die wiederum vom Typ Person wären. Als Produktionen müsste
man das Modell, an der entsprechenden Stelle, wie folgt verändern:
<PERSON> → <NAME> <HAUSTIER> <ALTER>
<MUTTER> <VATER>
<MUTTER> → <PERSON>?
<VATER> → <PERSON>?
Es muss erlaubt sein, dass der Stammbaum ein absehbares Ende haben
darf, ausgedrückt durch den Quantoren ?, was der Kardinalität “null
bis eins” entspricht. Jedoch ergibt sich nun ein ähnliches Problem wie
schon im vorherigen Beispiel: Der Modellbaum müsste eine potentiell
unendliche Rekursion zurück durch die “Generationen” einer Person
vorsehen, wodurch er unendlich in die Tiefe wachsen würde. Hierdurch würde Voraussetzung 2 verletzt.
2.2
instanzorientierter ansatz
In der vorliegenden Arbeit soll nun versucht werden, auf Basis des
SDTG Ansatzes, eine neue Herangehensweise zu entwickeln die es erlaubt, ein breiteres Spektrum an strukturierten Daten zu verarbeiten.
Ziel soll es sein die bisherigen Einschränkungen im Bezug auf das Modell fallen zu lassen, wodurch es möglich sein wird das SDTG Verfahren auf alle Daten anzuwenden, dessen Modell als reguläre Grammatik (Typ 3 der Chomsky Hierarchie) darstellbar ist. Da hierdurch eine
Orientierung des Elementvergleichs auf Basis eines endlichen Modellbaumes nicht mehr möglich ist, muss eine andere Lösung gefunden
werden um strukturelle Entsprechungen zwischen 2 bis n Datensätzen
zu aufzudecken. Eine Möglichkeit ist der im folgenden betrachtete instanzorientierte Ansatz.
2.2.1
Hierarchisch gewichtete Ähnlichkeit
Setzt man für einen Cluster von Daten voraus, dass jedes seiner Elemente aus dem selben Datenmodell hervorgegangen ist, so können
diese auch ohne Kenntnis des Modells verglichen werden. Betrachtet
man die bisher genutzten Algorithmen, so fällt auf, dass zwar das
Modell bestimmt, an welcher Position der jeweils nächste Vergleich
stattfindet, jedoch dass an dieser Position letztendlich der Typ des Instanzelements das Aussehen des Prototypen und den Fortgang des
Verfahrens bestimmt. Es gilt also für jedes Element einer Instanz ein
entsprechendes Element in den anderen Instanzen zu finden, worauf
der jeweilige Algorithmus rekursiv, mit diesen Elementen als Wurzeln,
aufgerufen werden kann. Es ist naheliegend, dass man Elemente die
7
den gleichen Typ aufweisen als identisch betrachtet. Bei den denkbar
einfachsten Bäumen, also einelementigen Wurzeln, ist es trivial identische Elemente zu identifizieren:
A1
A2
B3
A1 hat den selben Typ wie A2 , B3 korrespondiert mit keinem anderen
Element. Fügt man den Wurzelknoten nun jeweils ein Kind hinzu, ist
die Frage nach der Identität nicht mehr intuitiv lösbar.
A1
A2
B3
C1
D2
C3
Nun korrespondiert zwar der Typ des Wurzelknotens A1 mit dem des
Wurzelknotens A2 , jedoch sind deren Kindknotentypen C1 und D2
nicht identisch. Auf der anderen Seite sind die Typen der Wurzelknoten A1 und B3 verschieden, jedoch gleichen sich deren Kindknotentypen C1 und C3 . Egal welche beiden Bäume man herausgreift, man
könnte nicht mehr behaupten sie seien identisch sondern man müsste
sie als ähnlich bezeichnen. Da man Identität auch als maximale Ähnlichkeit darstellen kann, wird, gerade im Hinblick auf die unterschiedlich Semantik des Begriffs “Identität”, im Folgenden bezüglich des Vergleichs von Elementen der Begriff “Ähnlichkeit” verwendet. Die Ähnlichkeit zweier Knoten, wird also nicht nur lokal durch die Ähnlichkeit
zweier Typen, sondern auch durch die Ähnlichkeit ihrer Kindknoten
beeinflusst. Die Ähnlichkeit zweier Knoten ist somit nichts anderes,
als der rekursive Vergleich zweier Bäume. Da Bäume jedoch eine Hierarchie beschreiben, würde man die lokale Ähnlichkeit der Wurzelknotentypen stets stärker gewichten als die durch Rekursion ermittelte
Ähnlichkeit ihrer Kinder, so dass deren Einfluss zu den Blättern hin
abnimmt. Durch die rekursive Bestimmung der Ähnlichkeit ist nun eine Beschränkung im Bezug auf das Modell aufgehoben und es darf
jetzt rekursive Produktionen wie diese enthalten:
<A> → <A>?
2.2.2
Ähnlichkeitsbasierte Alignierung
Die zweite Beschränkung des Modells lag darin, dass jeder Typ eine
feste Anzahl von Attributen aufweisen musste. Hebt man diese Einschränkung auf, so wäre beispielsweise folgende Produktion möglich:
<A> → <B>*
8
Jetzt ergibt sich ein neues Problem, denn nun muss zur Bestimmung
der Ähnlichkeit von A1 zu A2 zusätzlich geklärt werden, mit welchem
Knoten des zweiten Baumes B1.1 verglichen wird. Dazu müsste wiederum die Ähnlichkeit von B1.1 zu B2.1 und B2.2 bestimmt werden und
das Maximum daraus würde wiederum die Ähnlichkeit der Kinder
von A1 und A2 darstellen.
A1
A2
B1.1
B2.1
B2.2
Abbildung 5: Alignierung von Knoten
In Abbildung 5 ist die Lösung trivial, da die Knoten vom Typ B selber
keine Kinder haben und somit ist die Ähnlichkeit von B1.1 zu B2.1 und
zu B2.1 gleich. Erweitert man das Beispiel um weitere Knoten wird das
Problem deutlich.
A1
B1.1
A2
B1.2
B2.1
B2.2
C1
C2
D2
Abbildung 6: Lokal optimale Alignierung von Knoten
Nun ist im ersten Baum der Knoten B1.2 mit dem Kindknoten C1 hinzugekommen und im zweiten Baum haben die Knoten B2.1 und B2.2
jetzt Kinder. Beginnt man nun eine naive Alignierung mit dem Knoten
B1.1 so ergibt sich für die Ähnlichkeit mit den Knoten B2.1 und B2.2
jeweils der selbe Wert, da B1.1 keine Kinder hat die mit den Kindern
der anderen zwei Knoten verglichen werden könnten. Wird B1.1 mit
dem erstbesten Knoten B2.1 aligniert, so ergibt sich dadurch für B1.1
eine lokal optimale Alignierung. Für B1.2 bleibt nun jedoch nur noch
der Knoten B2.2 übrig, der sich auf Kindebene jedoch unterscheidet,
wohingegen B2.1 maximal Ähnlich zu B1.2 gewesen wäre. Eine global
optimale Alignierung kann also durch lokal optimale Entscheidungen
nicht garantiert werden.
Das Beispiel macht deutlich, wie sich die beiden Aufgaben der Ähnlichkeitsbestimmung sowie der Alignierung gegenseitig beeinflussen, denn
ohne eine optimale Alignierung der Kindebene mit anschließender
Ähnlichkeitsbestimmung kann auch die Ähnlichkeit der Elternknoten
nicht korrekt bestimmt werden, was wiederum die Voraussetzung für
deren Alignierung ist etc. Im Folgenden gilt es also einen effizienten
Ansatz zu finden, der Ähnlichkeitbestimmung und Alignierung in der
geforderten Weise verbindet.
9
2.3
multiple sequence alignment
Betrachtet man wissenschaftliche Arbeiten, die sich mit dem Vergleich
von Bäumen beschäftigen, so fällt auf, dass Forschung in diese Richtung betrieben wird, dass diese Ansätze jedoch meist den paarweisen
Vergleich beschreiben (Yang, 1991) oder domänenspezifische Merkmale der Daten ausnutzen (Zhai & Liu, 2005). Andererseits ist das Multiple Sequence Alignment ein Kernproblem der Bioinformatik und dort
sehr gut erforscht, da sich hierdurch Muster in der Evolution einer Familie von Proteinen aufdecken lassen (Notredame, 2002, S. 1). Weil sich
die optimale Alignierung der Knoten von Bäumen mit der Alignierung
einer Sequenz von Elementen vergleichen lässt, deren jeweilige Ähnlichkeit zueinander sich wiederum rekursiv durch Alignierung weiterer Sequenzen ergibt, nämlich die der Kindebenen, lohnt es sich, diese
wissenschaftliche Disziplin näher zu betrachten.
2.3.1
MSA in der Bioinformatik
Notredame (2002) Beschreibt die Schwierigkeit, im Bezug auf das Multiple Sequence Alignment (MSA), als Kombination von drei technischen
Schwierigkeiten (Notredame, 2002, S. 2):
1. Die Wahl der zu vergleichenden Sequenzen
2. Der Entwurf einer Vergleichsfunktion
3. Die Optimierung dieser Funktion
Der erste Punkt ist ist vom Anwendungsfall abhängig und daher im
Rahmen des Entwurfs eines generischen Ansatzes pauschal nicht lösbar. Bezüglich der Vergleichsfunktion wurde bereits festgestellt, dass
diese, im Falle von Bäumen, wiederum auf einer Alignierung beruht.
Abgesehen davon muss für den Vergleich auf Typebene lediglich definiert werden, wie ähnlich sich die Typen untereinander sind, was im
einfachsten Falle bedeuten könnte, dass gleiche Typen maximale und
ungleiche Typen keine Ähnlichkeit aufweisen. Die eigentliche Herausforderung stellt der dritte Punkt dar. Notredame (2002) stellt fest, dass
eine mathematisch optimale Alignierung, von mehr als drei Sequenzen, zu komplex ist und beruft sich dabei auf Wang und Jiang (1994).
Aus diesem Grund seien auch alle derzeitigen MSA Ansätze heuristisch und in drei Kategorien unterteilbar: exakte, progressive sowie iterative Ansätze.
Exakte Alignierung
Exakte Algorithmen finden also nicht, wie der Name vermuten lässt,
die optimale Alignierung von mehreren Sequenzen. Ihre Ergebnisse
sind jedoch laut Notredame (2002) “[...] usually close to optimality”, also von hoher Qualität. Der Umfang der Anzahl der zu vergleichenden
Sequenzen sei hier jedoch nicht genau abgesteckt, ist jedoch mit unter
20 Sequenzen eher gering. Da die Qualität eines Prototypen vor allem
von einer ausreichend großen Trainingsmenge abhängt, erscheint eine exakte Alignierung aufgrund der damit verbundenen Komplexität
unmöglich.
Progressive Alignierung
Die progressive Alignierung basiert auf der Berechnung der optimalen
Alignierung einer begrenzten Zahl von Sequenzen, woraufhin diese
nach und nach Zusammengefasst werden. Diese Herangehensweise
hat den Vorteil, dass für die Berechnung einer beschränkten Anzahl
10
von Sequenzen, sehr genaue Algorithmen basierend auf dynamic programming eingesetzt werden können. Der Nachteil ist jedoch, dass die
Zusammenfassung der Sequenzen wiederum auf Basis lokaler Maxima geschieht. Dadurch ist nicht gewährleistet, dass die daraus abgeleitete globale Alignierung optimal ist.
Iterative Alignierung
Die dritte von Notredame (2002) identifizierte Kategorie ist die der iterativen Alignierungsstrategien. Hierbei wird versucht eine gefundene
Alignierung in einer Serie von Iterationsschritten zu verfeinern. Diese
Modifikationen basieren auf stochastischen Methoden, wie simulated
annealing, genetischen Algorithmen oder deterministischen Ansätzen,
wobei versucht wird die Alignierung von Sequenzen, die bereits Teil
einer einer multiplen Alignierung sind, immer weiter zu optimieren,
bis keine Verbesserung mehr möglich ist. Dadurch können lokale Maxima, wie sie bei progressiven Verfahren auftreten können, vermieden
werden.
2.3.2
Progressive Alignierung
Für die vorliegende Arbeit wird von einer progressiven Alignierungsstrategie ausgegangen, da diese in der Bioinformatik die am weitesten
verbreitete Methode ist (“Progressive alignments are by far the most
widely used.” (Notredame, 2002, S. 3)) und sich durch eine hohe Geschwindigkeit und eine akzeptable Sensitivität bezüglich der Daten
auszeichnet (“This approach has the great advantage of speed and
simplicity, combined with reasonable sensitivity” (Notredame, 2002)).
Darüberhinaus ist es sinnvoll, zunächst die Qualität eines einfachen
progressiven Ansatzes im strukturellen Data Mining zu evaluieren. Sollte das Ergebnis unbefriedigend sein, kann in Zukunft darauf aufbauend ein iteratives Verfahren entwickelt werden, das die durch einen
progressiven Ansatz gefundene Alignierung verfeinert.
Der erste progressive Algorithmus wurde von Hogeweg und Hesper
(1984) beschrieben. Den größten Teil des dort beschriebenen Ansatzes
macht die Konstruktion des phylogentischen Baumes aus, also der aus
den Ähnlichkeiten der Sequenzen rekonstruierte evolutionäre “Stammbaum” . Es wird betont dass die Alignierung von Sequenzen und die
Konstruktion phylogenetischer Bäume aufeinander Aufbauen würden,
da ohne die Rechtfertigung dieser integrierten Betrachtungsweise das
Konzept einer “guten Alignierungn” keine Substanz habe (Hogeweg
& Hesper, 1984, S. 1). In der Beschreibung von CLUSTAL W, einer Erweiterung dieses Ansatzes, wird dieser phylogenetische Baum auch
als guide tree (Thompson, Higgins & Gibson, 1994, S. 4674) bezeichnet,
da dieser die globale Alignierung “leitet”.
Da es hier darum geht, einen generischen Ansatz zu entwerfen, in
dem die Entstehung von Instanzen strukturierter Daten unabhängig
voneinander allein durch ihr gemeinsames Modell gelenkt wird, das
darüber hinaus als bekannt vorausgesetzt wird, kann dieser Aspekt
vernachlässigt werden. Ignoriert man diese domänenspezifische Anforderung, ergibt sich laut Hogeweg und Hesper (1984) als auch bei
Thompson et al. (1994) folgender Ablauf:
1. Alle Sequenzen werden paarweise aligniert wobei gleichzeitig
deren Ähnlichkeit zueinander (match value) berechnet wird.
2. Das zueinander ähnlichste Paar wird zusammengefasst und im
weiteren Verlauf wie eine Sequenz behandelt.
3. Dieser Vorgang wird solange wiederholt, bis alle Sequenzen zueinander aligniert wurden.
11
2.4
paarweise ähnlichkeit und alignierung
Im Bezug auf die paarweise Ähnlichkeit und Alignierung verweisen
Hogeweg und Hesper (1984) als auch Notredame (2002) auf dynamic
programming Algorithmen, wie den von Needleman und Wunsch (1970),
da diese für eine kleine Anzahl von Sequenzen eine mathematisch optimale Alignierung gewährleisten (Thompson et al., 1994, S. 4673).
Definition 1 Für den Needleman-Wunsch Algorithmus werden die folgenden Annahmen getroffen:
• Eine Sequenz A der Länge n bestehe aus den Elementen A1 , A2 , ..., An
• M(i,j) sei ein zweidimensionales Feld, dessen Werte über die Koordinaten (i,j) angesprochen werden
• s( Ai , Bj ) sei eine Funktion welche die lokale Ähnlichkeit zwischen A
und B als Zahlenwert zurückliefert
• g sei die gap penalty, also der Wert der einer Lücke entspricht
• l(A) sei eine Funktion welche die Länge einer Sequenz A zurückliefert
• max(a,b) sei eine Funktion die die größte von zwei Zahlenwerten a und
b zurückliefert
2.4.1
Needleman-Wunsch Algorithmus
Der von Needleman und Wunsch (1970) entwickelte Algorithmus ist
dem von Levenshtein (1966) entwickelten Algorithmus, zur Berechnung der Edit-Distanz, sehr ähnlich. Er stellt eine “[...] general method
applicable to the search for similarities in the amino acid sequence
of two proteins” dar, also eine Methode um zwei Proteine, d.h. Sequenzen von Aminosäuren, zu alignieren. In Algorithmus 1 ist eine
mögliche Umsetzung abgebildet.
Algorithm 1 Needleman-Wunsch Algorithmus
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure sequence_matching(A, B, g)
m ← l ( A)
n ← l ( B)
for (i ← 0, i < m) do
M(i, 0) ← i · g
end for
for (j ← 0, j < n) do
M(0, j) ← j · g
end for
for (i ← 0, i < m) do
for (j ← 0, j < n) do
match ← M(i − 1, j − 1) + s( Ai , Bi )
delete ← M (i − 1, j) + g
insert ← M (i, j − 1) + g
M(i, j) ← max(max(match, delete), insert)
end for
end for
return M (i, j)
end procedure
Die Alignierungsmatrix
Dabei werden in einer Alignierungsmatrix sowohl jede Paarung von
Elementen der beiden Sequenzen, als auch Lücken (gaps) berücksich-
12
tigt. Lücken entstehen dann, wenn ein Element Ai nicht mit dem Element Bi aligniert werden kann und stattdessen versetzt, beispielsweise
auf Bi+1 , abgebildet wird. Geht man davon aus dass A i Elemente und
B j Elemente besitzt, so muss die Matrix M i + 1 Zeilen und j + 1 Spalten aufweisen, da eine Sequenz auch auf eine leere Sequenz abgebildet
werden kann, indem lauter Lücken eingefügt werden.
Somit stellt diese Matrix alle möglichen Alignierungen zwischen
zwei Sequenzen dar, welche sich durch das Einfügen von Lücken beschreiben lassen, wodurch die Reihenfolge der Elemente nicht verändert wird. Eine Alignierung ist dabei ein Pfad durch diese Matrix beginnend bei M (0, 0) und endend bei M (i, j) (Needleman & Wunsch,
1970, S. 443-446).
Das Scoring
Die Werte in den Zellen ergeben sich aus vorher festgelegten scores für
die Alignierung zweier Elemente, bzw. für das Einfügen einer Lücke.
Da in der Bioinformatik die ähnlichen Motive zweier Proteine aligniert
werden sollen, wird das Einfügen einer Lücke mit einem panalty factor, also einem negativen score belegt. Das führt dazu, dass Lücken
nur dann eingefügt werden, wenn die Elemente anders nicht aligniert
werden können. Der gap score, bzw. penalty factor, wird hier mit der
variablen g bezeichnet. Da die Funktion, welche die Ähnlichkeit zweier Elemente bestimmt, nicht pauschal definiert werden kann, wird die
Funktion s( Ai , Bj ) vorausgesetzt, welche die Ähnlichkeit zweier Elemente A und B liefert. In der Bioinformatik geschieht das beispielsweise Anhand einer amino acid weight matrix (Thompson et al., 1994, S.
4675), die festlegt, wie ähnlich sich zwei Aminosäuren sind.
Berechnung der Ähnlichkeit
Algorithmus 1 stellt den Ansatz von Needleman und Wunsch (1970)
dar. In Zeile 4 bis 9 wird die Ähnlichkeitsmatrix vorbereitet, d.h. die
Zellen für das Szenario, dass jede Sequenz sukzessive mit der leeren Sequenz aligniert wird. In der darauffolgenden doppelten Schleife,
werden die übrigen Zellen, also M(0, 0) bis M (i, j), befüllt. Dabei werden Werte für drei Szenarien berechnet:
• Übereinstimmung von Ai mit Bj (match)
• Lücke in A einfügen (insert)
• Lücke in B einfügen (delete)
Da eine Übereinstimmung bedeutet, dass im vorherigen Schritt des
Alignierungspfades keine Lücke eingefügt wurde, repräsentiert somit
die von der aktuellen Zelle aus gesehen nord-westliche Nachbarzelle
den vorherigen Schritt. Der Wert für eine Übereinstimmung ergibt sich
aus der Summe der nord-westlichen Zelle mit der Ähnlichkeit von A
und B (s. Zeile 12). Ähnlich verhält es sich in den anderen beiden Szenarien. Eine Lücke kann auf zwei Arten entstehen: Entweder hat man
in Sequenz A eine Lücke einfügt, dann war der vorherige Schritt die
westliche Nachbarzelle (s. Zeile 14), oder aber die Lücke wurde in Sequenz B eingefügt, dann war es die nördliche Nachbarzelle (s. Zeile
13). Der Wert für eine Lücke errechnet sich aus der Summe der westlichen bzw. nördlichen Zelle und dem gap score g. Die optimale Strategie
für die aktuelle Zelle ergibt sich somit durch das Maximum der drei
Werte match, insert und delete. In Zeile 15 wird dieser Wert der Zelle
zugewiesen. Wurden auf diese Weise die Werte aller Zellen berechnet,
so befindet sich am Ende in Zelle M (i, j) ein Wert, der die Ähnlichkeit
der Sequenzen A und B, bei optimaler Alignierung, ausdrückt (s. Zeile
18).
13
Berechnung der Alignierung
Eine optimale Alignierung lässt sich nun rekonstruieren, indem aus
der Zelle M (i, j) der Pfad zurückverfolgt wird, der zu den jeweiligen
Maxima geführt hat. Da dies aus der reinen Information der Zellenwerte nicht rekonstruierbar ist, muss hierzu bereits bei der Ermittlung
der Zellenwerte für jede Zelle gespeichert werden, ob das Maximum
aus einer Übereinstimmung von A und B und/oder einer Lücke in
A und/oder einer Lücke in B entstammt. Um den Algorithmus nicht
zu kompliziert zu gestalten, wurde dieser Schritt bewusst außen vor
gelassen und wird in einem späteren Kapitel behandelt.
Beispiel
Der Ablauf des Algorithmus lässt sich gut an einem kurzen Beispiel
erklären. Gegeben sei:
• Sequenz A = A,D,E
• Sequenz B = B,D,F
• s(A,B) liefert 1 für gleiche Zeichen, ansonsten -2
• Der gap score ist -1
Zunächst werden die Matrizen M, für das Scoring, und T für die Rekonstruktion einer optimalen Alignierung (Backtracking Matrix) vorbereitet, wie in Abbildung 7 zu sehen ist.
M
#
A
D
E
#
0
−1
−2
−3
B
−1
D
−2
F
−3
T
#
A
D
E
#
B
←
D
←
F
←
↑
↑
↑
Abbildung 7: Initialzustand der Matrizen
In Abbildung 8 wurden bereits einige Werte ermittelt. Im Falle von D
und B ergibt sich für die Ähnlichkeit s(’B’,’D’) = -2. In diesem Falle
sind die Werte für eine Lücke in A oder B sowie für eine Abbildung
von ’B’ auf ’D’ gleich:
• Übereinstimmung: -1 + (-2) = -3
• Lücke in Sequenz A: -2 + (-1) = -3
• Lücke in Sequenz B: -2 + (-1) = -3
Daher wird an der entsprechden Stelle in der Backtracking Matrix gespeichert dass ein optimaler Alignierungspfad an dieser Stelle nach
Norden, Nord-Westen oder Westen fortgesetzt werden kann.
M
#
A
D
E
#
0
−1
−2
B
−1
−2
−3
D
−2
−3
F
−3
−4
T
#
A
D
E
#
↑
↑
B
←
←-↑
←-↑
D
←
←-↑
Abbildung 8: Alternative Pfade einer Alignierung
14
F
←
←-↑
In der nächsten Zelle stimmen die Zeichen aus beiden Sequenzen überein. s(’D’,’D’) = 1 und somit ergeben sich folgende Werte:
• Übereinstimmung: -2 + 1 = -1
• Lücke in Sequenz A: -3 + (-1) = -4
• Lücke in Sequenz B: -3 + (-1) = -4
Das Maximum ist hier durch eine Alignierung des Zeichens ’D’ aus
A mit ’D’ aus B zu erreichen. Daher wird in der Backtracking Matrix
lediglich der Pfad nach Nord-Westen gespeichert.
M
#
A
D
E
#
0
−1
−2
B
−1
−2
−3
D
−2
−3
−1
F
−3
−4
T
#
A
D
E
#
↑
↑
B
←
←-↑
←-↑
D
←
←-↑
-
F
←
←-↑
Abbildung 9: Matching zweier Sequenzelemente
Wird der Algorithmus bis zum Ende ausgeführt erhält man die in Abbildung 10 dargestellten Matrizen. Beim Backtracking können sich alternative Pfade ergeben, deshalb sind die Zellen die in Frage kommen
grau hinterlegt.
M
#
A
D
E
#
0
−1
−2
−3
B
−1
−2
−3
−4
D
−2
−3
−1
−2
T
#
A
D
E
F
−3
−4
−2
−3
#
↑
↑
↑
B
←
←-↑
←-↑
←-↑
D
←
←-↑
↑
F
←
←-↑
←
←-↑
Abbildung 10: Fertig errechnete Matrizen
Das bedeutet das folgende Alignierungen gleichsam optimal sind:
-BD-F
A-DE-
-BDF
A-DE
BD-F
ADE-
BDF
ADE
Daran lässt sich gut erkennen, dass die Alignierung stark von der verwendeten Ähnlichkeitsfunktion s( A, B) und dem gewählten gap score
abhängt. Hätte man für die Alignierung nicht identischer Zeichen, eine solche Entscheidung mit einem hohen Abzug “bestraft”, so wären
die alternativen Pfade, welche die Alignierung von ’A’ und ’B’ bzw. ’E’
und ’F’ zulassen, nicht entstanden.
15
2.4.2
Yangs Tree-Matching-Algorithmus
Yang (1991) erweiterte den Algorithmus von Needleman und Wunsch
(1970) im Rahmen eines Ansatzes, um syntaktische Unterschiede zwischen zwei Versionen eines Programmes zu identifizieren. Die zwei
Versionen werden dabei als Parse-Tree dargestellt. Bei diesem Ansatz
soll zusätzlich Wissen über die Grammatik der Programmiersprache
zu besseren Ergebnissen verhelfen (“[...] we develop a comparison algorithm that exploits knowledge of the grammar” (Yang, 1991, S. 739)).
Ausgangspunkt hierbei ist ein dynamic programming Algorithmus von
Hirschberg (1977) der jedoch vom Prinzip her dem von Needleman
und Wunsch (1970) in der Darstellung von Algorithmus 1 entspricht.
Es fällt auf, dass es keine gap penalty gibt, da das Einfügen von
Lücken beim Vergleich zweier Programmversionen unkritisch, ja notwendig ist, da hier, im Gegensatz zur Evolution von Proteinsequenzen, von einer Programmversion auf die andere drastische Änderungen möglich sind.
Rekursion
Um Bäume vergleichen zu können, wird der Algorithmus 1 um einen
rekursiven Aufruf in Zeile 15 in Algorithmus 2 erweitert. Dadurch
wird die Ähnlichkeit der Elternknoten durch die Ähnlichkeit ihrer Kinder beeinflusst.
Vergleichbarkeit
Desweiteren führt Yang (1991) den interessanten Aspekt der Vergleichbarkeit (comparability) ein da er feststellt, dass der Vergleich zweier
Knoten nur dann stattfinden könne , wenn deren Elternknoten übereinstimmen (“[...] two nodes can match only if their parents contain
identical symbols” (Yang, 1991, S. 747)). Dabei könne es jedoch erwünscht sein die Kinder vergleichbarer Knoten ebenfalls aufeinander
abzubilden (“[...] we may want to match two nodes when their parents
contain ’comparable’ but not identical tokens” (Yang, 1991, S. 747).
Im Algorithmus 2 sieht man in Zeile 2 dass zwei Knoten nur dann
verglichen werden, wenn diese auch vergleichbar sind, jedoch tragen
diese nur zum score ihrer Kindknoten bei, wenn sie identisch sind (s.
Zeile 21 f.)
Definition 2 Für Yangs Tree-Matching Algorithmus müssen folgende Annahmen getroffen werden:
• Ein Knoten A habe die Kindknoten A0 , A1 , ..., An−1
• M(i,j) sei ein zweidimensionales Feld, dessen Werte über die Koordinaten (i,j) angesprochen werden
• cmp(A,B) sei eine Funktion, die 1 liefert, sofern A und B vergleichbar
sind, ansonsten aber 0 zurückliefert
• eq(A,B) sei eine Funktion, die 1 liefert, sofern A und B identisch (maximal ähnlich) sind, ansonsten aber 0 zurückliefert
• c(A,i) sei eine Funktion, die den i-ten Kindknoten des Knotens A liefert
• lc(A) sei eine Funktion, die die Anzahl der Kindknoten des Knotens A
liefert
16
Algorithm 2 Yangs Tree-Matching-Algorithmus
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
procedure tree_matching(A, B)
if cmp(A,B) = 0 then
return 0
end if
m ← lc( A)
n ← lc( B)
for (i ← 0, i < m) do
M(i, 0) ← 0
end for
for (j ← 0, j < n) do
M(0, j) ← 0
end for
for (i ← 0, i < m) do
for (j ← 0, j < n) do
match ← M(i − 1, j − 1) + tree_matching(c( A, i ), c( B, j))
delete ← M (i − 1, j)
insert ← M (i, j − 1)
M(i, j) ← max(max(match, delete), insert)
end for
end for
if eq(A,B)=1 then
return M (i, j) + 1
else
return M (i, j)
end if
end procedure
17
3
DESIGN
Mit den Erkenntnissen aus der Analyse lässt sich ein instanzbasierter Ansatz, zur Prototypenextraktion aus strukturierten Daten, formulieren. Dazu werden zunächst die verwendeten Datenstrukturen und
Funktionen definiert. Anschließend wird der gesamte Ablauf der Extraktion in Form von Algorithmen dargestellt.
3.1
definitionen
Um eine einheitliche Basis zur Beschreibung der zu entwickelnden
Verfahren zu schaffen, bedarf es einiger Definitionen.
3.1.1
Datenstrukturen
Zunächst müssen die verwendeten Datenstrukturen, sozusagen als Infrastruktur für die Prototypenextraktion, definiert werden. Grundsätzlich liegt hier der Betrachtung der Datenstrukturen die Metapher des
Objekts zugrunde. Ein Objekt stellt der Umwelt den Zugriff auf dessen
Attribute und Methoden zur Verfügung. Zur Darstellung der Attribute
und Methoden eines Objekts wird der Punkt-Operator “.” verwendet.
Auf das Attribut attr des Objekts o würde somit durch die Schreibweise o.attr verwiesen. Die Schreibweise einer Methode unterscheidet sich
von der eines Attributs durch die in Klammern gesetzte Argumentliste. Der Ausdruck o. f unc( arg1) stellt somit einen Aufruf der Funktion
func(), des Objekts o, mit dem Argument arg1 dar.
Element
Ein Element ist, im vorliegenden Kontext, ein Träger sachbezogener Informationen. Als solches ist es Teil einer Datenstruktur, die diese Elemente in Bezug zueinander setzt. In einer Datenstruktur sind somit die
reinen Strukturinformationen gespeichert. Generell würde man zwar
auch bei dem Element von einer Datenstruktur sprechen, jedoch ist die
Struktur seiner Informationen unveränderlich, so dass aus Sicht der
Prototypenextraktion diese Struktur keinen Informationsgehalt hat. Somit kann das Element als strukturell atomar angesehen werden.
Definition 3 Ein Element e sei ein Träger sachbezogener Informationen. Als
solches sei es eine Instanz des Typen τ.
Prototypelement
Ein aus strukturellen Daten gewonnener Prototyp ist nicht nur ein Repräsentant der dominierenden Elementausprägungen, sondern bildet
auch strukturelle Gemeinsamkeiten ab. Auch hier können wieder sachbezogene von strukturellen Informationen getrennt werden.
18
Definition 4 Ein Prototypelement pe bilde die gemeinsamen Merkmale einer
Menge von Elementen ab. Der Typ des Prototypelements sei PE.
• pe bildet die sachbezogenen Informationen eines Elements in seinem
Label pe.lbl ab
– pe.lbl ∈ D = {d/ d ist ein Zeichen des lateinischen Alphabets,
inkl. Sonderzeichen}
• Die relative Häufigkeit, des durch pe repräsentierten Elements und damit das Gewicht des dadurch beschriebenen Aspekts, ist die Ausprägung des Attributs pe.f
– pe. f ∈ Q
Liste
Die Liste ist eine wichtige Basisdatenstruktur, z.B. um 1 : n Relationen
abzubilden. Daher ist sie als Attribut oft Teil anderer Datenstrukturen.
Definition 5 Eine Liste l ← {} mit den Elementen e0 , ..., en schreibe sich
{e0 , ..., en }. Der Typ der Liste sei L.
• {} sei die leere Liste
– e : {} → L
• l.add(e) füge der Liste l das Element e hinzu
– L.add : τ → L
– {}.add(e) = {e}
• l.remove(e) entferne das Element e aus der Liste l
– L.remove : τ → L
– {e}.remove(e) = {}
• l.length sei die Länge der Liste l
– L.length ∈ N0
– {}.length = 0
– {e1 , ..., en }.length = n
• l.get(i ) liefere das i-te Element der Liste l
– L.get : N0 → τ
– {e1 , ..., en }.get(n) = en
• l.contains(e) überprüfe ob die Liste l das Element e enthält
– L.contains : τ → {>, ⊥}
– {e1 , ..., en }.contains(e1 ) = >
Baum
Es wird davon ausgegangen, dass sich strukturierte Daten in Form
eines Baumes darstellen lassen. Dabei kapselt jeweils ein Knoten ein
informationstragendes Element. Ein Baum lässt sich rekursiv beschreiben, deshalb genügt die Definition eines Baumknotens zur Beschreibung eines Baumes.
19
Definition 6 Ein Baum setze sich aus Baumknoten zusammen. Der Typ eins
Baumknotens und somit des ganzen Baumes sei T.
• Ein Baumknoten t kapsle ein Element in seinem Attribut t.e
– T.e ∈ τ
• Jeder Baumknoten habe einen Elternknoten t.t p , ein Wurzelknoten verweise hierbei auf das leere Element t.t p ← e
– T.t p ∈ T
• Jeder Knoten habe eine Liste von 0 bis n Kindknoten t.lt ← {t1 , ..., tn }
– T.lt ∈ L
Sequenz
Als Basis der Alignierungsverfahren dient die Sequenz. Eine Sequenz
hat 1 bis n Positionen, denen jeweils wiederum 1 bis n Sequenzelemente
zugeordnet sind. Dabei drückt die Zuordnung mehrerer Sequenzelemente zu einer Position deren Alignierung an dieser Position aus. Jedes Sequenzelement kapselt wiederum ein Element. Mit der in der gemeinsamen Position enthaltenen Information alleine könnte bereits eine paarweise Alignierung vorgenommen werden. Um jedoch aus den
paarweisen, also lokalen Alignierungen eine gültige globale Alignierung
der Sequenzen abzuleiten, werden zusätzlich die Informationen benötigt, aus welcher Sequenz ein Sequenzelement ursprünglich stammt
und mit welchen anderen Sequenzelementen es potentiell aligniert
werden kann.
Sequenz
A1
B1
A3
B2
Position
Sequenzelement
Abbildung 11: Komponenten einer Sequenz
20
Definition 7 Eine Sequenz setze sich aus Positionen zusammen, denen wiederum Sequenzelemente zugeordnet seien. Die Sequenz habe den Typen T, die
Position den Typen P und das Sequenzelement sei vom Typ SE.
• Eine Sequenz s hat 1 bis n Positionen s.l p ← { p1 , ..., pn }
– S.l p ∈ L
• Für eine Position p gilt:
– Ihr können 1 bis n Sequenzelemente
p.lse ← {se1 , ..., sen } zugeweisen werden
* P.lse ∈ L
– Sie gehört zu einer Sequenz p.s
* P.s ∈ S
• Für ein Sequenzelement se gilt:
– Es kapselt ein Element se.e
* SE.e ∈ τ
– Es ist mit 0 bis n weiteren Sequenzelementen
se.lse ← {se1 , ..., sen } assoziiert
* SE.lse ∈ L
– Es ist einer Position se.p zugeordnet
* SE.p ∈ P
– Es stammt ursprünglich aus einer Sequenz se.s
* SE.s ∈ S
3.1.2
Funktionen
Zum Verständnis der im folgenden präsentierten Algorithmen, werden
einige Funktionen vorausgesetzt, deren Funktionen lediglich deklarativ beschrieben werden, da es sich dabei nicht um Kernaufgaben des
zu entwickelnden Ansatzes handelt.
Instanziierung von Typen
Um die im vorhergehenden Abschnitt definierten Datentypen im Kontext eines Algorithmus verwenden zu können, muss es eine Möglichkeit geben diese zu instantiieren.
Definition 8 Die Funktion create(τ) erzeuge eine Instanz des Typen τ.
Sollte sich dieser Datentyp aus weiteren Datentypen zusammensetzen,
so gelten diese als ebenfalls instanziiert. Für Listen gelte die abgekürzte
Schreibweise {}
create : τ → τ
create( L) → {}
Lokale Ähnlichkeit
Wie schon in der Analyse erwähnt, kann keine Funktion pauschal bestimmt werden, die die lokale Ähnlichkeit zweier Instanzen eines generischen Typs τ zurückgibt. Daher wird die Funktion sim(τ, τ ) als
gegeben angenommen.
21
Definition 9 Die Funktion sim(τ, τ ) liefere die lokale Ähnlichkeit zweier
Instanzen des Typen τ als rationale Zahl zwischen 0.0 und 1.0 zurück.
• 1.0 sei die maximale Ähnlichkeit
• Bei Werten > 0.0 gelten die Instanzen als ähnlich
• 0.0 bedeute die Instanzen sind minimal ähnlich, also nicht vergleichbar
sim : τ × τ → Q
Sortieren
Da bei der globalen Alignierung die Ordnung der Knoten verloren
geht, ist es nötig diese, durch Sortierung der Knoten von Prototypenelementen einer Baumebene, wiederherzustellen. Wie bei der Ähnlichkeit ist die Ordnung der Elemente dabei wieder vom konkreten Anwendungsfall abhängig. Daher wird von einer Funktion sort(ltpe ←
{t pe1 , ..., t pen }) ausgegangen, die eine Liste von Knoten, deren Elemente Prototypenelemente sind, sortiert.
Definition 10 Die Funktion sort(ltpe ← {t pe1 , ..., t pen }) sortiere eine Liste
von Baumknoten, deren Elemente Prototypelemente sind.
sort : L → L
Labeling
Die Erzeugung eines Prototypen aus einer Menge alignierter Elemente, setzt eine Strategie voraus, in der definiert ist, wie die relevanten
Informationen aus Elementen vom Typ τ gewonnen werden können
und wie diese im Prototypen repräsentiert werden.
Definition 11 Die Funktion label_proto(p,lτ ) setze das Label p.lbl eines
Prototyps p entsprechend den Elementen einer Liste lτ .
label_proto : P × L → e
3.2
prototypextraktion
In der Analysephase wurde festgestellt, dass beide dort genannten Algorithmen au und sdtg auf eine Möglichkeit, zur Alignierung der Kindknoten zweier Knoten, angewiesen sind. Der Aspekt der Alignierung
lässt sich also getrennt von der Erzeugung der Prototypen betrachten.
3.2.1
Einstiegspunkt
Zunächst wird die Funktion extract_prototype() (s. Algorithmus 3)
als Einstiegspunkt definiert, in der lediglich die Rekursion vorbereitet
wird. extract_prototype() erwartet eine Liste von Baumknoten. Da der
rekursive Extraktionsvorgang im folgenden auf Listen von Listen von
Baumknoten, also auf den Kindknoten eines Knotens, arbeitet, wird
die initiale Liste von Wurzelknoten in den Zeilen 3 bis 5 in diese Form
gebracht. Anschließend beginnt der rekursive Abstieg in die Baumstrukturen durch Aufruf der Funktion process_children() mit der angepassten Liste. Da davon ausgegangen wird, dass die Bäume sich in
ihrer Wurzel nicht unterscheiden, wird bei der Prototypextraktion nur
ein Prototyp entstehen. Daher wird ab Zeile 6 gezielt der erste Prototyp zurückgegeben.
22
Algorithm 3 Einstiegspunkt der Prototypenextraktion
1:
2:
3:
4:
5:
6:
7:
8:
function extract_prototype(lt ← {t1 , ..., tn })
ltn ← {}
for all t ∈ lt do
ltr .add({t})
end for
t p ← process_children(ltn , lt .length, lt .length).get(1)
return t p
end function
3.2.2
Rekursion
Da im Zuge der rekursiven Prototypisierung globalen Informationen
über den gesamten Baum transportiert werden müssen, wird an process_children(),
zusätzlich zur Liste von Listen von Knoten llt , die Anzahl der Bäume
insgesamt tcount , sowie die Anzahl der Elternknoten t pcount der vorherigen Ebene übergeben.
Die Funktion process_children(), dargestellt in Algorithmus 4, aligniert zunächst in Zeile 2 die übergebenen Listen von Baumebenen
mit Hilfe der Funktion align_progressive(). Der Rückgabewert dieser
Funktion ist wiederum eine Liste von Listen, aber diesmal mit anderer Semantik: Die inneren Listen stellen hierbei alignierte Knoten dar.
Daher wird in Zeile 4 bis 7 mit proto_strategy() der Prototyp von jeder Liste alignierter Knoten erzeugt. Hierfür wird wiederum die Anzahl der Bäume, sowie die Anzahl der Elternknoten, weitergegeben.
Die Prototypen werden wiederum in einer Liste gesammelt, welche
schließlich den Rückgabewert der Funktion process_children() bildet.
Algorithm 4 Rekursive Prototypenextraktion
1:
2:
3:
4:
5:
6:
7:
8:
9:
function process_children(llt ← {lt1 , ..., ltn }, tcount , t pcount )
llta ← align_progressive(llt )
ltpe ← {}
for all lta ∈ llta do
t pe ← proto_strategy(lta , tcount , t pcount )
ltpe .add(t pe )
end for
return sort(ltpe )
end function
3.2.3
Prototypisierungsstrategie
Da sich die Anti-Unifikation und das SDTG Verfahren lediglich in der
Art und Weise unterscheiden, wie der Prototyp aus einer Menge alignierter Knoten extrahiert wird, kann auch diese Logik in einer separaten Funktion untergebracht werden. Diese Trennung ist von Vorteil, um in Zukunft verschiedene Ansätze objektiv miteinander vergleichen zu können. Die folgenden Funktionen proto_strategy_au() sowie
proto_strategy_sdtg() stellen daher zwei Prototypisierungsstrategien
dar, die in Algorithmus 4 in Zeile 5 verwendet werden können.
Anti-Unifikation
In der Prototypisierungsstrategie proto_strategy_au() (s. Algorithmus
5) wird gleich in Zeile 2 getestet, ob die Anzahl der alignierten Knoten mit der Anzahl tcount der Bäume übereinstimmt. Ist dies nicht der
Fall, so wird das leere Element e ausgegeben, da nur Elemente, die in
allen anderen Bäumen eine Entsprechung haben, Teil des Prototypen
werden.
23
In den Zeilen 5 bis 8 wird ein neues Prototypelement erzeugt. Dabei
wird in Zeile 6 die Funktion label_proto () aufgerufen um das Label des
Prototypen, anhand der Merkmale der alignierten Knoten aus Liste lt ,
zu setzen. Anschließend wird ein neuer Baumknoten erzeugt und das
Prototypelemen als dessen Element gesetzt.
In den Zeilen 9 bis 12 wird zunächst eine Liste erzeugt, der anschließend alle Listen mit Kindknoten der alignierten Knoten hinzugefügt
werden. Danach werden die Prototypelementknoten der Kinder, durch
rekursiven Aufruf der Funktion process_children(), extrahiert und dem
soeben erzeugten Prototypknoten als Kindknoten angehängt (s. Zeile 12). Dabei wird wiederum die Gesamtanzahl der Bäume weitergereicht. Die Anzahl der Elternknoten, für die Ebene ihrer Kinder, ist
jetzt lt .length, also die Anzahl der alignierten Knoten.
Algorithm 5 Prototypingstrategie “Anti-Unifikation”
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
function proto_strategy_au(lt ← {t1 , ..., tn }, tcount , tpcount )
if lt .length < tcount then
return e
end if
pe ← create( PE)
label_proto( pe, lt )
t p ← create( T )
t p .e ← pe
ltc ← {}
for all t ∈ lt do
ltc .add(t.lt )
end for
if ltc .length > 0 then
t p .lt ← process_children(ltc , tcount , lt .length)
end if
return t p
17: end function
16:
Structure Dominance Tree Generalisation
Die Structure Dominance Tree Generalisation (SDTG) unterscheidet sich
nur an wenigen Punkten von der Anti-Unifikation. Gleich zu Beginn
fällt auf, dass es hier keine Abbruchbedingung wie in Algorithmus
5 gibt, da ein SDTG-Prototyp keine Schnittmenge, sondern vielmehr
eine gewichtete Vereinigungsmenge der Bäume darstellt.
Die Erzeugung des Prototypelementknotens in den Zeilen 2 bis 6
ist identisch mit der der Anti-Unifikation, bis auf die Tatsache, dass
in Zeile 4, die relative Häufigkeit des Auftretens eines Elements, zur
Anzahl der Elternknoten, im Prototypelement gespeichert wird. Der
weitere Verlauf entspricht wieder dem der Anti-Unifikation.
24
Algorithm 6 Prototypingstrategie “SDTG”
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
3.3
function proto_strategy_sdtg(lt ← {t1 , ..., tn }, tcount , tpcount )
pe ← create( PE)
label_proto( pe, lt )
l .length
pe. f ← ttpcount
t p ← create( T )
t p .e ← pe
ltc ← {}
for all t ∈ lt do
ltc .add(t.lt )
end for
if ltc .length > 0 then
t p .lt ← process_children(ltc , tcount , lt .length)
end if
return t p
end function
progressive alignierung
Wie sich herausstellt, verbirgt sich die meiste Logik in der progressiven
Alignierung. Bereits in der Analyse wurde dieses Verfahren vorgestellt,
das aus einem hierarchischem Clusteringverfahren und einem dynamic
programming Algorithmus, zur Berechnung der paarweisen Ähnlichkeit und Alignierung zweier Sequenzen, besteht. Das konkrete Vorgehen wird nun in Algorithmus 7 dargestellt.
Zunächst werden in den Zeilen 2 bis 16 die Listen von Baumknoten
in Form Sequenzen überführt. Dazu wird in Zeile 4 für jede Liste eine neue Sequenz erzeugt. Die Einzelnen Elemente der Liste, also die
Baumknoten, werden dabei von jeweils einem in Zeile 6 neu erzeugtem Sequenzelement gekapselt (s. Zeile 7). Dem Sequenzelement wird
in Zeile 8 die Sequenz s als Ursprungssequenz se.s zugewiesen. Daraufhin wird in Zeile 9 eine neue Position erzeugt, diese wird mit der
neu erzeugten Sequenz verknüpft (s. Zeile 10 und 11). Schließlich wird
auch die Position mit dem Sequenzelement in beide Richtungen verknüpft (s. Zeilen 12 bis 13). Jede so erzeugte Sequenz wird der Liste ls
hinzugefügt.
Im Zuge des hierarchischen Clusterings der Sequenzen in der Funktion clusterh() wird bei der Berechnung der paarweisen Ähnlichkeiten
gleichzeitig die Assoziation zwischen den Sequenzelementen hergestellt. Diese Assoziationen werden anschließend in der Funktion merge() genutz, um die Sequenzen zu vereinigen und somit eine globale
Alignierung herzustellen.
In den Zeilen 19 bis 26 wird die global alignierte Sequenz wieder in
eine Listendarstellung gebracht. Dazu wird für jede Position eine Liste
erstellt (s. Zeile 21), die alle Baumknoten aufnimmt (s. Zeile 23). Diese
Liste von Listen von alignierten Baumknoten wird schließlich in Zeile
27 zurückgegeben.
25
Algorithm 7 Einstiegspunkt der progressiven Alignierung
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
function align_progressive(llt ← {lt1 , ..., ltn })
ls ← {}
. Liste von Baumknoten in Sequenz umwandeln
for all lt ∈ llt do
s ← create(S)
for all t ∈ lt do
se ← create(SE)
se.e ← t
se.s ← s
p ← create( P)
s.l p ← { p}
p.s ← s
p.lse ← {se}
se.p ← p
end for
ls .add(s)
end for
llsa ← clusterh(ls ) . Clustering und paarweise Assoziierung
s a ← merge(llsa )
. Globale Alignierung
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
llt ← {} . Sequenz alignierter Positionen in Liste umformen
for all p ∈ s a .l p do
lt ← {}
for all se ∈ p.lse do
lt .add(se.e)
end for
llt .add(lt )
end for
return llt
end function
3.3.1
Hierarchisches Clustering
Das von Hogeweg und Hesper (1984) beschriebene progressive Verfahren, lässt sich direkt als hierarchisches Clustering von Sequenzen
darstellen, wobei als Distanzmaß die Ähnlichkeit der Sequenzen herangezogen wird.
Die Funktion clusterh() implementiert ein hierarchisches Clusteringverfahren und erwartet eine Liste von Sequenzen. Zunächst wird eine
Liste lclu erzeugt, welche die einzelnen Cluster enthalten wird. Da zu
Beginn jede Sequenz einen eigenen Cluster darstellt, werden diese jeweils einer Liste hinzugefügt, die wiederum der Liste lclu angehängt
werden (s. Zeile 2 bis 5).
Da das Clustering erst dann fertig ist, sobald alle Cluster zu einem
verschmolzen wurden, terminiert die Schleife in Zeile 6 erst, sobald die
Liste der Cluster lclu nur noch ein Element enthält. In jedem Schleifendurchlauf wird sodann die Distanz jeder Paarung von Clustern mittels
avg_linkage() berechnet. Das Cluster-Paar mit der geringsten Distanz,
also der größten Ähnlichkeit, wird schließlich in der Zeile 22 in einem
neuen Cluster vereint und die vorher eigenständigen Cluster werden
entfernt. Den Rückgabewert der Funktion clusterh() bildet somit der
vereinigte Cluster.
26
Algorithm 8 Hierarchisches Clustering
function clusterh(ls ← {s1 , ..., sn })
lclu ← {}
3:
for all s ∈ ls do
4:
lclu .add({s})
5:
end for
1:
2:
while lclu .length > 1 do
max_score ← −1
lbest a ← e
lbestb ← e
6:
7:
8:
9:
for i ← 1, lclu .length do
for j ← i + 1, lclu .length do
10:
11:
la ← lclu .get(i )
lb ← lclu .get( j)
curr_score ← avg_linkage(la , lb )
if curr_score > max_score then
max_score ← curr_score
lbest a ← la
lbestb ← lb
end if
12:
13:
14:
15:
16:
17:
18:
19:
end for
end for
20:
21:
22:
23:
24:
25:
26:
27:
lclu .add({lbest a , lbestb })
lclu .remove(lbest a )
lclu .remove(lbestb )
end while
return lclu .get(1)
end function
3.3.2
Berechnung der Clusterdistanz
In Zeile 14 des Algorithmus 8 wird die Distanz zwischen zwei Clustern mit Hilfe der Funktion avg_linkage (s. Algorithmus 9) berechnet.
Gleich zu Beginn werden die beiden übergebenen Cluster in eine flache Darstellung gebracht. In der Schleife von Zeile 5 bis 9 werden die
einzelnen Sequenzen der beiden Cluster miteinander über die Funktion htm() verglichen (s. Zeile 7). Die Ähnlichkeiten werden alle in der
Variablen score aufsummiert. Der Rückgabewert ist der auf die Anzahl
der Vergleichsoperationen normierte score.
27
Algorithm 9 Berechnung der Distanz zweier Cluster
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
function avg_linkage(la , lb )
la f ← flatten_cluster(la , {})
lb f ← flatten_cluster(lb , {})
score ← 0
for all s a ∈ la f do
for all sb ∈ lb f do
score ← score + htm(s a , sb )
end for
end for
score
return l .length
·l .length
af
bf
11:
end function
12:
function flatten_cluster(lc , l f )
if lc .length = 1 then
l f .add(lc .get(1))
return l f
end if
flatten_cluster(lc .get(1), l f )
flatten_cluster(lc .get(2), l f )
return l f
end function
13:
14:
15:
16:
17:
18:
19:
20:
3.4
alignierung
Der nächste Schritt in Algorithmus 7 nach dem hierarchischen Clustering der Sequenzen in Zeile 17 ist die Ableitung der globalen Alignierung der Sequenzen zueinander durch die Funktion merge().
3.4.1
Erzeugen der Vereinigungssequenz
Diese Funktion lässt sich gut rekursiv gestalten, da das Ergebnis der
Vereinigung zweier Cluster stets eine Liste mit zwei Elementen ist (s.
Zeile 22 Algorithmus 8). Nur die ursprünglichen Cluster, also die Blätter des Dendrogramms, bestehen lediglich aus einem Element. Diese
Tatsache bildet zugleich die Voraussetzung für die Abbruchbedingung
der Rekursion in den Zeilen 1 bis 4 des Algorithmus 10: Ist die Rekursion in den Blättern angekommen, so wird der Inhalt dieses Clusters,
also das Element, ausgegeben und die Funktion arbeitet sich von den
Blättern zur Wurzel (bottom up) durch den gesamten Cluster.
Zunächst wird in Zeile 7 eine neue Sequenz sm erstellt, die am Ende
die Vereinigungssequenz von s a und sb enthalten soll. In der äußeren
Schleife von Zeile 8 bis 17 wird für jede Position p a der Sequenz s a
eine neue Position pm erzeugt und mit der neuen Sequenz assoziiert
(s. Zeile 9 bis 12). In der inneren Schleife von Zeile 13 bis 16 werden
schließlich die Sequenzelemente von s a an die neue Position in sm gesetzt. Bildlich gesprochen “hängen” die Sequenzelemente der Sequenz
s a nun nicht mehr an den Positionen von s a , sondern an den Positionen
von sm . Die einfachen Referenzen von den Positionen der Originalsequenz s a zurück auf die Sequenzen bleiben jedoch erhalten.
Anschließend werden die Sequenzelemente aus s a mit denen aus
sb anhand ihrer Assoziationen aligniert. Dazu wird auf die Funktion
align_assoc() verwiesen. Sollten dabei Sequenzelemente in sb keine Assoziation zu s a haben, so werden diese letzendlich mit Hilfe der Funktion add_orphans() an die gemeinsame Sequenz angehängt.
28
Algorithm 10 Globale Alignierung der Sequenzen
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
function merge(llc ← {lc1 , ..., lcn })
if llc .length = 1 then
return llc .get(1)
end if
s a ← merge(llc .get(1))
sb ← merge(llc .get(2))
sm ← create(S)
. neue Sequenz erzeugen
for all p a ∈ s a .l p do
. s a Positionen kopieren
pm ← create( P)
sm .l p .add( pm )
pm .s ← sm
pm .lse ← {}
for all sea ∈ p a .lse do . Elemente an neue Position setzen
sea .p ← pm
pm .lse .add(sea )
end for
end for
align_assoc(sm , s a , sb )
add_orphans(sm , sb )
return sm
end function
3.4.2
Alignierung assoziierter Sequenzelemente
Die Umschließende Schleife in Zeile 2 bis 27 der Prozedur align_assoc()
(Algorithmus 11) iteriert nun über alle Sequenzelemente von s a . Die aktuelle Position (in der neuen gemeinsamen Sequenz sm ) eines Sequenzelements sea wird in Zeile 4 zunächst einer Liste p pool hinzugefügt,
die als Pool möglicher Positionen für die mit sea direkt und indirekt
assoziierten Sequenzelemente dient.
Die folgende Schleife iteriert nun über alle direkt mit sea assoziierten Sequenzelemente. Sind diese nicht bereits einer Position in der
neuen Sequenz zugewiesen worden (s. Zeile 7), so könnten sie (se peerd )
und die Sequenzelemente, die sich jeweils eine Position mit ihnen teilen (se peerd .p.lse ), potentiell in der neuen Sequenz mit Sequenzelement
sea aligniert werden. Anschließend wird im Pool möglicher Positionen
l pool , für jedes der direkt und indirekt assoziierten Sequenzelemente,
nach einer Position in sm gesucht, an die das jeweilige Sequenzelement
gesetzt werden kann, ohne die Integrität der globalen Alignierung zu
zerstören. Dafür muss in Zeile 12, für jedes dieser Sequenzelemente,
mit der Funktion valid_pos() getestet werden, ob sich nicht bereits an
der Zielposition ein Sequenzelement aus der selben Ursprungssequenz
befindet. Falls dabei keine Position des Pools in Frage kommt, so wird
in Zeile 18 bis 20 eine neue Position erzeugt und der gemeinsamen
Sequenz hinzugefügt. Auf diese Position kann das assoziierte Sequenzelement nun gesetzt werden (s. Zeile 21 und 22). Anschließend wird
in Zeile 23 die neue Position Teil des Pools.
29
Algorithm 11 Assoziierte Sequenzelemente alignieren
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
procedure align_assoc(sm , s a , sb )
for all p a ∈ s a .l p do . Assoziierte Elemente aus sb alignieren
for all sea ∈ p a .lse do
l pool ← {sea .p}
NEXT_PEER :
for all se peerd ∈ sea .lse do
if se peerd .p.s = sm then
goto NEXT_PEER
end if
for all se peer ∈ se peerd .p.lse do
for all p align ∈ l pool do
if valid_pos(se peer , p align ) then
se peer .p ← p align
p align .lse .add(se peer )
goto NEXT_PEER
end if
end for
pnew ← create( P)
sm .l p .add( pnew )
pnew .s ← sm
pnew .lse ← {se peer }
se peer .p ← pnew
l pool .add( pnew )
end for
end for
end for
end for
end procedure
function valid_pos(se, p)
for all se pos ∈ p.lse do
if se pos .s = se.s then
return ⊥
end if
end for
return >
end function
3.4.3
Übernahme nicht assoziierter Sequenzelemente
Der letzte Schritt in der Funktion merge() (s. Algorithmus 10, Zeile 19)
ist das Hinzufügen nicht mit s a assoziierter Sequenzelemente aus sb
zur gemeinsamen Sequenz sm . Dies wird mittels der Prozedur add_orphans() erreicht. Hier wird ausgehend von der Sequenz sb , über all
deren Positionen iteriert, wobei in den Zeilen 3 bis 5 jeweils eine neue
Position erzeugt, jedoch noch nicht in die gemeinsame Sequenz sm
eingehängt wird. Für alle Sequenzelemente jeder Position in sb wird
in Zeile 7 geprüft, ob diese noch mit einer Position in sb verknüpft
sind. Wenn dies der Fall ist, so wird dieses Sequenzelement in die
Liste der Positionselemente der neu erzeugten Position aufgenommen
(Zeile 8) und umgekehrt wird das Sequenzelement mit der Position
verknüpft (Zeile 9). Nach dem Durchlauf der Sequenzelemente einer
Position in sb wird in Zeile 12 getestet ob der neu erzeugten Position
Sequenzelemente hinzugefügt wurden. Wenn ja, wird sie in an die
neue gemeinsame Sequenz angehängt.
30
Algorithm 12 Nicht-Assoziierte Sequenzelemente hinzufügen
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
procedure add_orphans(sm , sb )
for all pb ∈ sb .l p do
pnew ← create( P)
pnew .s ← sm
pnew .lse ← {}
for all seb ∈ pb .lse do
if seb .p.s = sb then
pnew .lse .add(seb )
seb .p ← pnew
end if
end for
if pnew .lse .length > 0 then
sm .l p .add( pnew )
end if
end for
end procedure
3.5
tree-matching
Im letzen Abschnitt wurde die Funktion der Sequenz im Alignierungsprozess dargestellt. Für die globale Alignierung müssen zunächst die
Assoziationen zwischen den Sequenzelementen hergestellt werden. In
Abschnitt 2.4 wurden bereits dynamic programming Algorithmen besprochen, mit denen sich die Ähnlichkeit zweier Sequenzen berechnen lässt. Da dies die Bestimmung einer mathematisch optimalen Alignierung voraussetzt, lassen sich an diesem Punkt auch die Assoziationen zwischen den Sequenzelementen vornehmen. Hierzu ist das
Backtracking als zusätzlicher Schritt nötig. Diese Kombination, aus
paarweiser Ähnlichkeitsberechnung und Assoziation der alignierten
Sequenzelemente, wird im Folgenden als “Matching” bezeichnet.
3.5.1
Parametrisiertes Tree-Matching
Mit der progressiven Alignierungsstrategie von Hogeweg und Hesper
(1984) als Rahmen und dem von Yang (1991) auf Bäume angepassten
dynamic programming Algorithmus ließe sich theoretisch ein Vergleich
von 2 bis n Bäumen durchführen. Jedoch muss bedacht werden, dass
die von Hogeweg und Hesper (1984) entwickelte Strategie zwar gewährleistet, dass zu jedem Zeitpunkt maximal zwei Sequenzen verglichen werden, und der von Yang (1991) beschriebene Algorithmus den
Vergleich von Baumknoten wie den Vergleich von Sequenzen behandelt, jedoch bedeutet das auch, dass für den Vergleich zweier Knoten
der gesamte Algorithmus rekursiv für jede mögliche Alignierung ihrer
Kinder augerufen wird. Die Komplexität erhöht sich also mit der Tiefe
der Bäume, bzw. mit der Anzahl der Kinder pro Knoten.
Komplexität
Die Komplexität eines solchen Ansatzes lässt sich leicht überschlagen,
wenn man davon ausgeht, dass der paarweise Vergleich von Sequenzen, auf Basis eines dynamic programming Ansatzes, einen Aufwand
von O(n2 ) hat, da hierbei zwei Sequenzen eine Matrix aufspannen,
deren Zellen im Zuge der Berechnung gefüllt werden. Dazu wird im
folgenden von einem Baum, mit festem branching factor b ausgegangen.
Der branching factor ist dabei die Anzahl der Kinder, die jeder Knoten
hat. Die Tiefe, also die Anzahl der Ebenen eines Baumes, wird mit d
beschrieben. Vergleicht man nun zwei Knoten miteinander (Ebene 0),
so hängt dieser Vergleich vom paarweisen Alignment ihrer Kindkno-
31
ten ab (Ebene 1) ab, also von einem Alignment zweier Sequenzen. Der
Aufwand, zwei Knoten zu alignieren, ist also O(b2 ), da der konstante
Aufwand von 1 für die Wurzelebene entfallen kann. Dieser Aufwand
fällt rekursiv nun wieder für jeden Kindknoten an, wodurch auf Ebene
1 bereits ein Aufwand von O(b2 · b2 ) entsteht. Somit gelangt man zu
einer Komplexität von O(b2·(d−1) ). Hierdurch wird deutlich dass der
branching factor sowie die Tiefe der Bäume sehr starken Einfluss auf die
Komplexität des Verfahrens haben.
Lookahead
Wie bereits in den ersten Beispielen deutlich wurde, erhöht sich die
Qualität des Alignments mit jeder zusätzlich betrachteten Ebene von
Kindknoten. Es bietet sich daher an, die Zahl der betrachteten Ebenen, im Zuge der Alignierung zweier Knoten, zu beschränken, was im
Folgenden als Lookahead mit der Variablen l bezeichnet wird.
Parent weight
Im Zuge der Einführung einer Tiefenbegrenzung durch den Lookahead,
erscheint es konsequent, bei der Berechnung der Ähnlichkeit zweier
Knoten, die Ähnlichkeit der Kindknoten sukkzessive mit weniger Gewicht einfließen zu lassen. Dazu wird das Konzept des parent weight,
ausgedrückt durch die Variable p, eingeführt. Es legt fest, in welchem
Verhältnis die Ähnlichkeit der Kindknoten zu der lokalen Ähnlichkeit
ihrer Elternknoten steht.
Identität, Vergleichbarkeit und Ähnlichkeit
Yang (1991) führte in seinem Ansatz den Aspekt der Vergleichbarkeit
ein, um auch Knoten Alignieren zu können, die zwar nicht den identischen Typ aufweisen, jedoch von der Semantik her ähnlich sind. Da
Yang (1991), wie auch Needleman und Wunsch (1970), nicht normierte
Werte verwenden um die Ähnlichkeit auszudrücken, sind für die Konzepte Identität, Vergleichbarkeit sowie Ähnlichkeit unterschiedliche
Funktionen nötig, welche die Klassifikation übernehmen. Normiert
man jedoch die Ähnlichkeit auf einen Bereich zwischen einschließlich
0.0 und 1.0, so lassen sich die drei genannten Konzepte durch das der
Ähnlichkeit ausdrücken:
• Die Elemente A und B sind identisch, wenn sie die Ähnlichkeit
1.0 aufweisen
• Die Elemente A und B sind vergleichbar sobald sie eine Ähnlichkeit > 0.0 aufweisen
• Die Elemente A und B sind nicht vergleichbar und damit auch
nicht identisch wenn sie eine Ähnlichkeit von 0.0 aufweisen
Diese Vergleichsoperation wird, wie bereits in der Definition erwähnt,
von der Funktion sim() bereitgestellt.
Hierarchical Tree-Matching
Die neuen Anforderungen lassen sich auf Basis von Yangs Tree-Matching
Algorithmus (Algorithmus 2) leicht umsetzen. Beim Aufruf der Funktion muss nun der Lookahead l sowie das Parent Weight p mit übergeben
werden (s. Zeile 1). Die Verarbeitung kann bereits in Zeile 4 abgebrochen werden, falls A und B nicht vergleichbar sind, deren lokale Ähnlichkeit also 0.0 beträgt. Bei der Berechnung der Matrix wird nun beim
Rekursionsschritt zur Ermittlung der Ähnlichkeit der Kindknoten (s.
Zeile 17) der Lookahead l um eins verringert. Da jetzt Ähnlichkeiten
32
errechnet werden sollen, deren Gewicht zu den Blattknoten hin abnehmen soll, wird in Zeile 35 die Ähnlichkeit der Elternknoten A und
B im Verhältnis p zu 1 − p zu deren Kindknoten gewichtet. Die Normierung der Ähnlichkeit ergibt sich, indem die Ähnlichkeit der Kindknoten durch das Maximum der Anzahl der Kinder geteilt wird. Falls
sowohl A als auch B keine Kinder haben oder der Lookahead kleiner
oder gleich 0 ist, so zählt nur deren Ähnlichkeit (s. Zeile 33). Da hier
zur Bestimmung der Ähnlichkeit zweier Knoten eine Hierarchie von
Kindknoten betrachtet werden muss, wir dieses Verfahren als Hierarchical Tree-Matching bezeichnet.
Algorithm 13 Hierarchical Tree-Matching-Algorithmus
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
function htm(s a , sb , l, p)
m ← s a .lt .length
n ← sb .lt .length
if sim(s a , sb ) = 0 then
return 0
end if
for i ← 0, m do
am (i, 0) ← 0
end for
for j ← 0, n do
am (0, j) ← 0
end for
for i ← 0, m do
for j ← 0, n do
tca ← s a .tt .get(i )
tcb ← sb .tt .get( j)
match ← am (i − 1, j − 1) + htm(tca , tcb , l − 1, p)
delete ← am (i − 1, j)
insert ← am (i, j − 1)
max_score ← max(max(match, delete), insert)
am (i, j) ← max_score
if insert = max_score then
at (i, j) ← ’i’
else if delete = max_score then
at (i, j) ← ’d’
else
at (i, j) ← ’m’
end if
end for
end for
trackback(at , s a , sb )
if (m = n = 0) ∨ (l <= 0) then
return sim(s a , sb )
else
am (i,j)
return p · sim(s a , sb ) + (1 − p) · max
(m,n)
end if
end function
function max(a,b)
if a > b then
return a
else
return b
end if
end function
33
3.5.2
Backtracking
Zusätzlich wird in Algorithmus 13 das Backtracking implementiert
um nicht nur die Ähnlichkeit zu berechnen, sondern auch eine mathematisch optimale Alignierung zu erzeugen. Hierzu werden in Zeile 22 bis 29 die Werte der Backtracking-Matrix at gesetzt. Prinzipiell
kann es mehr als eine optimale Alignierung geben. Es ergeben sich immer dann verschiedene Pfade durch die Matrix sobald mehrere mögliche Operationen (Einfügung, Löschung und Abbildung) dem maximal
möglichen Wert der jeweiligen Zelle entsprechen. Diese alternativen
Pfade könnte man theoretisch für spätere Verbesserungen der globalen Alignierung nutzen. Im vorliegenden Ansatz wird darauf verzichtet und eine optimale Alignierung anhand der Vereinbarung gewählt,
dass Einfügeoperationen vor Löschungen und diese wiederum vor Abbildungen präferiert werden. Hierdurch werden nur Varianten zugelassen, in denen keine unvergleichbaren Sequenzelemente aufeinander
abgebildet werden. Diese Problematik zeigte sich in dem Beispiel zum
Abschnitt 2.4.1.
Algorithm 14 Rückverfolgung der Alignierung und Assoziation der
Sequenzelemente
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
procedure trackback(at , s a , sb )
i ← sa + 1
j ← sb + 1
while i > 1 ∧ j > 1 do
if at = ’i’ then
j ← j−1
else if at = ’d’ then
i ← i−1
else
sea ← s a .l p .get(i − 1)
seb ← sb .l p .get( j − 1)
if ¬sea .lse .contains(seb ) then
sea .lse .add(seb )
end if
if ¬seb .lse .contains(sea ) then
seb .lse .add(sea )
end if
end if
end while
end procedure
Das Backtracking ist separat im Algorithmus 14 dargestellt. Die Funktion trackback() erwartet die Backtracking-Matrix at sowie die zu alignierenden Sequenzen s a und sb . In der Schleife wird die Matrix rückwärts durchlaufen, beginnend in der äußersten Zelle. Der Pfad ergibt
sich durch die in den Zellen gespeicherten Werte: Hat eine Einfügebzw. eine Löschoperation in die aktuell betrachtete Zelle geführt, so
wird zwischen den Sequenzen keine Assoziation hergestellt. Bei einer
Einfügeoperation führt der Pfad in westlicher Richtung weiter (s. Zeile 6), bei einer Löschoperation in nördlicher (s. Zeile 14). Bei einer
Abbildung eines Sequenzelements auf ein anderes, wird das der Zelle
entsprechende Sequenzelement aus seb in die Liste der Assoziierten Sequenzelemente von sea aufgenommen (s. Zeile 13). Das selbe geschieht
analog mit Sequenzelement sea in Zeile 16. Diese Assoziationen werden schließlich, wie weiter oben beschrieben, bei der Vereinigung der
Sequenzen zur Herstellung einer globalen Alignierung verwendet (s.
Algorithmus 10).
34
4
IMPLEMENTIERUNG
Im letzten Kapitel wurden die in der Analyse identifizierten Anforderungen algorithmisch ausgearbeitet. Dabei haben sich bereits Komponenten mit unterschiedlichem Fokus ergeben. Das Ziel ist es nun das
gesamte Verfahren konkret in Java, also einer objektorientierten Programmiersprache umzusetzen. Um möglichst unabhängig von konkreten Datenstrukturen zu sein muss sich dieser Aspekt auch im Entwurf
der Softwarearchitektur widerspiegeln.
Laut Sommerville (2006) hängen Stil und Struktur der eingesetzten
Softwarearchitektur von den nicht-funktionalen Systemanforderungen
ab (s. (Sommerville, 2006, S. 242)). Als solche werden Performance, Security, Safety, Availability und Maintainability genannt.
Der Fokus dieser Arbeit liegt auf der Implementierung einer Softwarebibliothek, zur Prototypenextraktion aus strukturierten Daten. Da
die mit diesem Aufgabenkomplex verbundenen Teilaufgaben noch nicht
klar voneinander abgegrenzt wurden und er sich durch Weiterentwicklungen in der Zukunft noch verändern wird, ist die wichtigste nichtfunktionale Systemanforderung, dass das System klar strukturiert und
wartbar ist, was der Maintainability entspricht.
Sommerville (2006) beschreibt, dass eine darauf ausgerichtete Architektur aus kleinen, in sich abgeschlossenen Komponenten bestehen
muss, die sich einfach auswechseln lassen, sowie dass Produzenten
und Konsumenten von Daten getrennt werden müssen, wodurch eine
Abhängigkeit von einer gemeinsamen Datenstruktur vermieden wird
(Sommerville, 2006, S. 243).
Zunächst wird daher eine Schnittstelle zu strukturierten Daten definiert, ohne eine konkreten Typen vorauszusetzen. Analog zum Design
werden anschließend die für das Verfahren nötigen Datenstrukturen
vorgestellt. Schließlich wird die bisher algorithmisch definierte Logik
passenden Komponenten zugewiesen und die Interaktionen zwischen
ihnen erläutert.
4.1
umgang mit generischen datentypen
Schmid et al. (2010) beschreibt ein Element folgendermaßen: “[...] we
write an element e as τ (name) where name is a variable which can
be instantiated by a constant name-string [...] ” (Schmid et al., 2010,
S. 3). In dieser Definition stellt ein Element bereits einen Typen τ mit
dem Merkmal name dar. Diese Sichtweise rührt von der Orientierung
an der Domäne der SAP Business ByDesign Incidents, welche den Ausgangspunkt der Entwicklung des SDTG Ansatzes darstellt. Bei den Incidents handelt es sich um Fehlerprotokolle, die als strukturierte Daten
in Form von XML-Dateien persistiert werden. Eine Besonderheit der
Darstellung ist es, dass jedes Element lediglich über ein Attribut name
verfügt, worauf man beschloss die Ausprägung dieses Attributs mit
der Ausprägung des Elements e gleichzusetzen und dies im Typen τ
zusammenzufassen (Siehe auch (Bader, 2009, S. 39)). Der in Abbildung
12 dargestellte Baum entspricht dabei dieser Sichtweise.
35
A(“Anton”)
A
name
B
C
“Anton”
name
name
B(“Berta”) C(“Caesar”)
“Berta” “Caesar”
Abbildung 12: Unterschiedliche Datendarstellung
Da die zu entwickelnde Software prinzipiell auf jegliche Art strukturierter Daten angewendet werden können soll, wird darauf verzichtet
Annahmen bezüglich deren Eigenschaften zu treffen. Es wird stattdessen von Strukturen ausgegangen, die über baumartige Zugriffsmechanismen verfügen wie sie bereits in der Definition des Baumknotens in
Abschnitt 3.1.1 vorausgesetzt wurden. Um vom konkreten Datentypen
zu abstrahieren, wird daher lediglich eine Schnittstelle definiert, die
eine baumtypische Navigation innerhalb der zu verarbeitenden Datenstruktur zulässt. Dieser Ansatz bringt einige Vorteile mit sich:
• Die geforderte Trennung zwischen Produzent und Konsument
ist gewährleistet
• Einmal definiert kann der Zugriff auf ein bestimmtes Quellformat ohne Vorverarbeitung durchgeführt werden
• Verschiedene Ansätze können objektiv miteinander verglichen
werden, da alle die selbe Schnittstelle zu den Daten nutzen
4.1.1
Datenschnittstelle
Die Schnittstelle zu den Eingabedaten definiert sich analog zur Definition des Baumknotens aus Abschnitt 3.1.1. Die in Abbildung 13 dargestellte generische Schnittstelle ITreeNode entspricht daher der abstrakten Definition des Baumknotens. Demnach muss eine Klasse die diese
Schnittstelle realisiert den generischen Typen E binden. Er entspricht
dabei dem Element, also dem Träger der sachbezogenen Informationen.
data.tree
E: Object
«interface»
ITreeNode
getParent(): ITreeNode
getChildren(): List< ITreeNode<E> >
getElement(): E
addChildNode(elem: E): ITreeNode<E>
setElement(elem: E)
sort(cmp: Comparator<E>)
Abbildung 13: Datenschnittstelle ITreeNode
Wie bereits für die Definition des abstrakten Baumknotens gefordert,
so ist auch hier das Element nicht gleichzeitig der Baumknoten, son-
36
dern es wird weiterhin sachbezogene von struktureller Information getrennt. ITreeNode definiert dabei folgende Methoden:
• getParent() liefert den Elternknoten
• getChildren() liefert eine Liste der Kindknoten
• getElement() liefert das gekapselte Element des generischen Typs
E zurück
• addChildNode() fügt dem Knoten einen Kindknoten hinzu, in
dem das übergebene Element gekapselt wird
• setElement() legt das Element fest das durch den Knoten gekapselt werden soll
• sort() sortiert den Baum mit Hilfe einer Strategie, die die Priorität festlegt. Diese muss die Schnittstelle Comparator implementieren
4.1.2
Prototypschnittstelle
Auch der Prototyp ist wieder eine Baumstruktur und setzt sich daher auch aus Strukturinformationen und sachbezogenen Informationen zusammen. Der Zugriff auf die Struktur kann dabei wiederum
über die Schnittstelle ITreeNode erfolgen. Das Prototypelement muss
entsprechend der abstrakten Definition Zugriff auf sein Label und die
Häufigkeit zulassen. Dessen Schnittstelle IPrototype ist in Abbildung
14 dargestellt.
data.prototype
«interface»
IPrototype
getLabel(): String
getFrequency(): double
setLabel(label: String)
setFrequency(freq: double)
Abbildung 14: Prototypenschnittstelle IPrototype
Folgende Methoden werden von IPrototype definiert:
• getLabel() liefert das Label des Prototypen als Zeichenkette zurück
• getFrequency() gibt die relative Auftrittshäufigkeit des Elements
als rationale Zahl aus, das durch das Prototypelement repräsentiert wird
• setLabel() setzt das Label
• setFrequency() setzt die relative Auftrittshäufigkeit
4.1.3
Typspezifische Strategien
Jegliche Logik die sich auf die Struktur der Daten bezieht hat nun die
nötigen Zugriffsmöglichkeiten auf die Eingabedaten. Element- und damit typspezifische Operationen können nicht pauschal festgelegt werden. Da diese der Nutzer der Software bereitstellen muss, werden auch
37
hierfür Schnittstellen definiert. In Abschnitt 3.1.2 wurden in diesem
Zusammenhang folgende Aspekte genannt:
• Der Vergleich von Elementen (Ähnlichkeit)
• Die Ordnung/Sortierung von Elementen (Priorität)
• Die relevanten Merkmale eines Elements und wie diese im Prototypen abgebildet werden (Labeling)
Diese drei Strategien werden durch die Schnittstellen ISimilarity, Comparable und ILabeling definiert, welche sich im gemeinsamen Paket logic.comparison befinden. Die Paketstruktur und die Schnittstellen sind
in Abbildung 15 dargestellt.
logic.comparison
similarity
E: Object
«interface»
ISimilarity
+getSimilarity(E o1, E o2): double
priority
E: Object
«interface»
Comparator
+compare(E o1, E o2): int
priority
E: Object
«interface»
ILabeling
+labelPrototype(proto: IPrototype, elements List<E>)
Abbildung 15: Typspezifische Strategien im Paket logic.comparison
Ähnlichkeit (ISimilarity)
Um die lokale Ähnlichkeit zwischen zwei Elementen des generischen
Typs E zu ermitteln, greift die Programmlogik auf eine, durch den
Benutzer bereitgestellte, Strategie in Form einer Klasse zu, die ISimilarity für den verwendeten Elementtypen E implementiert. Das geschieht über die Methode getSimilarity(), die der Funktion sim() der
Designphase entspricht. Sie gibt für zwei Elemente des gleichen Typs
deren Ähnlichkeit als rationale Zahl zurück. Als Konvention wird davon ausgegangen dass das Ergebnis auf den Bereich zwischen 0.0 und
1.0 normiert ist (s. auch 3.1.2)
Priorität (Comparator)
Eine Implementierung der Schnittstelle Comparator gibt beim Aufruf
der Methode compare() für zwei Instanzen, o1 und o2, des gleichen Typs
38
einen ganzzahligen Wert zurück, der die Priorität von o1 gegenüber o2
widerspiegelt:
• Ein Wert < 0.0 bedeutet o1 hat eine niedrigere Priorität als o2
• 0.0 bedeutet o1 und o2 sind gleichwertig
• Ein Wert > 0.0 bedeutet o1 hat eine höhere Priorität als o2
Wie bereits erwähnt ist diese Funktionalität nötig, um die durch den
Alignierungsprozess verlorengegangene Ordnung der Elemente wieder herzustellen. Die Methode compare() erfüllt damit die selbe Aufgabe wie die Funktion sort().
Labeling (ILabeling)
Die Schnittstelle ILabeling definiert die für die Erzeugung des Prototypen notwendige Methode labelPrototype(), die wie die Funktion label_proto() die relevanten gemeinsamen Merkmale einer Liste alignierter Elemente auf das Label eines Prototypelements überträgt.
4.2
prototypextraktion
Die Funktionalität die extract_prototype() zur Verfügung stellt, soll in
der Implementierung in Java zunächst als Schnittstelle definiert werden. Dadurch soll ein Rahmen für zukünftige Erweiterungen geschaffen werden. Die Abbildung 16 zeigt die Schnittstelle IPrototypeExtraction.
logic.extraction
I: Object, O: Object
«interface»
IPrototypeExtraction
+extractPrototype(clusterMembers: List<I>): O
Abbildung 16: Extraktionsschnittstelle IPrototypeExtraction
Wie extract_prototype() erwartet ihre einzige Methode extractPrototype()
eine Liste von Elementen. Jetzt ist jedoch der Datentyp der Elemente nicht mehr auf den des Baumknotens festgelegt. Stattdessen weist
IPrototypeExtraction die generischen Typen I und O auf. Damit ist das
allgemeine Konzept der Prototypextraktion beschrieben: Anhand einer
Menge von Elementen eines beliebigen Typs wird ein Objekt erzeugt,
das diese Menge repräsentiert.
4.2.1
Prototypextraktion aus strukturierten Daten
Der entwickelte Ansatz zur Prototypextraktion aus strukturierten Daten füllt diesen Rahmen nun für Daten mit einer bestimmten Eigenschaft aus. Die abstrakte Klasse TreePrototypeExtraction konkretisiert
die Schnittstelle entsprechend für baumartig Strukturierte Daten und
bindet damit den generischen Typen E an ITreeNode<E>. In Abbildung
17 wird dieser Zusammenhang deutlich.
TreePrototypeExtraction implementiert die Funktionalität von extractPrototype() jetzt entsprechend extract_prototype(). Die Methode processChildNodes() entspricht der Funktion process_children und greift demnach
zum erzeugen des Prototypelements auf die Methode applyPrototypeStrategy() zurück. Diese abstrakte Methode muss jedoch erst von einer
39
logic.extraction
I: Object, O: Object
«interface»
IPrototypeExtraction
+extractPrototype(clusterMembers: List<I>): O
«bind»
I -> ITreeNode<E>
O -> ITreeNode< IPrototype >
TreePrototypeExtraction
- alignmentStrategy: IAlignment<E>
- sortingStrategy: Comparator<E>
- labelingStrategy: ILabeling<E>
+ extractPrototype(clusterMembers:List< ITreeNode<E> >)
: ITreeNode< IPrototype >
- processChildNodes(childNodeList:List< List< ITreeNode<E> > >)
: List< ITreeNode<IPrototype> >
# applyPrototypingStrategy(clusterMembers: List< ITreeNode<E> >,
treeCount: int, parentCount: int) : ITreeNode<IPrototype>
ILabeling
Comparator IAlignment
Abbildung 17: TreePrototypeExtraction konkretisiert IPrototypeExtraction
für baumartig strukturierte Daten
konkreten Klasse, die TreePrototypeExtraction erweitert, implementiert
werden. Die weiter oben beschriebenen typspezifischen Strategien ILabeling und Comparator tauchen hier als Abhängigkeiten wieder auf, da
diese für die Prototypenextraktion für den jeweiligen Eingabedatentyp
extern bereitgestellt werden müssen. Zusätzlich wird in der Methode processChildNodes() eine Alignierungsstrategie zur Alignierung der
in den Knoten gekapselten Elemente benötigt. Diese wird durch die
Schnittstelle IAlignment definiert.
TreePrototypeExtraction
- alignmentStrategy: IAlignment<E>
- sortingStrategy: Comparator<E>
- labelingStrategy: ILabeling<E>
+ extractPrototype(clusterMembers:List< ITreeNode<E> >)
: ITreeNode< IPrototype >
- processChildNodes(childNodeList:List< List< ITreeNode<E> > >)
: List< ITreeNode<IPrototype> >
# applyPrototypingStrategy(clusterMembers: List< ITreeNode<E> >,
treeCount: int, parentCount: int) : ITreeNode<IPrototype>
AuPrototypeExtraction
SdtgIoPrototypeExtraction
# applyPrototypingStrategy(...
# applyPrototypingStrategy(...
Abbildung 18: Die Prototypingstrategien Anti-Unifikation und SDTG
als Erweiterung der Klasse TreePrototypeExtraction
40
4.2.2
Prototypingstrategie
Die durch die Funktion proto_strategy() realisierte Prototypisierungsstrategie, wobei die Funktionen proto_strategy_au() und proto_strategy_sdtg()
verschiedene Varianten darstellen, wird durch eine Erweiterung der
abstrakten Klasse TreePrototypeExtraction bereitgestellt. Wie schon in
der Designphase, so soll als Alternative zur SDTG-Strategie ebenfalls
die Anti-Unifikation umgesetzt werden.
In der Abbildung 18 sieht man deutlich dass AuPrototypeExtraction
sowie SdtgIoPrototypeExtraction lediglich die in TreePrototypeExtraction
abstrakt definierte Methode applyPrototypeStrategy() implementieren.
4.3
alignierung
Da die Alignierungsfunktion eine eigenständige Komponente darstellt
soll auch dieser Aspekt durch eine Schnittstelle zugänglich gemacht
werden. Im letzten Kapitel wurde die Funktion align_progressive() definiert, welche die einzelnen Komponenten der progressiven Alignierung steuert.
logic.alignment
E: Object
«interface»
IAlignment
+ align(sequences: List< List<E> >)
: List< List<E> >
Abbildung 19: Alignierungsschnittstelle IAlignment
In Abbildung 19 ist die Schnittstelle IAlignment im Kontext des Pakets
logic.alignment abgebildet. Wie align_progressive() erwartet die Methode align() eine Liste von Listen mit Elementen des generischen Typs E
und gibt auch eine solche zurück, jedoch mit anderer Semantik. Wie
bereits bei IPrototypeExtraction soll diese generelle Definition einer Alignierungsstrategie für strukturierte Daten konkretisiert werden.
Progressive Alignierung
In der Klasse TreeAlignmentProgressive ist das progressive Alignierungsverfahren für Baumknoten, entsprechend der Funktion align_progressive(),
realisiert. Dabei werden auch hier die Listen von Baumknoten in Form
von Sequenzen verwaltet. Die allgemeine Beziehung zwischen den genannten Komponenten wird in Abbildung 20 dargestellt.
Das nötige Clusterverfahren wird wiederum als komplett eigenständige Komponente ausgelagert. Die Funktionalität der Prozedur merge()
wird dabei als Methode eines Clusters realisiert, die dafür wiederum
auf eine typspezifische Strategie zurückgreift.
41
nodeSeq: Sequence
logic.alignment
«instanceOf»
sequence
E: Object
Sequence
«creates»
E: Object
«interface»
IAlignment
+ align(sequences: List< List<E> >)
: List< List<E> >
«bind»
E -> ITreeNode<E>
2..
TreeAlignmentProgressive
ISimilarity<E>
Abbildung 20: Beziehung zwischen den Komponenten TreeAlignmentProgressive und Sequence
4.4
clustering
Die Schnittstelle für das Clustering orientiert sich an der Funktion clusterh(). Die Methode cluster() erwartet ebenfalls eine Liste von Elementen. Wieder ist der Typ der Elemente nicht festgelegt. Da typabhängige
Operationen des Clusterings nur in der Funktion avg_linkage() genutzt
werden, kann man von Linkage als Komponente sprechen. Aus diesem Grund erwartet die Methode cluster(), zusätzlich zur Liste der
Elemente, eine Strategie zur Berechnung des Abstands zwischen zwei
Clustern, in Form einer Implementierung der Schnittstelle ILinkage.
4.4.1
Hierarchisches Clustering
Wie in Abbildung 21 dargestellt ist das hierarchische Clusteringverfahren, wie es für die progressive Alignierung benötigt wird, eine Implementierung der Schnittstelle IClusterManager. Die Methode cluster()
von ClusterManagerHierarchical entspricht somit der Funktion clusterh(),
mit dem Unterschied, dass hiermit das Clustering unabhängig vom
Elementtyp möglich ist, sofern eine passende Linkage-Strategie bereitgestellt wird.
42
logic.clustering
ILinkage
«interface»
IClusterManager
+ cluster(elements: List<I>, distanceFunction: ILinkage<I>)
: AbstractCluster<I>
ClusterManagerHierarchical
+ cluster(elements: List<I>, distanceFunction: ILinkage<I>)
: AbstractCluster<I>
Abbildung 21: Clusteringschnittstelle IClusterManager
4.4.2
Linkage
Im Design des Verfahrens ist in avg_linkage() ein Verfahren dargestellt,
dass die Distanz zwischen zwei Clustern dadurch berechnet, indem
die paarweisen Ähnlichkeiten der Sequenzen in den Clustern zueinander berechnet wurden und das Ergebnis auf die Anzahl der Vergleichsoperationen normiert wurde. Prinzipiell sind hier jedoch verschiedene
Verfahren denkbar und daher sollen Freiheitsgrade an dieser Stelle zugelassen werden.
logic.clustering.linkage
I: Object
«interface»
ILinkage
+ getDistance(c1: AbstractCluster<I>,
c2: AbstractCluster<I>): double
I: Object
AverageLinkage
- scoringStrategy: ISimilarity<I>
+ getDistance(c1: AbstractCluster<I>,
c2: AbstractCluster<I>): double
ISimilarity
Abbildung 22: ILinkage als Schnittstelle zur Berechnung der Clusterdistanz
Deshalb definiert die Schnittstelle ILinkage lediglich die Methode getDistance(), die für zwei Cluster vom Typ AbstractCluster deren Distanz
berechnet und diese als rationale Zahl zurückgibt. Per Konvention ist
diese auf den Wertebereich zwischen 0.0 bis 1.0 normiert. ILinkage ist
wieder über den generischen Typ I parametrierbar, wodurch der Typ
der Clusterlemente nicht eingeschränkt wird.
43
Die Methode getDistance() der Klasse AverageLinkage entspricht der
Funktion avg_linkage(), im Gegensatz zu ihr ist die Logik, zur Bestimmung der Ähnlichkeit zwischen den Elementen, nicht auf das Hierarchical Tree Matching festgelegt. Wie in Abbildung 22 zu sehen, benötigt AverageLinkage hierfür wiederum eine externe Strategie vom Typ
ISimilarity, dessen Referenz ihr über den Konstruktor mitgegeben werden muss.
4.4.3
Cluster
In der algorithmischen Definition des Extraktionsverfahrens ist man
davon ausgegangen, dass man Cluster durch verschachtelte Listen darstellen kann, wie dies bei funktionalen Programmiersprachen der Fall
ist. Bei einer objektorientierten Programmiersprache wie Java ist dies
jedoch nicht möglich. Zwar ist der Elementtyp einer parametrierbaren
Listenklasse variabel, die Schachtelung dieser Parameter muss dabei
jedoch eindeutig sein. Daher wird ein Cluster als konkrete Datenstruktur eingeführt.
Prinzipiell gibt es zwei Arten von Clustern: Verbindungscluster und
Blattcluster. Blattcluster sind einelementige Cluster, sie kapseln also lediglich ein Element. Ein Verbindungscluster ist ein Cluster der zwei
andere Cluster miteinander verbindet. Damit ein Verbindungscluster
also z.B. einen Blattcluster mit einem anderen Verbindungscluster vereinigen kann, müssen beide Arten von Clustern einen gemeinsamen
Supertyp haben.
AbstractCluster
AbstractCluster ist eine abstrakte Klasse und stellt diesen Supertyp dar.
Sie implementiert die Methode add() mit der einem Cluster ein anderer
hinzugefügt werden kann. Diese Methode ist damit automatisch auch
in seinen Subklassen LeafCluster und LinkCluster verfügbar. Die Methode erwartet ein Objekt vom Typ AbstractCluster, erstellt intern einen
LinkCluster, der den Cluster auf dem die Methode aufgerufen wurde und den zu verbindenden Cluster verknüpft, und gibt diesen als
neuen Cluster zurück. Dadurch ist wieder eine beliebige Schachtelung
der Cluster möglich, so wie dies im Design vorgesehen war. Weiterhin werden folgende abstrakte Methoden definiert, die von konkreten
Unterklassen implementiert werden müssen:
• getMergedElements() gibt den Inhalt des Clusters vereinigt aus
– Wird dabei eine Vereinigungsstrategie vom Typ IMerge übergeben, so bestimmt diese, wie die Elemente vereint werden,
und von welchem Typ dieses vereinigte Objekt ist
– Ansonsten werden die Elemente des Clusters als Menge
vom Typ Set zurückgegeben
• getSize() gibt die Anzahl, der im Cluster enthaltenen Elemente,
zurück
Die Methode getMergedElements() arbeitet sich dabei ebenfalls rekursiv von den Blattclustern nach oben, wie es in dem Algorithmus zur
Funktion merge() beschreiben ist. Da jedoch auch hier die eigentliche
Merging-Strategie, also wie zwei Elemente miteinander vereint werden, nicht pauschal festgelegt werden kann, erwartet die Methode diese Strategie in Form einer Implementierung der Schnittstelle IMerge.
Falls diese nicht bereitgestellt wird, so werden die Elemente des Clusters als Menge ausgegeben.
44
logic.clustering.cluster
E: Object
AbstractCluster
+ add(leaf: AbstractCluster<E>): AbstractCluster<E>
+ getMergedElements(): Set<E>
+ <O> getMergedElements(IMerge<E,O> mergeStrategy): O
+ getSize(): int
E:Object
E:Object
LinkCluster
LeafCluster
...
...
Abbildung 23: AbstractCluster als Cluster-Supertyp
LeafCluster
In Abbildung 24 sieht man wie AbstractCluster als Blattcluster in der
Klasse LeafCluster erweitert wurde. Im Attribut leaf wird hierbei das
Element gespeichert, daher wird beim Aufruf von getMergedElements()
lediglich dieses zurückgegeben. Dieses Verhalten entspricht der Abbruchbedingung der Rekursion in Zeile 3 der Funktion merge() in Algorithmus 10.
E:Object
LeafCluster
- leaf: E
+ getMergedElements(): Set<E>
+ <O> getMergedElements(IMerge<E,O> mergeStrategy): O
+ getSize(): int
Abbildung 24: LeafCluster, der einelementige Cluster
LinkCluster
Ein Verbindungscluster kombiniert zwei Cluster zu einem. Bei einem
Aufruf von getMergedElements() auf einem LinkCluster wird die selbe Methode auf den beiden verbundenen Clustern aufgerufen. Die
zwei entstandenen Objekte werden schließlich mit Hilfe der MergingStrategie verschmolzen. Das entspricht den Zeilen 5 und 6 der Funktion merge() in der sie sich selbst rekursiv aufruft.
E:Object
LinkCluster
- leftLink: AbstractCluster<E>
- rightLink: AbstractCluster<E>
+ getMergedElements(): Set<E>
+ <O> getMergedElements(IMerge<E,O> mergeStrategy): O
+ getSize(): int
Abbildung 25: LinkCluster als Verbindung zwischen zwei Clustern
45
4.5
sequence-matching
Wie die Funktion avg_linkage(), so bestimmt auch die Methode getDistance() der Klasse AverageLinkage die Distanz zwischen zwei Elementen nicht selbstständig, sondern legt lediglich fest, wie die einzelnen
Distanzen zwischen den Elementen zu einem Wert kombiniert werden. Die Funktion avg_linkage() ruft zur Bestimmung der Distanz die
Funktion htm() auf, die auch gleichzeitig die paarweisen Assoziationen
zwischen den Sequenzelementen vornimmt. Anstatt nun ein weiteres
Konzept wie die Distanz einzuführen, kann man stattdessen auch hier
das der Ähnlichkeit einsetzen.
4.5.1
Hierarchical Sequence-Matching
Das in der Funktion htm() realisierte Hierarchical Tree-Matching ist, wenn
man es genau nimmt, lediglich ein rekursiver Sequenzvergleich, bei
dem sich die Ähnlichkeit zwischen zwei Sequenzelementen durch deren “Kindsequenzen” ergibt. Deshalb wird hier, etwas allgemeiner, ein
Hierarchical Sequence-Matching implementiert, dass erst bei der Anwendung auf Baumknoten zu einem Hierarchical Tree-Matching wird.
logic.comparison.similarity
E: Object
«interface»
ISimilarity
+getSimilarity(E o1, E o2): double
«bind»
Sequence<E>
E: Object
AbstractSimilarityCaching
- cache: Map< Pair<I>,Double >
+ getSimilarity(obj1: I, obj2: I): double
# calculateSimilarity(obj1: I, obj2: I): double
«bind»
E -> Sequence<E>
hierachical
E: Object
HierarchicalSequenceMatching
- similarityStrategy: ISimilarity<E>
- translationStrategy: ITranslator<E, Sequence<E> >
- lookahead: int
- parentWeight: double
# calculateSimilarity(obj1: E, obj2: E): double
+ matchSequence(s1: Sequence<E>,
s2: Sequence<E>, la: int): double
- trackBack(seq1 List< SequenceElement<E> >,
seq2 List< SequenceElement<E> >, tbm int[][])
nodeSeq: Sequence
ISimilarity ITranslator
«modifies»
Abbildung 26: Hierarchical Sequence-Matching
46
4.5.2
Caching von Ergebnissen
In Abbildung 26 sieht man, dass die Klasse HierarchicalSequenceMatching nicht direkt die Schnittstelle ISimilarity implementiert. Vielmehr
ist sie eine Erweiterung der abstrakten Klasse AbstractSimilarityCaching.
Der Hintergrund hierbei ist, dass die Ähnlichkeit eines Sequenzpaares, im Zuge des hierarchischen Clusterings, oft wiederholt nachgefragt wird. Da diese Berechnung jedoch, wie bereits in Abschnitt 3.5
erwähnt, sehr teuer ist, ist es sinnvoll sie für ein Sequenzpaar nur einmal durchzuführen, das Ergebnis zu speichern und im Falle einer wiederholten Anfrage das gespeicherte Ergebnis zurückzugeben.
Diese Caching-Funktionalität wird von AbstractSimilarityCaching bereitgestellt. Als Cache verwendet die Klasse eine Instanz von Map, einem assoziativen Speicher, mit Hilfe dessen einem Paar von Elementen
eine rationale Zahl zugeordnet werden kann. Wird die Methode calculateSimilarity() zur Berechnung der Ähnlichkeit zwischen zwei Elementen aufgerufen, so wird zunächst im Cache geprüft ob die Ähnlichkeit
dieses Elementpaars bereits berechnet wurde. Wenn ja, wird die Zahl
direkt zurückgegeben, wenn nicht, so wird die Ähnlichkeit mit Hilfe
der Methode calculateSimilarity() der Subklasse berechnet und anschließend im Cache gespeichert.
4.5.3
Hierarchical Tree-Matching
Um das Zusammenspiel der einzelnen Komponenten des Hierarchical
Sequence-Matchings zu erläutern, bietet es sich an, dies am Beispiel des
Hierarchical Tree-Matchings zu tun.
Lokale Ähnlichkeit der Elemente
Den Kern stellt die Klasse HierarchicalSequenceMatching dar. Ihre Methode matchSequence() weist im Grunde die selbe Logik auf wie die
Funktion htm() (s. Algorithmus 13). Die Aufgabe der Funktion sim()
übernimmt hierbei eine typspezifische Strategie zur Ähnlichkeitsbestimmung der Klasse ISimilarity. Gefragt ist nun ein Matching von Sequenzen, dessen Elemente Baumknoten (Typ ITreeNode) sind. Hierfür
wurde die Ähnlichkeitsstrategie SimilarityTreeNode, vom Typ ISimilarity), implementiert. Da ein Baumknoten jedoch wiederum ein Element
eines beliebigen Typen kapseln kann, muss SimilarityTreeNode im Konstruktor wiederum eine Ähnlichkeitsstrategie passend zum Elementtyp mitgegeben werden. Diese Schachtelung von Strategien macht den
Ansatz sehr flexibel, ohne dabei die einzelnen Komponenten unnötig
stark an einen bestimmten Typen zu binden.
Translationsstrategie
Da der in matchSequence() eingesetzte Algorithmus, für die Bestimmung des Matchings zweier Sequenzelemente, rekursiv das selbe auch
für deren Kindsequenzen tun muss, wird hier wieder eine externe Strategie benötigt. Die Schnittstelle dafür bildet ITranslator. Sie definiert die
Methode translate(), die der Übersetzung von einem Objekt in ein anderes dient. Für das Tree-Matching wird daher mit TranslatorTreeNode
eine Übersetzungsstrategie implementiert, die einen Baumknoten in
eine Sequenz seiner Kindknoten “übersetzt”.
4.5.4
Sequenz
Die Sequenz als Basisdatenstruktur kann entsprechend der Definition im Kapitel Design direkt als Komposition der Komponenten Se-
47
quenz, Position und Sequenzelement dargestellt werden. Dieser Zusammenhang ist in Abbildung 27 dargestellt.
logic.alignment.sequence
E: Object
Sequence
- positions: List< SequencePosition<E> >
+ merge(Sequence<E>): Sequence<E>
+ getAlignedObjects(): List< List<E> >
...
E: Object
SequencePosition
- sequence: Sequence<E>
# members: List<SequenceElement>
...
baseSequence
E: Object
SequenceElement
- baseSequence: Sequence<E>
- position: SequencePosition<E>
- peers: List< SequenceElement<E> >
- element: E
...
1
0..
peers
Abbildung 27: Die Sequenz als Komposition aus drei Datenstrukturen
Sequence
Die Klasse Sequence verwaltet eine Liste mit den Sequenzpositionen
vom Typ SequencePosition. Auffällig ist, dass die Funktion merge() (s.
Algorithmus 10) jetzt Teil der Klasse Sequence geworden ist, dabei hat
sich an der Funktionsweise jedoch nichts geändert.
SequencePosition
Eine SequencePosition referenziert die ihr zugeordneten Sequenzelemente ebenfalls über eine Liste. Die Sequence Instanz der die Position zugeordnet ist, wird über die Variable sequence referenziert.
SequenceElement
Ein Sequenzelement vom Typ SequenceElement ist mit keinen bis beliebig vielen anderen Sequenzelementen assoziiert. Diese Referenzen
werden in der Liste peers gespeichert. Ein Sequenzelement stammt aus
einer bestimmten Ursprungssequenz und hält eine Referenz auf diese in der Variablen baseSequence. Die Position der ein Sequenzelement
zugeordnet ist, kann sich im Zuge der Vereinigung von Sequenzen
ändern. Die Referenz auf die aktuelle Position wird in der Variablen
position gespeichert.
48
5
RESÜMEE UND AUSBLICK
Der modellorientierte Ansatz zur Prototypextraktion setzt ein Modell
voraus, dass als Baum darstellbar ist um es als Richtschnur für den
Vergleich der Instanzen zu verwenden. In Abschnitt 2.1 wurde gezeigt, dass diese Voraussetzung die Ausdruckskraft, im Hinblick auf
die möglichen Instanzen des Modells, sehr stark einschränkt. Im Vergleich zu den Produktionen einer regulären Grammatik (Typ 3) erlaubt
das eingeschränkte Modell keine Kleene’sche Hülle sowie keine rekursiven Produktionen. Dadurch ergeben sich strukturelle Unterschiede
zwischen den Instanzen lediglich durch Wahlmöglichkeiten bezüglich
der Produktionen, bildlich gesprochen also indem verschiedene “Pfade” im Modellbaum eingeschlagen werden.
5.1
evaluation
Der im Rahmen dieser Arbeit entwickelte instanzorientierte Ansatz
hingegen, setzt das gemeinsame Modell als gegeben voraus, nutzt dieses jedoch nicht um den Vergleich der Instanzen zu führen. Da das
Matching, d.h. der Vergleich, in Verbindung mit der Alignierung der
Baumstrukturen, nun ausschließlich über die Ähnlichkeit der Instanzen geschieht, musste ein Verfahren zum effizienten Matching multipler Bäume entwickelt werden. Mit einem modifizierten Verfahren
aus der Bioinformatik, dass die Hierarchie der Bäume nutzt, um die
Komplexität des Vergleichs einzuschränken, ist dies schließlich möglich geworden. Das Modell muss nun nicht mehr als endlicher Baum
dargestellt werden können, wodurch das Ziel, Prototypen aus Instanzen einer regulären Grammatik zu extrahieren, erreicht ist.
Bei der Umsetzung des Ansatzes als Java Softwarebibliothek wurde
ein besonderes Augenmerk auf die Erweiterbarkeit gelegt. Nahezu alle
Komponenten der Software lassen sich austauschen und unabhängig
voneinander nutzen, wodurch eine Plattform für zukünftige Weiterentwicklungen geschaffen wurde. Auch der objektive Vergleich verschiedener Ansätze und Teilaspekte lässt sich so einfach durchführen. Um
diese Flexibilität zu erreichen wurde darauf geachtet, jegliche typspezifische Logik, in Form definierter Strategien, auszulagern, so dass die
Softwarebibliothek leicht in konkrete Anwendungen eingebunden werden kann. Dies ist wichtig, um neben der theoretischen Auswertung
auch empirische Daten über den Nutzen dieser neuen Verfahren sammeln zu können. Auf diese Weise ist ein schneller Erfahrungsaustausch
zwischen Forschung und Anwendung möglich.
5.2
anknüpfungspunkte
Das instanzorientierte Verfahren zu Prototypextraktion bietet viel Potential in Hinblick auf dessen Anwendung, Auswertung und Optimierung.
5.2.1
Empirische Ergebnisse
Es gilt nun vielfältige Anwendungsmöglichkeiten zu finden, in denen
sich das Verfahren bewähren kann. Interessant wäre beispielsweise zu
testen, inwiefern sich die unterschiedlichen Parameter des Verfahrens,
wie der Lookahead, auf die Qualität des Prototyps und die Laufzeit
auswirken.
49
Auch die Datendarstellung hat erheblichen Einfluss auf die Komplexität der Analyse. Tiefe Hierarchien, die sich erst unterhalb des
durch den Lookahead abgedeckten Bereich unterscheiden, können zu
schlechten Ergebnissen führen. Hier wären beispielsweise automatische verlustfreie Transformationen in einem Vorverarbeitungsschritt
denkbar.
5.2.2
Iterative Alignierung
Auf Basis des entwickelten progressiven Verfahrens zur Alignierung,
könnte ein iteratives Verfahren realisiert werden, das lokale Maxima
durch ständige Verfeinerung der Alignierung vermeidet und so zu einer besseren globalen Alignierung führt. Hierbei ließen z.B. sich die
alternativen Pfade, die bei der paarweisen Alignierung entstehen, nutzen.
5.2.3
Automatisches Clustering
Weiterhin stellt das automatische Clustering auf Basis des hierarchischen Tree-Matchings eine interessante Möglichkeit dar, Teilaspekte
der Arbeit weiterzuentwickeln. Damit wäre es möglich, eine Menge
von Daten, auf Basis struktureller Ähnlichkeiten zu partitionieren. Dadurch ließen sich bisher unbekannte Zusammenhänge und Kategorien
in Daten aufdecken. Im Rahmen der Softwarebibliothek müsste hierzu
lediglich das implementierte Clusteringverfahren dahingehend erweitert werden, dass es z.B. ab einer bestimmten Clustergröße stoppt und
die so erzeugten Cluster ausgibt.
5.2.4
Globale Alignierung
Hinsichtlich der Ableitung der globalen aus den paarweisen Alignierungen wurde im vorliegenden Ansatz eine eher rechenintensive, dafür aber anschauliche Lösung vorgestellt, die zu vielen Vergleichsoperationen führt. Hier lassen sich mit Sicherheit effizientere Abläufe finden.
5.2.5
Neuer modellorientierter Ansatz
Der Nachteil des instanzorientierten Ansatzes ist, dass die Informationen, die das Modell bietet, nicht genutzt werden. Der modellorientierte
Ansatz hingegen nutzt diese Informationen, schränkt dabei jedoch die
Ausdruckskraft des Modells ein. Anstatt also die Idee eines modellorientierten Ansatzes an sich fallen zu lassen, sollte dieser vielmehr unter
anderen Prämissen neu angegangen werden. Beispielsweise wäre es
vorstellbar, die zur Erzeugung der Instanzen eines Clusters angewandten Regeln, statt die daraus resultierenden Strukturen zu generalisieren.
50
L I T E R AT U R V E R Z E I C H N I S
Agnar, A. & Plaza, E. (1994). Case-based reasoning: Foundational
issues, methodological variations, and system approaches. AI
Communications, 7 (1), 39–59.
Bader, F. (2009). Modellbasierte Klassifikation von Störungsmeldungen in
betriebswirtschaftlichen Softwaresystemen - Ein Ansatz zum PrototypLernen durch strukturbasierte Generalisierung.
Hirschberg, D. S. (1977). Algorithms for the longest common subsequence problem. Journal of the ACM (JACM), 24 (4), 664–675.
Hogeweg, P. & Hesper, B. (1984). The alignment of sets of sequences
and the construction of phyletic trees: An integrated method.
Journal of Molecular Evolution, 20 (2), 175–186.
Levenshtein, V. I. (1966, Februar). Binary Codes Capable of Correcting
Deletions, Insertions and Reversals. Soviet Physics Doklady, 10,
707.
Needleman, S. B. & Wunsch, C. D. (1970, März). A general method applicable to the search for similarities in the amino acid sequence
of two proteins. Journal of Molecular Biology, 48 (3), 443–453.
Notredame, C. (2002). Recent progress in multiple sequence alignment:
a survey. Pharmacogenomics, 3 (1), 131–144.
Schmid, U., Hofmann, M., Bader, F., Häberle, T. & Schneider, T. (2010).
Incident mining using structural prototypes (Bericht). University of
Bamberg.
Sommerville, I. (2006). Software engineering (8. Aufl.). Addison Wesley.
Thompson, J. D., Higgins, D. G. & Gibson, T. J. (1994, November). CLUSTAL w: improving the sensitivity of progressive multiple sequence alignment through sequence weighting, position-specific
gap penalties and weight matrix choice. Nucleic Acids Research,
22 (22), 4673 –4680.
Wang, L. & Jiang, T. (1994). On the complexity of multiple sequence
alignment. Journal of Computational Biology, 1 (4), 337–348.
Yang, W. (1991, July). Identifying syntactic differences between two
programs. Software - Practice and Experience, 21 (7), 739-755.
Zhai, Y. & Liu, B. (2005). Web data extraction based on partial tree
alignment. In Proceedings of the 14th international conference on
world wide web (S. 76–85).
51
Ich erkläre hiermit gemäß § 17 Abs. 2 APO, dass ich die vorstehende
Bachelorarbeit selbstständig verfasst und keine anderen als die
angegebenen Quellen und Hilfsmittel benutzt habe.
21. Oktober 2010
Datum
Unterschrift
52
Herunterladen