GIS in RapidMiner (1)

(English version)

Update 2020-02: GIS-Funktionalität ist jetzt als Erweiterung verfügbar.

Es gibt regelmäßig Kundenanfragen nach GIS-Funktionalität in RapidMiner. Leider ist eine solche Funktionalität (noch) nicht im Kern oder in Erweiterungen enthalten. Trotzdem kann man einiges erreichen, wenn man bereit ist, sich etwas in die Materie einzuarbeiten.

Meine bevorzugte Lösung ist, möglichst viel in einer geographischen Datenbankumgebung wie PostGIS zu erledigen. Damit sind die im Folgenden beschriebenen Dinge leicht zu lösen. Leider gibt es nicht überall eine PostGIS-Installation. Es kann also notwendig sein, die Funktionalität in RapidMiner nachzubauen.

In dieser Serie von Posts möchte ich erklären, wie man RapidMiner erweitert, um Geodaten zu verarbeiten und aus ihnen neue Informationen zu gewinnen.

Ziele

Einige Funktionen, die von einer GIS-fähigen Software erwartet werden:

  • Geodaten aus verbreiteten (Datei-)Formaten lesen
  • Distanzberechnung zwischen Punkten oder anderen Objekten
  • Berechnung von Abmessungen von Objekten, etwa Länge, Umfang und Fläche
  • Identifizierung von Objekten, die sich berühren, enthalten oder überlappen
  • Selektion von Objekten anhand ihrer Position, Abmessungen oder in Abhängigkeit von anderen Objekten

Damit können wir im Data-Science-Kontext ganz viel machen. Wir können Objekte klassifizieren (z. B. Punkte in einer Stadt, Straßen in der Nähe von Autobahnen usw.), Punkte clustern und Attribute ableiten, die bei der Analyse hilfreich sind. Wir können auch zwei Datensätze im Hinblick auf ihre geographische Lage abgleichen, z. B. Flächen suchen, die sich berühren oder überschneiden.

Koordinatensysteme

Die meisten geographischen Daten, auf die wir im Internet treffen, sind in Längen- und Breitengrad-Koordinaten angegeben. Dieses System hat den Vorteil, daß es einen Punkt auf der Erde mit zwei Zahlen (-90 (Süd) bis +90 (Nord) und -180 (West) bis +180 (Ost) Grad) ausdrückt. Das Problem dieser Darstellung ist jedoch, daß die Distanz zwischen zwei Punkten in Koordinaten nicht leicht zu interpretieren ist. Am Äquator sind die gedachten Linien weiter auseinander als in Mitteleuropa, und am Nord- und Südpol treffen sie sich schließlich in einem Punkt. Deswegen gibt es keine einfache Formel „Ein Längengrad entspricht X Metern”.

Für einige Anwendungen mag das genügen. Um z. B. in einer Stadt den nächsten Punkt B vom Punkt A zu finden, können die simplen Koordinaten sehr wohl verwendet werden. Aber wir können nicht mit Distanzen und Flächenangaben rechnen. In einem größeren Gebiet (Deutschland, Europa, USA…) sind die Unterschiede zwischen einzelnen Koordinatenpaaren auch nicht mehr sauber interpretierbar.

Den Ausweg bieten Koordinatensysteme (oder Koordinatenbezugssysteme, KBS abgekürzt). Sie werden auch „Projektion“ genannt, da mit ihrer Hilfe die ellipsoidförmige Erde in zwei Dimensionen (also auf Papier oder Bildschirm) abgebildet, „projiziert“ wird.

Koordinatensysteme sind üblicherweise für eine bestimmte Region (z. B. ein Land) definiert und erlauben, in üblichen Maßeinheiten wie Meter zu rechnen. Sie stellen sicher, daß die reale Distanz zwischen der Koordinate 100 and der Koordinate 101 (Beispiel) sowohl im Norden als auch im Süden des betreffenden Landes gleich groß ist.

Die verbreiteten Koordinatensysteme sind zentral registriert, sie können mit einer „EPSG-Nummer“ angesprochen werden.

In Deutschland sehe ich häufig Varianten der Gauß-Krüger-Projektion in Verwendung, z. B. EPSG:31468. Für Österreich verwende ich ETRS89/Austria Lambert, EPSG:3416.

Werkzeug-Auswahl und Installation

GeoScript ist ein Skripting-Frontend für andere Open-Source-Bibliotheken (z. B. GeoTools) und andere mit Groovy-Anbindung. Da RapidMiner Groovy-Skripting eingebaut hat, können wir GeoScript verwenden. (Es gäbe auch die Möglichkeit, mit R- oder Python-Skripten in RapidMiner zu arbeiten. Diese sind jedoch eigene Extensions, die zusätzlich installiert und gewartet werden müssen.)

Die Installation birgt einige Tücken. Der GeoScript-Download bringt 218 jar-Archive mit einer Gesamtgröße von 71 MB mit – viele davon werden auch in RapidMiner (teilweise in anderen Versionen) verwendet. Ich warne davor, all diese Jars ins RapidMiner-lib-Verzeichnis zu kopieren – RapidMiner Studio startet dann nicht mehr.

Deswegen müssen die Jars selektiv hineinkopiert werden, solange RapidMiner noch verwendbar ist, aber die gewünschte Funktionalität zur Verfügung steht.

Mein Ansatz ist der folgende: Unter rapidminer-studio/lib erzeuge ich ein Verzeichnis „geoscript”, und kopiere die Libraries dorthin. Danach wird das Startskript von RapidMiner Studio um diesen Classpath erweitert (rmClasspath= … in der sh-Datei).

Ein Zip-Archiv mit meiner Auswahl der Libraries (aus den Projekten GeoScript und GeoTools) liegt hier. Zusätzlich habe ich im rapidminer-studio/lib-Verzeichnis groovy-all-2.3.3.jar in .jar.old umbenannt und groovy-all-2.4.5.jar aus der Groovy-Distribution hineinkopiert.

Verwendung von Geodaten in RapidMiner

Als erstes müssen wir die Daten in RapidMiner hineinbringen. Hierfür gibt es viele Möglichkeiten, beginnend mit Geokoordinaten in CSV-Dateien bis hin zu geographischen Datenbanken.

