Machine Learning mit Python – Minimalbeispiel

Maschinelles Lernen (Machine Learning) ist eine Gebiet der Künstlichen Intelligenz (KI, bzw. AI von Artificial Intelligence) und der größte Innovations- und Technologietreiber dieser Jahre. In allen Trendthemen – wie etwa Industrie 4.0 oder das vernetzte und selbstfahrende Auto – spielt die KI eine übergeordnete Rolle. Beispielsweise werden in Unternehmen viele Prozesse automatisiert und auch Entscheidungen auf operativer Ebene von einer KI getroffen, zum Beispiel in der Disposition (automatisierte Warenbestellungen) oder beim Festsetzen von Verkaufspreisen.

Aufsehen erregte Google mit seiner KI namens AlphaGo, einem Algortihmus, der den Weltmeister im Go-Spiel in vier von fünf Spielen besiegt hatte. Das Spiel Go entstand vor mehr als 2.500 Jahren in China und ist auch heute noch in China und anderen asiatischen Ländern ein alltägliches Gesellschaftsspiel. Es wird teilweise mit dem westlichen Schach verglichen, ist jedoch einfacher und komplexer zugleich (warum? das wird im Google Blog erläutert). Machine Learning kann mit einer Vielzahl von Methoden umgesetzt werden, werden diese Methoden sinnvoll miteinander kombiniert, können durchaus äußerst komplexe KIs erreicht werden.  Der aktuell noch gängigste Anwendungsfall für Machine Learning ist im eCommerce zu finden und den meisten Menschen als die Produktvorschläge von Amazon.com bekannt: Empfehlungsdienste (Recommender System).

Klassifikation via K-Nearest Neighbour Algorithmus

Ein häufiger Zweck des maschinellen Lernens ist, technisch gesehen, die Klassifikation von Daten in Abhängigkeit von anderen Daten. Es gibt mehrere ML-Algorithmen, die eine Klassifikation ermöglichen, die wohl bekannteste Methode ist der k-Nearest-Neighbor-Algorithmus (Deutsch:„k-nächste-Nachbarn”), häufig mit “kNN” abgekürzt. Das von mir interviewte FinTech StartUp Number26 nutzt diese Methodik beispielsweise zur Klassifizierung von Finanztransaktionen.

Um den Algorithmus Schritt für Schritt aufbauen zu können, müssen wir uns

Natürlich gibt es in Python, R und anderen Programmiersprachen bereits fertige Bibliotheken, die kNN bereits anbieten, denen quasi nur Matrizen übergeben werden müssen. Am bekanntesten ist wohl die scikit-learn Bibliothek für Python, die mehrere Nächste-Nachbarn-Modelle umfasst. Mit diesem Minimalbeispiel wollen wir den grundlegenden Algorithmus von Grund auf erlernen. Wir wollen also nicht nur machen, sondern auch verstehen.

Vorab: Verwendete Bibliotheken

Um den nachstehenden Python-Code (Python 3.x, sollte allerdings auch mit Python 2.7 problemlos funktionieren) ausführen zu können, müssen folgende Bibliotheken  eingebunden werden:

Übrigens: Eine Auflistung der wohl wichtigsten Pyhton-Bibliotheken für Datenanalyse und Datenvisualisierung schrieb ich bereits hier.

Schritt 1 – Daten betrachten und Merkmale erkennen

Der erste Schritt ist tatsächlich der aller wichtigste, denn erst wenn der Data Scientist verstanden hat, mit welchen Daten er es zu tun hat, kann er die richtigen Entscheidungen treffen, wie ein Algorithmus richtig abgestimmt werden kann und ob er für diese Daten überhaupt der richtige ist.

In der Realität haben wir es oft mit vielen verteilten Daten zu tun, in diesem Minimalbeispiel haben wir es deutlich einfacher: Der Beispiel-Datensatz enthält Informationen über Immobilien über vier Spalten.

  • Quadratmeter: Größe der nutzbaren Fläche der Immobilie in der Einheit m²
  • Wandhoehe: Höhe zwischen Fußboden und Decke innerhalb der Immobilie in der Einheit m
  • IA_Ratio: Verhältnis zwischen Innen- und Außenflächen (z. B. Balkon, Garten)
  • Kategorie: Enthält eine Klassifizierung der Immobilie als “Haus”, “Wohnung” und “Büro”

 

beispiel-txt-file

[box]Hinweis für Python-Einsteiger: Die Numpy-Matrix ist speziell für Matrizen-Kalkulationen entwickelt. Kopfzeilen oder das Speichern von String-Werten sind für diese Datenstruktur nicht vorgesehen![/box]

Aufgerufen wird diese Funktion dann so:

Die Matrix mit den drei Spalten (Quadratmeter, Wandhohe, IA_Ratio) landen in der Variable “dataSet”.

Schritt 2 – Merkmale im Verhältnis zueinander perspektivisch betrachten