Shapefile ist ein verbreitetes Dateiformat, in dem die Geodaten mit weiteren Attributen verknüpft sein können. GeoScript kann Shapefiles einlesen, wir können aus ihnen somit ganz normale RapidMiner-ExampleSets machen.

Dann müssen wir eine Repräsentation der Daten finden, mit der RapidMiner umgehen kann. Für Punkte kann es passen, sie als zwei Attribute (latitude  und longitude) mitzuführen. Für komplexere Objekte wie Linien (z. B. Straßenverlauf) und Polygone (z. B. Ländergrenzen) reicht es aber nicht.

Es gibt verschiedene Repräsentationsmöglichkeiten für Geometrien: Well Known Text (WKT), Well Known Binary (WKB), GeoJSON usw. GeoScript enthält Konvertierungsfunktionen für diese Formate, wir können also die Geometrie-Objekte in RapidMiner in einem Nominal-Attribut mitführen. Ich habe WKT, WKB und GeoJSON mit großen Mengen von Geometrie-Objekten getestet, in der Verarbeitungsgeschwindigkeit gibt es keine großen Unterschiede.

Für WKT spricht, daß es in GeoScript einfach mit fromWKT() eingelesen und mit toString() ausgegeben werden kann. Für die anderen Formate muß man Reader- und Writer-Objekte bemühen.

Groovy-Skripting in RapidMiner

Eine wichtige Referenz fürs Skripting ist „How to Extend RapidMiner 5”, auch für Version 6.X noch gültig. Darin ist beschrieben, wie ExampleSets erweitert werden. Das brauchen wir, wenn wir mit Hilfe von Geo-Funktionen neue Attribute erstellen. Forum-Beiträge wie dieser ergänzen die Informationen um die Erzeugung ganzer neuer ExampleSets. Damit können wir einen Import aus Geo-Dateiformaten wie Shapefiles realisieren.

Ausblick

Die nächsten Beiträge dieser Serie beschäftigen sich mit dem Import von Shapefiles und anderen Dateiformaten, der Konvertierung zwischen Koordinatensystemen, der Berechnung von Distanzen und Abmessungen von Objekten sowie mit geographischen Operationen.

Bisherige Ansätze

Thomas Ott: Geospatial Distance in RapidMiner and Python

Thomas Ott: Extracting OpenStreetMap Data in RapidMiner: Geokodierung mit OpenStreetMap-Daten

Using Web Services in RapidMiner: Geokodierung mit der Google Geocoding API

GIS in RapidMiner

Update 2020-02: GIS functionality is now  available as an extension.

Customers sometimes ask for GIS functionality in RapidMiner. This functionality is not (yet) built into the core, nor it is available as an extension. However, with a bit of learning, many problems can be solved.

My preferred solution for geographic data processing is a database environment like PostGIS. All the topics I’ll describe here are easily solved there. Unfortunately, not everyone has a PostGIS installation, so it can be necessary to implement the functionality in RapidMiner.

In this series of blog posts I’d like to demonstrate how RapidMiner can be extended to process geodata and gain information from them.

Goals

Some functions expected from a GIS-capable software are:

  • Import of geographic data from popular (file) formats
  • Distance calculation between points or other objects
  • Calculation of metrics like length, circumference or area
  • Identification of objects that touch, contain or intersect with each other
  • Selection of objects based on their position, metrics or in dependence on other objects

We can do a lot with these capabilities in a data science context: Classify objects (e. g. points in a city, streets near highways etc.), cluster points, and derive helpful attributes for further analysis. We can also connect two data sets by their geographic position, for example find areas that touch or intersect.

Coordinate systems

Most geographic data on the Internet is coded in latitude and longitude coordinates. This notation is able to express each point on Earth with two numbers: -90 (south) to +90 (north) and -180 (west) to +180 (east). The problem with this representation is the bad interpretability of distance between coordinates. On the equator, the fictive lines are further from each other than in Central Europe, and they even meet on the North and South Poles. So there is no simple formula like “One degree of latitude is X meters”.

This can be good enough for some applications. You can select the nearest point for another point in a city with them. But it’s not possible to calculate distances and areas in meters or other useful units. In a larger area like Germany, Europe or the USA, even the differences between coordinate pairs are not well interpretable.

The solution for this problem is using coordinate systems (also called coordinate reference systems, CRS). They are also called “projections” because they’re used for displaying the ellipsoid of Earth in two dimensions on paper or a screen.

Coordinate systems are usually defined for a particular region like a country and enable calculations in useful units like meters. They make sure that the real distance between coordinates 100 and 101 (for example) is the same both in the northern and the southern
part of the country or region.

There is a central registry of coordinate systems, they can be referred to by using an “EPSG number” in almost any geo-capable software.

In Germany I’ve seen usage of Gauss-Krueger projections like EPSG:31468. For Austria I use ETRS89/Austria Lambert (EPSG:3416).

Tool selection and installation

GeoScript is a scripting frontend for other open source libraries (e. g. GeoTools) and others. It has a Groovy implementation. As RapidMiner also contains Groovy scripting, we can use GeoScript therein. (It would be possible to use R or Python scripts in RapidMiner. But these are separate extensions with additional installation and maintenance.)

Installation is not easy. The GeoScript download contains 218 jar archives weighing 71 MB – some of them are also used in RapidMiner (even some differing versions). It is not advisable to simply copy all of them into the lib directory of RapidMiner – Studio won’t start then.

Therefore, only a selection of the jars must be copied, as long as RapidMiner is still usable, and the desired geographic function is there.

My approach was to create a new subdirectory under rapidminer-studio/lib called “geoscript” and copy the libraries into it. The start script of RapidMiner Studio must be extended to contain the additional subdirectory in the class path (rmClasspath=… in the shell file).

Here is a zip archive of my library selection, copied together from the GeoScript and GeoTools projects. Additionally, I renamed groovy-all-2.3.3.jar to .jar.old in rapidminer-studio/lib and copied groovy-all-2.4.5.jar from the Groovy distribution.

Using geodata in RapidMiner

First we must import the data into RapidMiner. There are many methods for this, from geometries in CSV files to geographic databases.

A popular file format is „shapefile“. It contains the geometries with additional attributes. GeoScript can read shapefiles, so we can import them as normal ExampleSets into RapidMiner.

After importing we need to find a suitable representation of geodata. It is possible to work with two attributes for the latitude and longitude of points, but they’re not suitable for more complex types like LineString (e. g. streets) or Polygon (e. g. countries).

There are different representations of geometries: Well Known Text (WKT), Well Known Binary (WKB), GeoJSON etc. GeoScript contains conversion functions for these and more formats, so we can convert geometries to a string representation to store them in a Nominal attribute in RapidMiner. I tested WKT, WKB and GeoJSON with a huge number of geometry objects, the processing speed is not really different.

WKT can be read by GeoScript using the fromWKT() function and written with toString(). This is easier than with the other formats which require the usage of Reader and Writer objects.

Groovy scripting in RapidMiner

An important reference for scripting RapidMiner is „How to Extend RapidMiner 5„, still valid for version 6.
It describes the manipulation of ExampleSets and the creation of additional attributes. We need this for creating new attributes with geographic functions. Forum posts like this describe the creation of entirely new ExampleSets. This enables the import of geographic data files like shapefiles.

Preview

The next parts of this series of blog posts will describe the import of shapefiles and other geographic data, conversion between coordinate systems, calculation of distances and measures, and geographic operations.

Previous work

Thomas Ott: Geospatial Distance in RapidMiner and Python

Thomas Ott: Extracting OpenStreetMap Data in RapidMiner: Geocoding using OpenStreetMap data

Using Web Services in RapidMiner: Geocoding coordinates using the Google Geocoding API

Predictive-Analytics-Konferenz 2015, zweiter Tag

Heute fand der zweite und damit letzte Tag der PRAN statt. Die Vorträge waren wieder sehr interessant.

Christoph Reininger von Runtastic sprach über die Methoden und Werkzeuge der Kunden-Analytik. Hier habe ich mir mehr erwartet. Im Vortrag ging es eher nur um klassische Kundensegmentierung und Customer Life Time Value, beides sind Dinge, die viele andere klassische Firmen machen. Aber wahrscheinlich wollen sie die wirklich innovativen Dinge (falls diese stattfinden) nicht an die große Glocke hängen. Es ist jedenfalls gut zu wissen, daß die von Runtastic direkt erhobenen Daten alle in Österreich in einem Rechenzentrum gespeichert sind und nicht irgendwo in der Cloud. (Leider gilt das nicht für die Google-Analytics-Daten und jene aus dem Werbenetzwerk.)

Marc Bastien von IBM demonstrierte dann IBM Watson Analytics. Das ist schon beeindruckend, wie viel Intelligenz in diesem Cloud-Werkzeug steckt. Aktuell kann es noch keinen Data Scientist ersetzen, aber wenn gerade kein solcher in der Nähe ist, könnte es helfen, in den eigenen Daten interessante Zusammenhänge zu entdecken. Hier kam schon vom Vortragenden die Empfehlung, keine personenbezogenen Daten hochzuladen – selten sind Cloud-Diensteanbieter so ehrlich, zuzugeben, daß es datenschutzrechtliche Bedenken gibt. (Generell wurde die gestrige EuGH-Entscheidung zum Safe-Harbor-Abkommen mehrmals thematisiert. Darüber wird es in nächster Zeit sicher noch einiges zu diskutieren geben.)

Allan Hanbury von der TU Wien zeigte medizinische Anwendungen von Big Data. Spannend für mich und andere im Publikum war die Erkenntnis, daß Ärzte lieber auf Google und Wikipedia nach Symptomen und Therapien suchen als in medizinischer Fachliteratur. Traurig ist auch, daß die Elektronische Gesundheitskarte ELGA zwar eine Zusammenführung der Daten erlaubt, aber Forschung mit ihnen explizit untersagt. Die Konsequenz daraus ist wohl ein opt out. Dafür gibt es im Bereich der Radiologie Fortschritte: Es wurde eine „Suchmaschine“ entwickelt, mit der Ärzte nach Auffälligkeiten in Röntgenbildern und den dazu gehörenden Diagnosen suchen können.

Lisa Neuhofer und Barbara Hachmöller von myr:conn solutions stellten ihr Projekt vor, das Erdölunternehmen hilft, die Ergiebigkeit einer Ölquelle anhand von Probebohrungen zu schätzen. Sie haben dafür einen recht erfolgreichen Modellierungsprozess entwickeln können. Die Anwendung zeigt auch wieder, wie weit das Feld ist, an dem man Analytik einsetzen kann. Bei diesem Thema war auch die Zusammenarbeit mit der Geowissenschaft (welche Gesteinsschichten welche Eigenschaften haben) sehr wichtig.

Nach der Mittagspause sprach Stefan Gindl von der Modul University über Herausforderungen und Trends der Stimmungsanalyse (sentiment analysis, ein Untergebiet von Text Mining). Es ist interessant zu sehen, daß die heutigen Ansätze bereits gut funktionieren, aber bei Themen wie der Erkennung von Sarkasmus und Ironie noch Verbesserungsbedarf besteht. Tatsächlich gibt es aber schon erste Fortschritte in der Forschung auf diesem Gebiet.

Jens Barthelmes von IBM schloß an. Sein Thema war „Social Media Analytics – Alles nur Hype?“. Er erwähnte verschiedene Kritikpunkte an den Datenquellen (die tatsächlich ziemlich chaotisch sind) und den Ergebnissen und erklärte, warum seiner Meinung nach trotzdem ein Wert in dieser Form der Analytik besteht. Das „Geheimnis“ ist, nicht nach der Phase „Monatsbericht über die Wahrnehmung des Unternehmens auf Facebook/Twitter/usw.“ aufzuhören, sondern die Ergebnisse als zusätzlichen Input für die restliche Analytik des Unternehmens anzusehen. Somit lassen sich etwa Absatzprognosemodelle etwas verbessern.

Michael Sedlmair von der Uni Wien sprach über Visualisierung im Big-Data-Zeitalter. Große Datensätze mit eventuell vielen Attributen lassen sich ja mit herkömmlichen Methoden schlecht darstellen. Für dieses Problem hat er einige mögliche Lösungen wie etwa die automatische Vorselektion „interessanter“ Attribute präsentiert. Er gab seinem Bedauern Ausdruck, daß noch kein fertiges Werkzeug existiert, mit dem diese Operationen ohne Programmierung ausgeführt werden könnten.