Für diesen Anwendungsfall soll eine Klassifizierung (und gewissermaßen die Vorhersage) erfolgen, zu welcher Immobilien-Kategorie ein einzelner Datensatz gehört. Im Beispieldatensatz befinden sich vier Merkmale: drei Metriken und eine Kategorie (Wohnung, Büro oder Haus). Es stellt sich zunächst die Frage, wie diese Merkmale zueinander stehen. Gute Ideen der Datenvisualisierung helfen hier fast immer weiter. Die gängigsten 2D-Visualisierungen in Python wurden von mir bereits hier zusammengefasst.

[box]Hinweis: In der Praxis sind es selten nur drei Dimensionen, mit denen Machine Learning betrieben wird. Das Feature-Engineering, also die Suche nach den richtigen Features in verteilten Datenquellen, macht einen wesentlichen Teil der Arbeit eines Data Scientists aus – wie auch beispielsweise Chief Data Scientist Klaas Bollhoefer (siehe Interview) bestätigt.[/box]

Die beiden Scatter-Plots zeigen, das Häuser (blau) in allen Dimensionen die größte Varianz haben. Büros (gelb) können größer und höher ausfallen, als Wohnungen (rot), haben dafür jedoch tendenziell ein kleineres IA_Ratio. Könnten die Kategorien (blau, gelb, rot) durch das Verhältnis innerhalb von einem der beiden Dimensionspaaren in dem zwei dimensionalen Raum exakt voneinander abgegrenzt werden, könnten wir hier stoppen und bräuchten auch keinen kNN-Algorithmus mehr. Da wir jedoch einen großen Überschneidungsbereich in beiden Dimensionspaaren haben (und auch Wandfläche zu IA_Ratio sieht nicht besser aus),

Eine 3D-Visualisierung eignet sich besonders gut, einen Überblick über die Verhältnisse zwischen den drei Metriken zu erhalten: (die Werte wurden hier bereits normalisiert, liegen also zwischen 0,00 und 1,00)

3D Scatter Plot in Python [Matplotlib]

Es zeigt sich gerade in der 3D-Ansicht recht deutlich, dass sich Büros und Wohnungen zum nicht unwesentlichen Teil überschneiden und hier jeder Algorithmus mit der Klassifikation in Probleme geraten wird, wenn uns wirklich nur diese drei Dimensionen zur Verfügung stehen.

Schritt 3 – Kalkulation der Distanzen zwischen den einzelnen Punkten

Bei der Berechnung der Distanz in einem Raum hilft uns der Satz des Pythagoras weiter. Die zu überbrückende Distanz, um von A nach B zu gelangen, lässt sich einfach berechnen, wenn man entlang der Raumdimensionen Katheten aufspannt.

c = \sqrt{a^2+ b^2}

Die Hypotenuse im Raum stellt die Distanz dar und berechnet sich aus der Wurzel aus der Summe der beiden Katheten im Quadrat. Die beiden Katheten bilden sich aus der Differenz der Punktwerte (q, p) in ihrer jeweiligen Dimension.Bei mehreren Dimensionen gilt der Satz entsprechend:

Distanz = \sqrt{(q_1-p_1)^2+(q_2-p_2)^2+…+(q_n-p_n)^2}

Um mit den unterschiedlichen Werte besser in ihrer Relation zu sehen, sollten sie einer Normalisierung unterzogen werden. Dabei werden alle Werte einer Dimension einem Bereich zwischen 0.00 und 1.00 zugeordnet, wobei 0.00 stets das Minimum und 1.00 das Maximum darstellt.

NormWert = \frac{Wert - Min}{Wertspanne} = \frac{Wert - Min}{Max - Min}

Die Funktion kann folgendermaßen aufgerufen werden:

Schritt 4 & 5 – Klassifikation durch Eingrenzung auf k-nächste Nachbarn

Die Klassifikation erfolgt durch die Kalkulation entsprechend der zuvor beschriebenen Formel für die Distanzen in einem mehrdimensionalen Raum, durch Eingrenzung über die Anzahl an k Nachbarn und Sortierung über die berechneten Distanzen.

Über folgenden Code rufen wir die Klassifikations-Funktion auf und legen die k-Eingrenzung fest, nebenbei werden Fehler gezählt und ausgewertet. Hier werden der Reihe nach die ersten 30 Zeilen verarbeitet:

Nur 30 Testdatensätze auszuwählen ist eigentlich viel zu knapp bemessen und hier nur der Übersichtlichkeit geschuldet. Besser ist für dieses Beispiel die Auswahl von 100 bis 300 Datensätzen. Die Ergebnisse sind aber bereits recht ordentlich, allerdings fällt dem Algorithmus – wie erwartet – noch die Unterscheidung zwischen Wohnungen und Büros recht schwer.

0 – klassifiziert wurde: Buero, richtige Antwort: Buero
1 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
2 – klassifiziert wurde: Buero, richtige Antwort: Buero
3 – klassifiziert wurde: Buero, richtige Antwort: Buero
4 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
5 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
6 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
7 – klassifiziert wurde: Wohnung, richtige Antwort: Buero
8 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
9 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
10 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
11 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
12 – klassifiziert wurde: Buero, richtige Antwort: Buero
13 – klassifiziert wurde: Wohnung, richtige Antwort: Buero
14 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
15 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
16 – klassifiziert wurde: Buero, richtige Antwort: Buero
17 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
18 – klassifiziert wurde: Haus, richtige Antwort: Haus
19 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
20 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
21 – klassifiziert wurde: Buero, richtige Antwort: Buero
22 – klassifiziert wurde: Buero, richtige Antwort: Buero
23 – klassifiziert wurde: Buero, richtige Antwort: Buero
24 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
25 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
26 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
27 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
28 – klassifiziert wurde: Wohnung, richtige Antwort: Wohnung
29 – klassifiziert wurde: Buero, richtige Antwort: Buero
Error Count: 2

Über weitere Tests wird deutlich, dass k nicht zu niedrig und auch nicht zu hoch gesetzt werden darf.

 Datensätze  k Fehler
 150 1   25
 150 3   23
 150 5   21
 150 20   26

Ein nächster Schritt wäre die Entwicklung eines Trainingprogramms, dass die optimale Konfiguration (k-Eingrenzung, Gewichtung usw.) ermittelt.

Fehlerraten herabsenken

Die Fehlerquote ist im Grunde niemals ganz auf Null herabsenkbar, sonst haben wir kein maschinelles Lernen mehr, sondern könnten auch feste Regeln ausmachen, die wir nur noch einprogrammieren (hard-coding) müssten. Wer lernt, macht auch Fehler! Dennoch ist eine Fehlerquote von 10% einfach zu viel für die meisten Anwendungsfälle. Was kann man hier tun?

  1. Den Algorithmus verbessern (z. B. optimale k-Konfiguration und Gewichtung finden)
  2. mehr Merkmale finden (= mehr Dimensionen)
  3. mehr Daten hinzuziehen (gut möglich, dass alleine dadurch z. B. Wohnungen und Büros besser unterscheidbar werden)
  4. einen anderen Algorithmus probieren (kNN ist längst nicht für alle Anwendungen ideal!)

Das Problem mit den Dimensionen

Theoretisch kann kNN mit undenklich vielen Dimensionen arbeiten, allerdings steigt der Rechenaufwand damit auch ins unermessliche. Der k-nächste-Nachbar-Algorithmus ist auf viele Daten und Dimensionen angewendet recht rechenintensiv.

In der Praxis hat nicht jedes Merkmal die gleiche Tragweite in ihrer Bedeutung für die Klassifikation und mit jeder weiteren Dimension steigt auch die Fehleranfälligkeit, insbesondere durch Datenfehler (Rauschen). Dies kann man sich bei wenigen Dimensionen noch leicht bildlich vorstellen, denn beispielsweise könnten zwei Punkte in zwei Dimensionen nahe beieinander liegen, in der dritten Dimension jedoch weit auseinander, was im Ergebnis dann eine lange Distanz verursacht. Wenn wir beispielsweise 101 Dimensionen berücksichtigen, könnten auch hier zwei Punkte in 100 Dimensionen eng beieinander liegen, läge jedoch in der 101. Dimension (vielleicht auch auf Grund eines Datenfehlers) eine lange Distanz vor, wäre die Gesamtdistanz groß. Mit Gewichtungen könnten jedoch als wichtiger einzustufenden Dimensionen bevorzugt werden und als unsicher geltende Dimensionen entsprechend entschärft werden.

Je mehr Dimensionen berücksichtigt werden sollen, desto mehr Raum steht zur Verfügung, so dass um wenige Datenpunkte viel Leerraum existiert, der dem Algorithmus nicht weiterhilft. Je mehr Dimensionen berücksichtigt werden, desto mehr Daten müssen zu Verfügung gestellt werden, im exponentiellen Anstieg – Wo wir wieder beim Thema Rechenleistung sind, die ebenfalls exponentiell ansteigen muss.

Weiterführende Literatur


Machine Learning in Action

 


Introduction to Machine Learning with Python

Einführung in Data Science: Grundprinzipien der Datenanalyse mit Python

KNN: Rückwärtspass

Im letzten Artikel der Serie haben wir gesehen wie bereits trainierte Netzwerke verwendet werden können. Als Training wird der Prozess bezeichnet der die Gewichte in einen Netzwerk so anpasst, dass bei einem Vorwärtspass durch ein Netzwerk zu einen festgelegten Eingangsdatensatz ein bestimmtes Ergebnis in der Ausgangsschicht ausgegeben wird. Im Umkehrschluss heißt das auch, dass wenn etwas anderes ausgeliefert wurde als erwartet, das Netzwerk entweder noch nicht gut genug oder aber auf ein anderes Problem hin trainiert wurde.

Training

Das Training selbst findet in drei Schritten statt. Zunächst werden die Gewichte initialisiert. Üblicherweise geschieht das mit zufälligen Werten, die aus einer Normalverteilung gezogen werden. Je nachdem wie viele Gewichte eine Schicht hat, ist es sinnvoll die Verteilung über den Sigma Term zu skalieren. Als Daumenregeln kann dabei eins durch die Anzahl der Gewichte in einer Schicht verwendet werden.