Wie immer beschloß Prof. Marcus Hudec die Konferenz mit einem seiner berühmten 100-Folien-Vorträge. Die Präsentation war von Anfang bis Ende fesselnd: er erklärte neue Trends wie Deep Learning und beschäftigte sich mit den Auswirkungen großer Datensätze auf die statistischen Eigenschaften von Modellen, die Konfidenzberechnung und innovative Sampling-Verfahren.

Wie immer waren es interessante anderthalb Tage bei der Konferenz. Ich nehme eine Menge Anregungen für meine Projekte in nächster Zeit mit und bin 2016 sicher wieder dabei.

Predictive-Analytics-Konferenz, erster Tag

Die Predictive-Analytics-Konferenz in Wien ist für mich jedes Jahr ein Pflichttermin. Die meisten Vorträge sind spannend und man trifft viele interessante Leute. In Wien ist es ja sonst nicht so einfach, Gesprächpartner mit Data-Mining-Erfahrung zu finden.

Die Keynote war ein sehr interessanter Vortrag von Stefan Stoll (Duale Hochschule Baden-Württemberg), der über disruptive Entwicklungen durch den Einsatz von Software und Analytik gesprochen hat. Er hat dabei wirtschaftliche Zusammenhänge beleuchtet, die mir so bisher unbekannt waren.

Danach stellte Prof. Erich Neuwirth (bei dem ich meine ersten Statistik-Vorlesungen hatte) seine Methode der Wahlhochrechnungen vor. Er gab auch historische Einblicke in die Anfangszeit in den 1970ern und erklärte den Kontrast mit heute: einerseits waren die Modelle damals einfacher, weil nur zwei Großparteien und eine kleine existierten, andererseits geschieht die Berechnung selbst heute in Sekunden auf einem PC, während damals Großrechner eingesetzt werden mußten.

Michael Wurst von IBM stellte die In-Database-Mining-Möglichkeiten der IBM-Datenbankprodukte vor. Es ist jetzt möglich, Data-Mining-Verfahren etwa in Netezza und DB/2 auszuführen, entweder native Implementierungen oder externe R- oder Python-Skripts. Analytik in der Datenbank ist für mich auch sehr interessant, ich habe dazu bereits 2014 bei den Linuxwochen vorgetragen und es wird auch bei den PostgreSQL-Konferenzen in Wien und Hamburg diesen Herbst mein Thema sein.

Ingo Feinerer stellt das von ihm entwickelte R-Paket „tm“ vor. Dieses Paket ist eine Komplettlösung für Text Mining in R. Dieses Aufgabengebiet habe ich bisher nur mit RapidMiner abgedeckt, aber ich werde sicher einmal auch die Gelegenheit haben, mit tm in R zu arbeiten. Spannend ist hierbei die transparente Hadoop-Integration, die ja für größere Textsammlungen notwendig sein kann.

Den Schlußvortrag des Tages hielten Wilfried Grossmann und Stefanie Rinderle-Ma von der Uni Wien. Sie berichteten über ihr Projekt, in einer Lernplattform an der Uni Process Mining zu betreiben. Soweit ich mich erinnern kann, war dies der erste Vortrag zu Business Process Mining bei der Predictive-Analytics-Konferenz. Das Thema ist sicher auch eine Betrachtung  in SCO2T wert. Wenn der Tag nur mehr Stunden hätte…

 

Navigationsmenü für Pentaho-Dashboards

(English)

Wenn man in einem Pentaho-System eine gewisse Anzahl von Dashboards und Berichten implementiert hat, ergibt sich unweigerlich die Frage nach der Navigation zwischen ihnen. Der eleganteste Weg ist ein zentrales Menüsystem, das leicht in alle Dashboards eingebunden werden kann und an einer Stelle verwaltet wird.

Navigation menu

Das Bootstrap-Framework, das heutzutage in Pentaho Community Dashboards verwendet wird, bietet ein sogenanntes Navbar-Objekt, das für diese Zwecke sehr gut geeignet ist.

Navigation menu opened

Für die beste Wartbarkeit erstellt man am besten eine eigene JavaScript-Datei, in der das Menü definiert wird. Diese Datei wird dann in allen Dashboards, die das Menü enthalten sollen, eingebunden.

Die Menüzeile besteht aus einem Titel (im Beispiel „Analytic Backend“), der mit einem Link hinterlegt sein kann, und den einzelnen Menüs. Die Menüs enthalten die Menüpunkte (ebenfalls verlinkt) und Trennlinien.

Mit ein paar simplen JavaScript-Funktionen können alle benötigten Objekte als HTML-Code zusammengesetzt werden. Das fertige Navbar-Objekt wird dann in die Seite eingefügt.

Zuerst definieren wir die notwendigen Funktionen:

/*
    Navigation menu for Pentaho Community Dashboards
*/

//Creates a menu item with a link
function menuLink(url, caption) {
    return('<li><a href="' + url + '">' + caption + '</a></li>');
}

//Creates a separator item
function menuSeparator() {
    return('<li role="separator" class="divider"></li>');
}	

//Creates a drop-down menu with a title.
//If right = true, the menu will be right-aligned (this should be the last menu)
function menu(title, content, right) {

    if (right === undefined) {
        right = false;
    }

    if (right) {
        rightClass = " navbar-right";
    } else {
        rightClass = "";
    }

    menuInit = '<ul class="nav navbar-nav' + rightClass + '"><li class="dropdown">' +
	   '<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button aria-haspopup="true" '+ 'aria-expanded="false">' + title + ' <span class="caret"></span></a>' +
	   '<ul class="dropdown-menu">';
    menuEnd = '</ul></li></ul>';
	
    return(menuInit + content + menuEnd);
}

//Creates the entire navigation bar
function menuNavbar(url, title, content) {
    navbar = '<nav class="navbar navbar-default"><div class="container-fluid"><div class="navbar-header">' +
        '<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">' +
            '<span class="sr-only">Toggle navigation</span><span class="icon-bar"></span></button>' +
        '<a class="navbar-brand" href="' + url + '">' + title + '</a></div>' +
        '<div class="collapse navbar-collapse" id="mainMenu">' +
        content +
        '</div></div></nav>';

    return(navbar);
}