Im zweiten Schritt wird der Vorwärtspass für die Trainingsdaten errechnet. Das Ergebnis wird beim ersten Durchlauf alles andere als zufrieden stellend sein, es dient aber dem Rückwärtspass als Basis für dessen Berechnungen und Gewichtsänderungen. Außerdem kann der Fehler zwischen der aktuellen Vorhersage und dem gewünschten Ergebnis ermittelt werden, um zu entscheiden, ob weiter trainiert werden soll.

Der eigentliche Rückwärtspass errechnet aus der Differenz der Vorwärtspassdaten und der Zieldaten die Steigung für jedes Gewicht aus, in dessen Richtung dieses geändert werden muss, damit das Netzwerk bessere Vorhersagen trifft. Das klingt zunächst recht abstrakt, die genauere Mathematik dahinter werde ich in einem eigenen Artikel erläutern. Zur besseren Vorstellung betrachten wir die folgende Abbildung.

    visuelle Darstellung aller Gewichtskombinationen und deren Vorhersagefehler

Das Diagramm zeigt in blau zu allen möglichen Gewichtskombinationen eines bestimmten, uns unbekannten, Netzwerks und Problems den entsprechenden Vorhersagefehler. Die Anzahl der Kombinationen hängt von der Anzahl der Gewichte und der Auflösung des Wertebereiches für diese ab. Theoretisch ist die Menge also unendlich, weshalb die blaue Kurve eine von mir ausgedachte Darstellung aller Kombinationen ist. Der erste Vorwärtspass liefert uns eine Vorhersage die eine normalisierte Differenz von 0.6 zu unserem eigentlichen Wunschergebnis aufweist. Visualisiert ist das Ganze mit einer schwarzen Raute. Der Rückwärtspass berechnet aus der Differenz und den Daten vom Vorwärtspass einen Änderungswunsch für jedes Gewicht aus. Da die Änderungen unabhängig von den anderen Gewichten ermittelt wurden, ist nicht bekannt was passieren würde wenn alle Gewichte sich auf einmal ändern würden. Aus diesem Grund werden die Änderungswünsche mit einer Lernrate abgeschwächt. Im Endeffekt ändert sich jedes Gewicht ein wenig in die Richtung, die es für richtig erachtet. In der Hoffnung einer Steigerung entlang zu einem lokalen Minimum zu folgen, werden die letzten beiden Schritte (Vor- und Rückwärtspass) mehrfach wiederholt. In dem obigen Diagramm würde die schwarze Raute der roten Steigung folgen und sich bei jeder Iteration langsam auf das linke lokale Minimum hinzubewegen.

 

Anwendungsbeispiel und Programmcode

Um den ganzen Trainingsprozess im Einsatz zu sehen, verwenden wir das Beispiel aus dem Artikel “KNN: Vorwärtspass”. Die verwendeten Daten kommen aus der Wahrheitstabelle eines X-OR Logikgatters und werden in ein 2-schichtiges Feedforward Netzwerk gespeist.

XOR Wahrheitstabelle

X1 X2 Y = X1 ⊻ X2
0 0 0
0 1 1
1 0 1
1 1 0

Der Programmcode ist in Octave geschrieben und kann zu Testzwecken auf der Webseite von Tutorialpoint ausgeführt werden. Die erste Hälfte von dem Algorithmus kennen wir bereits, der Vollständigkeit halber poste ich ihn noch einmal, zusammen mit den Rückwärtspass. Hinzugekommen sind außerdem ein paar Konsolenausgaben, eine Lernrate- und eine Iterations-Variable die angibt wie viele Trainingswiederholungen durchlaufen werden sollen.

Zu jeder Zeile bzw. Funktion die wir im Vorwärtspass geschrieben haben, gibt es im Rückwärtspass eine abgeleitete Variante. Dank den Ableitungen können wir die Änderungswünsche der Gewichte in jeder Schicht ausrechnen und am Ende einer Trainingsiteration anwenden. Wir trainieren 10.000 Iterationen lang und verwenden eine Lernrate von 0,8. In komplexeren Fragestellungen, mit mehr Daten, würden diese Werte niedriger ausfallen.

Es ist außerdem möglich den ganzen Programmcode viel modularer aufzubauen. Dazu werde ich im nächsten Artikel auf eine mehr objekt-orientiertere Sprache wechseln. Nichts desto trotz liefert der obige Algorithmus gute Ergebnisse. Hier ist mal ein Ausgabebeispiel:

 

Data Science mit Neo4j und R

Traurig, aber wahr: Data Scientists verbringen 50-80% ihrer Zeit damit, Daten zu bereinigen, zu ordnen und zu bearbeiten. So bleibt nur noch wenig Zeit, um tatsächlich vorausschauende Vorhersagemodelle zu entwickeln. Vor allem bei klassischen Stacks, besteht die Datenanalyse zum Großteil darin, Zeile für Zeile in SQL zu überführen. Zeit zum Schreiben von Modell-Codes in einer statistischen Sprache wie R bleibt da kaum noch. Die langen, kryptischen SQL-Abfragen verlangsamen aber nicht nur die Entwicklungszeit. Sie stehen auch einer sinnvollen Zusammenarbeit bei Analyse-Projekten im Weg, da alle Beteiligten zunächst damit beschäftigt sind, die SQL-Abfragen der jeweils anderen zu verstehen.

Komplexität der Daten steigt

Der Grund für diese Schwierigkeiten: Die Datenstrukturen werden immer komplexer, die Vernetzung der Daten untereinander nimmt immer stärker zu. Zwängt man diese hochgradig verbundenen Datensätze in eine SQL-Datenbank, in der Beziehungen naturgemäß abstrakt über Fremdschlüssel dargestellt werden, erhält man als Ergebnis übermäßig komplizierte Schematas und Abfragen. Als Alternative gibt es jedoch einige NoSQL-Lösungen – allen voran Graphdatenbanken – die solche hochkomplexen und heterogenen Daten ohne Informationsverlust speichern können – und zwar nicht nur die Entitäten an sich, sondern auch besonders die Beziehungen der Daten untereinander.

Datenanalysen zielen immer stärker darauf ab, das Verhalten und die Wünsche von Kunden besser verstehen zu können. Die Fragen lauten z. B.:

  • Wie hoch ist die Wahrscheinlichkeit, dass ein Besucher auf eine bestimmte Anzeige klickt?
  • Welcher Kunde sollte in welchem Kontext welche Produktempfehlungen erhalten?
  • Wie kann man aus der bisherigen Interaktionshistorie des Kunden sein Ziel vorhersagen, bevor er selbst dort ankommt?
  • In welchen Beziehungen steht Nutzer A zu Nutzer B?

Menschen sind bekanntermaßen von Natur aus sozial. Einige dieser Fragen lassen sich daher beantworten, wenn man weiß, wie Personen miteinander in Verbindung stehen: Unsere Zielperson, Nutzer A ähnelt in seinem Kontext und Verhalten Benutzer B. Und da Benutzer B ein bestimmtes Produkt (z. B. ein Spielfilm) gefällt, empfehlen wir diesen Film auch Nutzer A. In diese Auswertung fließen natürlich auch noch weitere Faktoren mit ein, z. B. die Demographie und der soziale Status des Nutzers, seine Zuordnung zu Peer Groups, vorher gesehene Promotions oder seine bisherigen Interaktionen.

Visualisierung eines Graphen mit RNeo4j

Mit R und Neo4j lassen sich Graphen und Teilgraphen ganz einfach mit RNeo4j, igraph und visNetwork libraries visualisieren.

 

Das folgende Beispiel zeigt wie in einem Graphen Schauspieler und Filme sowie ihre Beziehungen zueinander anschaulich dargestellt werden können, z. B. um Empfehlungen innerhalb eines Filmportals zu generieren. Dabei sind zwei Schauspieler über eine Kante miteinander verbunden, wenn sie beide im gleichen Film mitspielen.

Im ersten Schritt werden dazu in Neo4j die Film-Datensätze importiert (Achtung: Dieser Vorgang löscht die aktuelle Datenbank).

Als nächstes wird mit Cypher eine entsprechende Liste von Beziehungen aus Neo4j gezogen. Wie man sehen kann, ist die Darstellung des gewünschten Graph-Musters innerhalb der Abfrage sehr anschaulich.

Die visNetwork Funktion erwartet sowohl Kanten-Dataframes als auch Knoten-Dataframes. Ein Knoten-Dataframe lässt sich daher über die eindeutigen Werte des Kanten-Dataframes generieren.

Im Anschluss können die Knoten- und Kanten-Dataframes in das visNetwork übertragen werden.
visNetwork(nodes, edges)

Nun kommt igraph mit ins Spiel, eine Bibliothek von Graph-Algorithmen. Durch Einbindung der Kantenliste lässt sich einfach ein igraph Graph-Objekt erstellen, das den Teilgraphen miteinschließt.

Die Größe der Knoten kann als Funktion der Edge-Betweeness-Centrality definiert werden. In visNetwork entspricht dabei jede “value”-Spalte im Knoten-Dataframe der Größe des Knoten.
nodes$value = betweenness(ig)

Mit Einführung der “Value”-Spalte werden die Knoten nun alle unterschiedlich groß dargestellt.
visNetwork(nodes, edges)

Mit Hilfe eines Community-Detection-Algorithmus lassen sich im Graphen nun Cluster finden. In diesem Beispiel wird der „Girvan-Newman”-Algorithmus verwendet, der in igraph als cluster_edge_betweenness bezeichnet wird.

In der Liste oben sind alle Schauspieler der ersten zwei Cluster zu sehen. Insgesamt konnten sechs Cluster identifiziert werden.

Durch Hinzufügen einer “Group”-Spalte im Knoten-Dataframe, werden alle Knoten in visNetwork entsprechend ihrer Gruppenzugehörigkeit farblich markiert. Diese Cluster-Zuordnung erfolgt über clusters$membership. Durch Entfernen der “Value”-Spalte lassen sich die Knoten wieder auf eine einheitliche Größe bringen.