Dann kommt der variable Teil, die Definition der Menüs und der Menüpunkte:

/*
    Customization starts here.
    
    1. Menus
*/

customersMenu = menu("Customers",
    menuLink("/pentaho/api/repos/%3Apublic%3ACustomer%20classes.wcdf/generatedContent", "Customer attributes") +
    menuLink("/pentaho/api/repos/%3Apublic%3ACustomer%20groups.wcdf/generatedContent", "Customer groups") +
    menuSeparator() +
    menuLink("/pentaho/api/repos/%3Apublic%3ATop%20customers.wcdf/generatedContent", "Top customers") +
    menuLink("/pentaho/api/repos/%3Apublic%3ARegistration%20metrics.wcdf/generatedContent", "Registration metrics") +
    menuSeparator() +
    menuLink("/pentaho/api/repos/%3Apublic%3AInactive%20customers.wcdf/generatedContent", "Inactive customers") +
    ""
);

vehiclesMenu = menu("Vehicles",
    menuLink("/pentaho/api/repos/%3Apublic%3AVehicle%20positions.wcdf/generatedContent", "Vehicle positions") +
    menuLink("/pentaho/api/repos/%3Apublic%3AVehicle%20management.wcdf/generatedContent", "Vehicle management") +
    menuSeparator() +
    menuLink("/pentaho/api/repos/%3Apublic%3ADamage%20management.wcdf/generatedContent", "Damage management") +
    menuLink("/pentaho/api/repos/%3Apublic%3AActive%20rides.wcdf/generatedContent", "Active rides") +
    ""
);

// More menus

// Right-aligned menu
technicalMenu = menu("Technical",
    menuLink("https://sco2t.com/", "Sco2t main page") +
    menuLink("https://datascientist.at", "datascientist.at") +
    menuLink("https://rapidminer.com", "RapidMiner") +
    "",
    true
);

Die einzelnen menuLink-Zeilen enthalten die Ziel-URL (ein Dashboard, ein Report, oder auch eine beliebige URL außerhalb des Systems) und den Menü-Text.

Am Ende wird das Menü selbst angelegt.

//Concatenate menus in the desired order. If one is to be right-aligned, it must be the last one.
menuContent = customersMenu + vehiclesMenu + 
              usageFinancialsMenu + appsMenu + technicalMenu
;

//Create the navigation bar with a link, the main title and the whole menu content
navbar = menuNavbar("/pentaho/api/repos/%3Apublic%3AStart%20page.wcdf/generatedContent", "Analytic Backend", menuContent);

//When the document is ready, use JQuery to inject the navigation bar into the page content
$( document ).ready(function() {
    $(".container").before(navbar);
});

Damit haben wir die gewünschte Lösung: ein platzsparendes, zentral gewartetes Menü, das mit minimalem Aufwand in neue und bestehende Dashboards eingebaut werden kann: In der Layout-Ansicht „Add Resource“, type „JavaScript“, „External file“; dann wird die JavaScript-Datei im Dateibrowser ausgewählt oder einfach als Text eingefügt.

Add navigation menu

Navigation Menu for Pentaho Dashboards

When a Pentaho system reaches a certain number of dashboards and reports, the question of navigation between them becomes important. A central menu system an elegant way to solve this problem. It should be easy to include in dashboards and maintained in one place.

Navigation menu

The Bootstrap framework used in Pentaho Community Dashboards, contains a Navbar object that is very suitable for this purpose.

Navigation menu opened

For easy maintenance, a separate JavaScript file is created to define the menu. This file has to be included in all dashboards that need to contain the menu.

The navigation bar contains a title („Analytic Backend“ in the example) that can be linked to a URL, and the menus. The menus contain menu items (also with URLs) and separator lines.

A few simple JavaScript functions build the necessary HTML. The complete Navbar object is then inserted into the page.

First, a few functions:

/*
    Navigation menu for Pentaho Community Dashboards
*/

//Creates a menu item with a link
function menuLink(url, caption) {
    return('<li><a href="' + url + '">' + caption + '</a></li>');
}

//Creates a separator item
function menuSeparator() {
    return('<li role="separator" class="divider"></li>');
}	

//Creates a drop-down menu with a title.
//If right = true, the menu will be right-aligned (this should be the last menu)
function menu(title, content, right) {

    if (right === undefined) {
        right = false;
    }

    if (right) {
        rightClass = " navbar-right";
    } else {
        rightClass = "";
    }

    menuInit = '<ul class="nav navbar-nav' + rightClass + '"><li class="dropdown">' +
	   '<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button aria-haspopup="true" '+ 'aria-expanded="false">' + title + ' <span class="caret"></span></a>' +
	   '<ul class="dropdown-menu">';
    menuEnd = '</ul></li></ul>';
	
    return(menuInit + content + menuEnd);
}

//Creates the entire navigation bar
function menuNavbar(url, title, content) {
    navbar = '<nav class="navbar navbar-default"><div class="container-fluid"><div class="navbar-header">' +
        '<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">' +
            '<span class="sr-only">Toggle navigation</span><span class="icon-bar"></span></button>' +
        '<a class="navbar-brand" href="' + url + '">' + title + '</a></div>' +
        '<div class="collapse navbar-collapse" id="mainMenu">' +
        content +
        '</div></div></nav>';

    return(navbar);
}

Then the variable part where the menus and menu items get defined:

/*
    Customization starts here.
    
    1. Menus
*/

customersMenu = menu("Customers",
    menuLink("/pentaho/api/repos/%3Apublic%3ACustomer%20classes.wcdf/generatedContent", "Customer attributes") +
    menuLink("/pentaho/api/repos/%3Apublic%3ACustomer%20groups.wcdf/generatedContent", "Customer groups") +
    menuSeparator() +
    menuLink("/pentaho/api/repos/%3Apublic%3ATop%20customers.wcdf/generatedContent", "Top customers") +
    menuLink("/pentaho/api/repos/%3Apublic%3ARegistration%20metrics.wcdf/generatedContent", "Registration metrics") +
    menuSeparator() +
    menuLink("/pentaho/api/repos/%3Apublic%3AInactive%20customers.wcdf/generatedContent", "Inactive customers") +
    ""
);

vehiclesMenu = menu("Vehicles",
    menuLink("/pentaho/api/repos/%3Apublic%3AVehicle%20positions.wcdf/generatedContent", "Vehicle positions") +
    menuLink("/pentaho/api/repos/%3Apublic%3AVehicle%20management.wcdf/generatedContent", "Vehicle management") +
    menuSeparator() +
    menuLink("/pentaho/api/repos/%3Apublic%3ADamage%20management.wcdf/generatedContent", "Damage management") +
    menuLink("/pentaho/api/repos/%3Apublic%3AActive%20rides.wcdf/generatedContent", "Active rides") +
    ""
);

// More menus

// Right-aligned menu
technicalMenu = menu("Technical",
    menuLink("https://sco2t.com/", "Sco2t main page") +
    menuLink("https://datascientist.at", "datascientist.at") +
    menuLink("https://rapidminer.com", "RapidMiner") +
    "",
    true
);

All menuLink lines contain a target address (a dashboard or report in the Pentaho system or an external URL) and the menu text.

After the menus, the navigation bar itself is created.

//Concatenate menus in the desired order. If one is to be right-aligned, it must be the last one.
menuContent = customersMenu + vehiclesMenu + 
              usageFinancialsMenu + appsMenu + technicalMenu
;

//Create the navigation bar with a link, the main title and the whole menu content
navbar = menuNavbar("/pentaho/api/repos/%3Apublic%3AStart%20page.wcdf/generatedContent", "Analytic Backend", menuContent);

//When the document is ready, use JQuery to inject the navigation bar into the page content
$( document ).ready(function() {
    $(".container").before(navbar);
});

This gives us the desired solution: a centrally maintained menu that can be easily built into dashboards.

In the Layout view click „Add Resource“ with the type JavaScript and External file. Select the file in the file browser or enter the file path.

Add navigation menu

Data Science with PostgreSQL

… ist der Titel des Vortrags, den ich bei der Europäischen PostgreSQL-Konferenz eingereicht habe. Die Konferenz findet vom 27. bis 30. Oktober in Wien statt. Der Vortrag wurde vom Programmkomitee (alles große Namen in der PostgreSQL-Welt) angenommen.

Im Vortrag geht es um die verschiedenen Aufgaben im Bereich Data Science und wie PostgreSQL sie abdeckt:

  • Datenintegration und ETL: Foreign Data Wrappers für den Zugriff auf andere Datenbanken, Dateien, NoSQL- und Hadoop-Datenquellen; prozedurale Sprachen für den Zugriff auf Web-APIs und andere Systeme
  • Preprocessing: Standard-SQL und fortgeschrittene Methoden
  • Data understanding: Deskriptive Statistiken mit SQL, Visualisierung mit PL/R
  • Predictive analytics: Data Mining mit PL/R und PL/Python, Modellanwendung in der Datenbank

Ich freue mich sehr, vor dem hochkarätigen Publikum einer renommierten Konferenz über diese Themen sprechen zu können.

Über die Schwierigkeit, ein analytisches Unternehmen zu sein

Im immer sehr interessanten „Stats with Cats“-Blog erschien vor kurzem der Beitrag „It’s Hard to be a Data Driven Organization„. Ich kann ihn sowohl Managern als auch anderen Data Scientists sehr empfehlen.

Der Autor spricht viele Themen an, die ich gerade in Österreich auch schon gesehen habe: Insbesondere das Nicht-Glauben an die Aussagekraft von Daten und statistischen Methoden und die Überzeugung, die eigene Erfahrung würde zu besseren intuitiven Entscheidungen führen als eine datengestützte Vorgehensweise.

Auch als Data Scientist muß man sich manchmal dem Management stellen und die Ergebnisse der eigenen Arbeit erklären. In diesem Kontext trifft man dann eventuell auf Gegenmeinungen von Leuten, die das politische Spiel im Unternehmen besser beherrschen (weil es ihre Hauptbeschäftigung ist?). Es kann schwierig sein, dem genug entgegenzusetzen, weil man in der Organisation doch eine niedrigere Rolle einnimmt (trotz der häufig besseren Ausbildung und einer vergleichbaren Gehaltsstufe).

Wenn ein Unternehmen sich als daten-gesteuert ansehen will, ist es die Verantwortung der Geschäftsleitung, durch die politischen Argumente hindurchzusehen und die Arbeit der Data Scientists entsprechend zu bewerten.

Data Science und Mathematik

Auf Heise Developer erschien heute ein Artikel „Data Scientist – ein neues Berufsbild für die Big-Data-Welt„. Relevante Aspekte wie Methoden, Werkzeuge und Ausbildungsmöglichkeiten werden darin thematisiert.

Mit einer Aussage bin ich jedoch nicht ganz einverstanden: der Formel „Data Science = Mathematik + Informatik + Domänenwissen“.

Informatik (wenn auch nur Teile davon) kann ich absolut bestätigen. Das Wissen um Datenbanksysteme, Systemarchitekturen, Programmiersprachen, Textkodierungssysteme usw. ist für uns Data Scientists ohne Frage essenziell.

Domänenwissen über alle möglichen Themen kann man als Freelancer gar nicht haben. Es zählt vielmehr die Fähigkeit (und der Wille), sich mit offenen Augen durch die Welt zu bewegen und sich fürs aktuelle Projekt tatsächlich in die Problemfelder der Aufgabe einarbeiten zu können.

Was mich aber in der „Formel“ am meisten stört, ist die Betonung von Mathematik. Statistik ist nur ein sehr kleiner Ausschnitt der Mathematik, vielleicht nicht einmal ein besonders typischer. Und es ist die Statistik, die als Grundlage von Data Mining und Predictive Analytics gilt. Andere Teile von Mathematik (Graphentheorie etwa) sind sicherlich nützlich für abgegrenzte Teilaufgaben (also durchaus für eine Spezialisierung geeignet, wenn man Interesse daran hat), aber im Zweifelsfall sollte man sich lieber intensiv mit Statistik beschäftigen als den gleichen Zeitaufwand auf allgemeine Mathematik aufzuteilen.