Werden die Knoten- und Kanten-Datenframes erneut in visNetwork übertragen, sind nun alle Knoten eines Clusters in derselben Farbe dargestellt.
visNetwork(nodes, edges)

Mit diesem Workflow lassen sich Teilgraphen in Neo4j einfach abfragen und Cluster-Algorithmen einfach darstellen.

Generell eignen sich Graphdatenbanken wie Neo4j besonders gut, um stark vernetzte und beliebig strukturierte Informationen zu handhaben – egal ob es sich um Schauspieler, Filme, Kunden, Produkte, Kreditkarten oder Bankkonten handelt. Zudem können sowohl den Knoten als auch den Kanten beliebige qualitative und quantitative Eigenschaften zugeordnet werden. Beziehungen zwischen Daten sind also nicht mehr bloße Strukturinformationen, sondern stehen vielmehr im Zentrum des Modells.

Cypher: intuitiv nutzbare Programmiersprache

Die Zeiten, in denen Data Science zum Großteil aus Datenbereinigung und -mapping besteht, sind damit vorbei. Mit dem entsprechenden Ansatz laufen Entwicklungsprozesse deutlich schneller und einfacher ab. Data Scientists kommen mit weniger Code schneller ans Ziel und können mehr Zeit in das tatsächliche Entwickeln von relevanten Modellen investieren. Dabei nutzen sie die Flexibilität einer quelloffenen NoSQL-Graphdatenbank wie Neo4j kombiniert mit der Reife und weiten Verbreitung der Statistiksprache R für statistisches Rechnen und Visualisierung. Programmierer müssen nicht mehr stundenlang komplexe SQL-Anweisungen schreiben oder den ganzen Tag damit verbringen, eine Baumstruktur in SQL zu überführen. Sie benutzen einfach Cypher, eine musterbasierte, für Datenbeziehungen und Lesbarkeit optimierte Abfragesprache und legen los.

Neural Nets: Time Series Prediction

Artificial neural networks are very strong universal approximators. Google recently defeated the worlds strongest Go (“chinese chess”) player with two neural nets, which captured the game board as a picture. Aside from these classification tasks, neural nets can be used to predict future values, behaviors or patterns solely based on learned history. In the machine learning literature, this is often referred to as time series prediction, because, you know, values over time need to be predicted. Hah! To illustrate the concept, we will train a neural net to learn the shape of a sinusoidal wave, so it can continue to draw the shape without any help. We will do this with Scala. Scala is a great lang, because it is strongly typed but feels easy like Python. Throughout this article, I will use the library NeuroFlow, which is a simple, lightweight library I wrote to build and train nets. Because Open Source is the way to go, feel free to check (and contribute to? :-)) the code on GitHub.

Introduction of the shape

If we, as humans, want to predict the future based on historic observations, we would have no other chance but to be guided by the shape drawn so far. Let’s study the plot below, asking ourselves: How would a human continue the plot?

sinuspredictdr
f(x) = sin(10*x)

Intuitively, we would keep on oscillating up and down, just like the grey dotted line tries to rough out. To us, the continuation of the shape is reasonably easy to understand, but a machine does not have a gut feeling to ask for a good guess. However, we can summon a Frankenstein, which will be able to learn and continue the shape based on numbers. In order to do so, let’s have a look at the raw, discrete data of our sinusoidal wave:

x f(x)
0.0 0.0
0.05 0.479425538604203
0.10 0.8414709848078965
0.15 0.9974949866040544
0.20 0.9092974268256817
0.25 0.5984721441039564
0.30 0.1411200080598672
0.35 -0.35078322768961984
0.75 0.9379999767747389

Ranging from 0.0 until 0.75, these discrete values drawn from our function with step size 0.05 will be the basis for training. Now, one could come up with the idea to just memorize all values, so a sufficiently reasonable value can be picked based on comparison. For instance, to continue at the point 0.75 in our plot, we could simply examine the area close to 0.15, noticing a similar value close to 1, and hence go downwards. Well, of course this is cheating, but if a good cheat is a superior solution, why not cheat? Being hackers, we wouldn’t care. What’s really limiting here is the fact that the whole data set needs to be kept in memory, which can be infeasible for large sets, plus for more complex shapes, this approach would quickly result in a lot of weird rules and exceptions to be made in order to find comprehensible predictions.

Net to the rescue

Let’s go back to our table and see if a neural net can learn the shape, instead of simply memorizing it. Here, we want our net architecture to be of kind [3, 5, 3, 1]. Three input neurons, two hidden layers with five and three neurons respectively, as well as one neuron for the output layer will capture the data shown in the table.

sinuspredictnet

A supervised training mode means, that we want to train our net with three discrete steps as input and the fourth step as the supervised training element. So we will train a, b, c -> d and e, f, g -> h et cetera, hoping that this way our net will capture the slope pattern of our sinusoidal wave. Let’s code this in Scala:

First, we want a Tanh activation function, because the domain of our sinusoidal wave is [-1, 1], just like the hyperbolic tangent. This way we can be sure that we are not comparing apples with oranges. Further, we want a dynamic network (adaptive learning rate) and random initial weights. Let’s put this down:

No surprises here. After some experiments, we can pick values for the settings instance, which will promise good convergence during training. Now, let’s prepare our discrete steps drawn from the sinus function:

We will draw samples from the range with step size 0.05. After this, we will construct our training values xs as well as our supervised output values ys. Here, a group consists of 4 steps, with 3 steps as input and the last step as the supervised value.

After a pretty short time, we will see good news. Now, how can we check if our net can successfully predict the sinusoidal wave? We can’t simply call our net like a sinus function to map from one input value to one output value, e. g. something like net(0.75) == sin(0.75). Our net does not care about any x values, because it was trained purely based on the function values f(x), or the slope pattern in general. We need to feed our net with a three-dimensional input vector holding the first three, original function values to predict the fourth step, then drop the first original step and append the recently predicted step to predict the fifth step, et cetera. In other words, we need to traverse the net. Let’s code this:

with

So, basically we don’t just continue to draw the sinusoidal shape at the point 0.75, we draw the entire shape right from the start until 4.0 – solely based on our trained net! Now, let’s see how our Frankenstein will complete the sinusoidal shape from 0.75 on:

sinuspredictfintwo

I’d say, pretty neat? Keep in mind, here, the discrete predictions are connected through splines. Another interesting property of our trained net is its prediction compared to the original sinus function when taking the limit towards 4.0. Let’s plot both:

sinuspredictfin

The purple line is the original sinusoidal wave, whereas the green line is the prediction of our net. The first steps show great consistency, but slowly the curves diverge a little over time, as uncertainties will add up. To keep this divergence rather low, one could fine tune settings, for instance numeric precision. However, if one is taking the limit towards infinity, a perfect fit is illusory.

Final thoughts

That’s it! We have trained our net to learn and continue the sinusoidal shape. Now, I know that this is a rather academic example, but to train a neural net to learn more complex shapes is straightforward from here.

Thanks for reading!

Datenvisualisierung in Python [Tutorial]

Python ist eine der wichtigsten Programmiersprachen in der Data Science Szene. Der Einstieg in diese Programmiersprache fällt zum Beispiel im Vergleich zur Programmiersprache R etwas einfacher, da Python eine leicht zu verstehende Syntax hat. Was jedoch beim Einstieg zur größeren Hürde werden kann, ist der Umgang mit den unüberschaubar vielen Bibliotheken. Die wichtigsten Bibliotheken für Data Science / Data Analytics stellte ich bereits in diesem Artikel kurz vor. Hier ist es wichtig, einfach erstmal anzufangen – Warum nicht mit den ersten Datenvisualisierungen?

Natürlich gibt es sehr viele tolle und schön anzusehende Visualisierungen, die teilweise sehr speziell sind. In einem anderen Artikel stellte ich beispielsweise die 3D-Visualisierung von Graphen mit Python und UbiGraph vor. Dieser Artikel hier gilt aber vor allem Einsteigern, die erste Diagramme hergezaubert bekommen möchten.

Damit wir beginnen können, müssen im Python-Skript zuerst zwei wichtige Bibliotheken eingebunden werden:

import matplotlib.pyplot as pyplot

import pandas as pandas

Beide Bibliotheken können direkt gedownloaded werden, sind aber auch im Anaconda Framework enthalten (Empfehlung: Anaconda für Python 2.7).

Die Bibliothek matplotlib (library) ist mit Sicherheit die gängigste zur Visualisierung von Daten. Die Bibliothek pandas ist eine der verbreitetsten, die für den Zugriff, die Manipulation und Analyse von Daten eingesetzt wird. In diesen einfachsten Beispielen benutzen wir pandas nur zum Zugriff auf Daten.

Für die Visualisierung benötigen wir natürlich auch ein Beispiel-Dataset (Tabelle). Eine solche kann sich jeder selber erstellen, wer die nachfolgenden Code-Beispiele aber nachstellen möchte, kann diese Daten verwenden:

Diese 20 Zeilen können einfach via Copy + Paste in eine Datei kopiert werden, die dann als data-science-blog-python-beispiel.txt abgespeichert werden kann.

Der Zugriff von Python aus erfolgt dann mit pandas wie folgt:

dataset = pandas.read_csv("data-science-blog-python-beispiel.txt", sep="|", header=0, encoding="utf8")

Kreisdiagramm

Ein Kreisdiagramm (Pie Chart) lässt sich basierend auf diesen Daten beispielsweise wie folgt erstellen:

kreisdiagramm

Balkendiagramm

Balkendiagramme können einfachste Größenverhältnisse aufzeigen.

balkendiagram

Gestapeltes Balkendiagramm

Mit nur wenig Erweiterung wird aus dem einfachen Balkendiagramm ein gestapeltes.

balkendiagram-gestapelt

Histogramm (Histogram)

Histogramme sind ein wichtiges Diagramm der Statistik, mit dem sich Verteilungen aufzuzeigen lassen.

histogramm

Lininediagramm