Sicher kann es nützlich sein, mehr Mathematik zu wissen. Aber genauso könnte man von Wissen in den Bereichen Betriebs- und Volkswirtschaft, Linguistik oder Physik profitieren. Nach meiner Erfahrung ist Vielseitigkeit ganz wichtig.

Viele Data-Mining-Methoden und Vorgehensweisen lassen sich nicht mehr vollständig mit Mathematik beschreiben. Wir wissen aber, wie wir die Ergebnisse trotzdem in der Praxis validieren und einsetzen können.

Die Unterscheidung zwischen Statistik und Mathematik sieht man auch daran, daß in fast jedem Text über Data Science die Sprachen R (spezialisiert auf Statistik) und Python (mit der Erweiterung um statistische Funktionen), aber selten die klassischen mathematischen Sprachen wie Octave/Matlab erwähnt werden. (Das schließt natürlich nicht aus, daß jemand diese Werkzeuge kennt und erfolgreich nutzt.)

Data Science ist heute so weit fortgeschritten, daß High-Level-Werkzeuge wie RapidMiner, Pentaho und Datameer fast alle Aspekte ohne Programmierung und vor allem ohne mathematische Formeln abdecken. Um mit ihnen erfolgreich predictive analytics zu betreiben, sind gewisse statistische Kenntnisse wichtig. Für Außenstehende mag das von Mathematik nicht unterscheidbar sein, aber Tatsache ist, daß man weitgehend ohne Formeln und mathematische Beweise verstehen kann, wie die Verfahren arbeiten und wo ihre Vor- und Nachteile liegen.

In der RapidMiner-Schulung kommen jedenfalls kaum Formeln vor, trotzdem können die Teilnehmer danach komplexe Data-Mining-Prozesse auf ihre Daten anwenden und aus ihnen erfolgreich Vorhersagen generieren. Sie kennen die Anwendbarkeit und die Vor- und Nachteile von einzelnen Algorithmen (ohne sie mathematisch Schritt für Schritt erklärt zu bekommen) und können sie in der Praxis einsetzen – und darum geht es in der Data Science.

Vielleicht ist der Science-Aspekt im Artikel auch ein bißchen zu kurz gekommen. In der Wissenschaft geht es auch darum, skeptisch zu bleiben und die Ergebnisse am besten nochmal unabhängig zu überprüfen. (Da hilft wieder speziell die Statistik.)

Die Ausbildung ist natürlich ein Thema. Ich bin wirklich gespannt, ob die neuen und kommenden Data-Science-Ausbildungsmöglichkeiten auch in der Praxis verwendbar sind, oder ob vielleicht doch eher die Erfahrung nach wie vor mehr zählt. Jene, die aktuell schon als Data Scientist arbeiten, so wie ich, mußten das ja auch irgendwo lernen und dabei vielleicht Umwege gehen. Unsere Begeisterung für Datenanalyse hat uns (vielleicht auch unbewußt) in diese Richtung gesteuert und dazu geführt, uns in den notwendigen Themen zu vertiefen. Daraus folgt für mich, daß auch in Zukunft Leute eine Chance haben werden, auch wenn sie nicht die konkrete (Data Science genannte) Ausbildung gemacht haben.

Pentaho Community Dashboards: Button-Komponente und Parameterübergabe

(English version)

Manchmal ist es am einfachsten, simple „Webanwendungen“ zur Dateneingabe mit den Pentaho-Dashboards zu entwickeln.  (RapidMiner hat vor einiger Zeit ähnliche Funktionen in den Server eingebaut, um statt nur Dashboards echte Webapps entwickeln zu können.)

Eine wichtige Rolle spielt hierbei die Button-Komponente. Mit ihr kann man die Eingabe abschießen und z. B. mit einer Kettle-Transformation die Daten verarbeiten.

Normalerweise ist das Zusammenspiel zwischen Dashboard-Parametern, Komponenten-Parametern und Datenquellen-Parametern ziemlich simpel und logisch, aber in dieser Konstellation kann es kompliziert werden, insbesondere wenn die Dashboard-Parameter auch noch anders heißen als die Parameter der Transformation.

In diesem Beispiel legen wir die Simple Parameters Param1, Param2 und Parameter3 im Dashboard an, und in der PDI-Transformation die Parameter Param1, Param2 und Param3. Sie bekommen entsprechende Default-Werte, damit wir sie im Output unterscheiden können. Parameter3 ist im Dashboard absichtlich anders benannt.

Wir legen eine Datenquelle vom Typ „kettle over kettleTransFromFile“ an und wählen die Transformationsdatei aus. Der Name eines Schrittes der Transformation wird unter „Kettle Step name“ festgelegt. Unter Variables geben wir die Namen der in der Transformation definierten Parameter (also Param1, Param2, Param3) ohne Value an (also bleiben alle Value-Felder leer). Unter Parameters wiederholen wir diese drei Namen, und als Value geben wir die gleichen Namen nochmal ein. (Also: Param1/Param1, Param2/Param2, Param3/Param3.)

Wichtig ist jetzt das korrekte Einstellen der Button-Komponente. Unter Advanced Properties wird zuerst „Action Datasource“ auf den Namen der Datenquelle gesetzt, und dann die Action Parameters eingegeben. Hier geben wir unter Arg die Parameternamen, die die Datenquelle erwartet, ein, also Param1, Param2 und Param3. Als Value aber die Namen der Dashboard-Parameter, also Param1, Param2 und Parameter3. Damit haben wir die Verbindung vom anders benannten Parameter zur Transformation geschaffen.

Pentaho Community Dashboards: The Button component and passing parameters

Sometimes, the easiest way to create a simple „data input web application“ is a Pentaho Dashboard. (RapidMiner put similar functionality into the Server to enable the development of web apps instead of only dashboards.)

The Button component has an important role when building applications: It is an easy way to take the input and call a Kettle transformation (for example) to process the data.

Usually, the interaction between Dashboard parameters, Component parameters and Datasource parameters is quite simple and logical. However, in this situation it can became more complicated, especially if the parameters in the dashboard and in the transformation have different names.