Der Beispieldatensatz gibt kein gutes Szenario her, um ein korrektes Liniendiagramm darstellen zu können; aber dennoch hier ein How-To für ein Liniendiagramm:

line-diagam

Kastengrafik (Box Plot)

Ein Box Plot zeigt sehr gut Schwerpunkte in einer Verteilung.

box-plot-diagam

Punktverteilungsdiagramm (Scatter Plot)

punktdiagramm

Blasendiagramm (Bubble Chart)

Das Punktdiagramm kann leicht durch hinzufügen einer dritten Dimension zu einem Bubble-Chart erweitert werden. In dieser Darstellung mit logarithmischen x-/y-Achsen (log).

bubblechart

 

Flexible ABC Analyse mit Excel Power Pivot und DAX

Eine klassische Methode im Bereich des Controllings ist sicherlich die ABC-Analyse, auch Paretoprinzip oder 80/20-Regel genannt. Das Paretoprinzip beschreibt ein statistisches Phänomen, bei dem eine kleine Anzahl hoher Werte (Kategorie A)  mehr zum Gesamtwert beiträgt als eine große Anzahl kleiner Werte (Kategorie C). Vilfredo Pareto (1848 – 1923)  entdeckte dieses Prinzip, als er die Bodenverteilung in Italien untersuchte. Er fand heraus, daß ca. 20 % der Bevölkerung ca. 80 % des Bodenbesitzes besitzen.

Im Folgenden soll mit Hilfe von Excel Power Pivot (ein Mitglied der Microsoft Power BI Familie) und DAX Formeln (Data Analysis Expressions) ein Weg aufgezeigt werden, wie eine flexible ABC-Analyse (Materialgruppenübergreifend oder je Materialgruppe) auf Basis von Artikelumsätzen (Einkaufsvolumen, EVO) realisiert werden kann. Dabei werden die Artikel mit den Kategorien A (80 %), B (15%) sowie C (5%) im Modell gekennzeichnet, so daß Anzahl Artikel und Umsätze (EVO) bei Bedarf aggregiert nach Materialgruppe dargestellt werden können.

„Aber das kann ich doch mit der Pivottabelle auch schon machen!“ werden Sie jetzt vielleicht sagen. Richtig ist, daß man mit der klassischen Pivottabelle den kumulierten Anteil in % ausweisen kann. Dazu muß ein Wertfeld lediglich über die Wertfeldeinstellungen, Reiter „Werte anzeigen als“ auf die Option „% von Ergebnis in“ umgestellt werden. Soweit so gut, nur was ist mit der Zuweisung der Klasse A, B, C? Wie kann man nach der Klassifizierung gruppieren? Und weiter, wie stellt man die Anzahl der Artikel nicht als einzelne Elemente sondern als Aggregat dar?

excel-abc-analyse-1 Read more

Von Rohdaten zu entscheidungsrelevanten Informationen mit Microsoft Self Service BI

Ganz still und leise, ja fast geräuschlos führte Microsoft in Office 2010 „by the backdoor“ eine Reihe von kostenlosen AddIns ein. Diese AddIns unterstützen die Anbindung von heterogenen Datenquellen, deren Kombination, Anreicherung, Modellierung und Visualisierung. Microsoft faßt diese AddIns unter dem Begriff Power BI zusammen: Excel Power Query, Excel Power Pivot, Excel Power View, Excel Power Map. Diese Power BI Tools können sich durchaus mit anderen am Markt verfügbaren BI Tools messen. Die Vorteile liegen auf der Hand, sie sind kostenlos und die Akzeptanz von Excel in Unternehmen kann als gegeben vorausgesetzt werden. Geschäftsrelevante Daten können mit Hilfe dieses tool sets effizient in entscheidungsrelevante Informationen „in Form“ gebracht werden: ETL (Einlesen, Transformieren, Laden), DI (Daten Integration), DQ (Datenqualität), Data Visualization, BI Themen, welche ausreichend abgedeckt werden. Ein kostenloses Tool Set, wie gemacht für den Fachanwender. Unter Self Service BI versteht man die Bereitstellung einer IT Umgebung für den Fachanwender, durch deren Hilfe er oder sie weitestgehend unabhängig von der IT Daten beschaffen, Analysen erstellen und Berichte erzeugen kann. Dieses agile Business Intelligence Konzept ermöglicht dem Fachanwender schnelles und effizientes Agieren auf sich ändernde Anforderungen steuerungsrelevante Kennzahlen betreffend. Ein probates Mittel ist Self Service BI bei regelmäßig wiederkehrenden Entscheidungen. Im Folgenden soll das Prinzip der Selbstbedienung anhand eines konkreten Beispiels aus dem Einkauf näher beleuchtet werden. Dabei werden die einzelnen Phasen (ETL, Modellierung, interaktive Auswertung) und Funktionen (DAX Funktionen) eines typischen Self Service Prozesses von Excel Power Pivot dargestellt. Das Datenmodell wurde mit Excel 2013 erstellt. Ab Office 2013 ist Power BI bereits im Auslieferungszustand vorhanden. Read more