In this example, we create Simple Parameters called Param1, Param2 and Parameter3 in the dashboard, and Param1, Param2, Param3 in the PDI transformation. We assign them different default values so we can distinguish them in the output. Parameter3 is intentionally called differently in the dashboard.

We create the datasource of type „kettle over kettleTransFromFile“ and select the transformation file on the server. The name of one step in the transformation must be entered in „Kettle Step name“. In the Variables input, we enter the transformation parameter names Param1, Param2, Param3 without entering values. (The Value fields must stay empty.) In the Parameters, we enter the same names but this time also in the value fields: Param1/Param1, Param2/Param2, Param3/Param3.

Now it’s important to set up the Button component correctly. In the Advanced Properties, we set the Action Datasource to be the name of the data source, and then enter the Action Parameters. Here, the Arg names are the data source parameter names (Param1, Param2, Param3), and the Value names are the Dashboard parameter names: Param1, Param2 and Parameter3. This is how the link to differently named dashboard parameters is done.

RapidMiner-Trainings in Wien

Die RapidMiner-Trainings in Dortmund erfreuen sich großer Beliebtheit und sind eine sehr gute Einführung ins Data Mining.

Leider ist Dortmund von Wien und Umgebung ziemlich weit entfernt. An- und Abreise verschlingen jeweils mindestens einen halben Tag, und dann kommen noch Kosten für die zusätzlichen Übernachtungen dazu.

Deswegen halte ich erstmals in Wien die Trainings „RapidMiner Basics“ Teil 1 und 2 ab.

21.-22. Sept. 2015: Teil 1

23.-24. Sept. 2015: Teil 2

Am Vormittag des 25. September besteht die Möglichkeit, die Zertifizierung zum RapidMiner Analyst durchzuführen.

Veranstaltungsort: Data Technology GmbH., Amalienstr. 65, 1130 Wien (5. Stock), erreichbar mit der U4 (Ober St. Veit, Aufgang Preindlsteg)

Die Sprache ist von den Teilnehmern abhängig – wenn alle Deutsch können, ist das Training auf Deutsch, sonst auf Englisch.

Erfahrungen mit PostgreSQL und dem MySQL-Foreign-Data-Wrapper

(English version)

Foreign Data Wrapper in PostgreSQL sind eine sehr elegante Möglichkeit, andere Datenbanken und andere Datenquellen wie normale Tabellen anzusprechen.

Ich habe den MySQL-FDW eingehend getestet und möchte die Erfahrungen teilen.

Generell lassen sich auch Tabellen anlegen, die aus verschiedenen Gründen danach nicht vollständig in PostgreSQL nutzbar sind. Z. B. verursachen die berüchtigten ungültigen Timestamps von MySQL (0000-00-00 00:00) Lesefehler beim Abfragen der betreffenden Zeilen. Einige spezielle Datentypen, die in MySQL und PostgreSQL gleich heißen, sind trotzdem nicht lesbar, z. B. der Datentyp POINT.

Abgesehen von diesen Problemen geht das Lesen üblicherweise problemlos. In einigen Konstruktionen (z. B. wenn Werte verglichen werden sollen) versucht das Foreign-Wrapper-Modul, PostgreSQL-Sprachelemente wie ::TYP (statt CAST(… AS TYP)) an die fremde Datenbank zu senden, was einen Fehler ergibt.

Die Lösung ist, die betreffenden Werte selbst mit der standardkonformen CAST-Syntax umzuwandeln.

INSERTs und UPDATEs sind ein anderes Thema. Hat man sich mühsam eine Abfragesyntax erarbeitet, die von beiden Datenbanken akzeptiert wird, stürzen PostgreSQL-Backends sporadisch und nicht reproduzierbar ab, sodaß das Datenbanksystem sich automatisch neu startet und dabei alle bestehenden Verbindungen abreißt. Leider wird dabei nichts geloggt, sodaß ich den Grund noch nicht herausgefunden habe. Derzeit kann ich diese Funktionalität jedenfalls nicht verwenden.

Die Anwendung wäre, Änderungen an Datensätzen mit Hilfe von Triggern direkt in der anderen Datenbank nachzuziehen. So läuft weiterhin ein periodischer Pentaho-Data-Integration-Prozesses.

Update 2016-03-06: Mit aktuellen Versionen des Foreign Data Wrappers treten keine Abstürze mehr auf. INSERTs und UPDATEs sind jetzt stabil. Somit können datenbankübergreifende Trigger-Funktionen geschrieben werden, um Werte in der MySQL-Datenbank zu aktualisieren, wenn sich etwas in PostgreSQL ändert.

Practical experience with PostgreSQL and the MySQL Foreign Data Wrapper

Foreign Data Wrappers in PostgreSQL are a very elegant way to access other datasources and use them like normal database tables.

I’d like to share the results of my tests of the MySQL FDW.

It is possible to create tables that are not fully usable in PostgreSQL afterwards, for different reasons. For example, the infamous invalid MySQL timestamp (0000-00-00 00:00) makes the record unreadable. There are data types like POINT that are called the same in MySQL and PostgreSQL but they are different enough not to be readable, as well.

Aside from these problems, reading data usually works without issues. In some queries (e. g. when comparing values not having the same data type), the foreign data wrapper module tries to use PostgreSQL-specific syntax like ::TYPE instead of the standard CAST(… AS TYPE) in the foreign database, returning errors.

The solution for this problem is to explicitly cast the values with the standard CAST syntax.

INSERT and UPDATE don’t work quite as well. After finding a query syntax that is accepted by both database systems, PostgreSQL backends start crashing sporadically and in a non-reproducible way. The database server restarts automatically but kills all existing connections. Nothing is logged, so I couldn’t find the reason yet. Therefore, I can’t use this functionality yet.

I wanted to use write access to the MySQL tables to quickly enter changes in the foreign database from a PostgreSQL trigger function. As this doesn’t work, a Pentaho Data Integration process is started periodically for the same purpose.

Update 2016-03-06: Current versions of the Foreign Data Wrapper don’t crash the PostgreSQL backend anymore. INSERT and UPDATE on foreign tables is stable now. Therefore it is possible to write trigger functions that update values in the MySQL database automatically when a value changes in PostgreSQL.