Schlagwort-Archive: CRS

GIS in RapidMiner (3) – Distanz, Fläche

(English version)

Nach der Einführung und dem Datenimport geht es nun an echte geographische Berechnungen.

Eine der wichtigsten Informationen ist die Distanz von Objekten voneinander oder einem Referenzpunkt. Auch Data-Mining-Verfahren wie k Nearest Neighbors berechnen Distanzen.

Zwei verschiedene Methoden stehen uns zur Verfügung, um Distanzen zwischen zwei Punkten auf der Erdoberfläche zu berechnen: Entweder können wir die Punkte als zweidimensionale Geometrie mit X- und Y-Koordinaten auffassen (die Berechnung ist dann ganz einfach), oder die Distanz auf der Oberfläche des Ellipsoids der Erde ausrechnen. Die zweite Vorgehensweise ist mathematisch natürlich deutlich aufwändiger, liefert aber bei größeren Distanzen (z. B. Orte auf verschiedenen Kontinenten) genauere Daten. Deswegen wird in vielen Anwendungen, die nur Objekte in einem eingeschränkten Gebiet enthalten, auf die erste Methode zurückgegriffen.

Transformation in eine andere Projektion (Koordinatensystem)

Wie in der Einführung ausgeführt müssen wir die Geometrien manchmal in andere Projektionen transformieren, um mit sinnvollen Einheiten wie Meter rechnen zu können. Die Methoden dafür sind in GeoScript enthalten und ihre Anwendung ist recht einfach:


import geoscript.proj.*;

fromProj = new Projection("epsg:4326");
toProj = new Projection("epsg:3035");

projectedGeom = Projection.transform(geom, fromProj, toProj);

Ein fertig anwendbarer RapidMiner-Prozess befindet sich hier. Er braucht drei Parameter, die als Makros im Prozesskontext definiert sind und beim Aufruf angegeben werden können:

GEOM_ATT: Name des Attributs, das die zu transformierende Geometrie (im WKT-Format) enthält

FROM_PROJECTION, TO_PROJECTION: Die EPSG-Nummern der Quell- und Zielprojektion.

Damit lassen sich die Koordinaten leicht von einem allgemeinen Koordinatensystem wie WGS84 (Längen- und Breitengrad, EPSG:4326) in  ein gebräuchlicheres wie z. B. ETRS89/Austria Lambert (EPSG:3416) konvertieren. Das werden wir im nächsten Beispielprozess anwenden, um Distanzen zwischen Objekten in Wien, aber auch Fläche und Umfang von Bezirken zu berechnen.

Berechnung von Distanz, Fläche und Umfang

GeoScript enthält dafür einfach anzuwendende Funktionen:

flaeche = geom.getArea();
umfang = geom.getLength();
//Für die Distanz brauchen wir eine zweite Geometrie
distanz = geom1.distance(geom2);

Sobald man das Geometrie-Objekt in einer richtigen Projektion hat, sind die Berechnungen ganz simpel.

getArea() liefert die Fläche eines Polygons oder einer Polygongruppe (Multipolygon); getLength() die Länge einer Linie oder den Umfang eines Polygons, jeweils in den Einheiten der aktuellen Projektion.

Für die Distanz brauchen wir ein zweites Geometrie-Objekt, das nicht unbedingt ein Punkt sein muß – es ist auch möglich, die Distanz zwischen Linien und Flächen zu berechnen.

Der Beispielprozess holt zwei Datensätze vom Open-Data-Portal der Stadt Wien: Museen (Punkte) und Bezirksgrenzen (Polygone). Beide werden aus Längen- und Breitengrad-Koordinaten in eine in Österreich gebräuchliche, meter-basierte Projektion transformiert. Mit getArea() und getLength() werden Fläche und Umfang der Bezirke berechnet. Da der Original-Datensatz diese Information bereits enthält, können wir leicht prüfen, ob die Berechnungen korrekt sind. (Kleine Unterschiede resultieren wohl aus der Rundung der Koordinaten für den CSV-Export.)

Dann wird noch der erste Bezirk selektiert und mit dem Museums-Datensatz zusammengeführt. In diesem kombinierten Datensatz haben wir nun zwei Geometrien, wir können also die Entfernung des Museums von der Innenstadt berechnen. Punkte, die im Polygon des ersten Bezirks liegen, haben die Distanz 0.

Berechnung von Distanzen auf der Erdoberfläche

Die zweite, genauere, aber langsamere Berechnungsmethode kann auch recht einfach angewendet werden. Hierfür importieren wir aus der GeoTools-Library, auf die GeoScript aufbaut, die Klasse GeodeticCalculator. (Die Bibliotheken, die wir in der Einführung für GeoScript übernommen haben, reichen dafür aus, wir müssen also nichts Neues installieren.)

Für diese Methode brauchen wir die Längen- und Breitengrade von zwei Punkten, also WGS84-Koordinaten. (Es gäbe auch die Möglichkeit, transformierte Koordinaten zu verwenden, dafür müßten wir dem GeodeticCalculator auch das Koordinatensystem übergeben.)

import org.geotools.referencing.GeodeticCalculator;

gcalc = new GeodeticCalculator();

gcalc.setStartingGeographicPoint(lon1, lat1);
gcalc.setDestinationGeographicPoint(lon2, lat2);

distance = gcalc.getOrthodromicDistance();

Hier ist es wichtig, die Reihenfolge der Koordinatenangaben zu beachten. In anderen Bereichen sind wir gewohnt, X- und Y-Koordinaten in dieser Reihenfolge anzugeben, GIS-Systeme arbeiten jedoch manchmal mit der Reihenfolge Y, X.

Der Beispielprozess enthält die Koordinatenpaare einiger Hauptstädte auf verschiedenen Kontinenten. Mit einem Cartesian Product werden alle Städte mit allen anderen verknüpft und jeweils die Distanzen in km berechnet. (Die berechneten Distanzen habe ich mit PostGIS verifiziert; die Ergebnisse sind sehr genau.) Für diese Distanzen würde eine Berechnung mit der Geometrie-Methode schon sehr große Ungenauigkeiten liefern, hier empfiehlt es sich also sehr, die GeodeticCalculator-Methode zu nutzen.

GIS in RapidMiner (3) – Distance and Area

After the introduction and data import we can start to perform actual geographic calculations.

One of the most important measures is the distance of objects from each other or from a reference point. Distances are also calculated by data mining operations like k Nearest Neighbors.

Two different methods of calculating distances between points on the surface of Earth exist: Either we can pretend that the points are in a two-dimensional geometry with X and Y coordinates (which makes the distance calculation very easy), or we use the actual Earth ellipsoid for the calculation. The second method is very computing-intensive, but it returns more precise results when used on larger distances (e. g. places on different continents). For many operations acting on a limited area, the first method is used.

Transformation to another projection (coordinate system)

As described in the introduction, we often need to transform geometries to different projections so we can use units like meters. Coordinate system transformation is also available in GeoScript, and using it is quite easy.

import geoscript.proj.*;

//Source and destination projections
fromProj = new Projection("epsg:4326");
toProj = new Projection("epsg:3035");

projectedGeom = Projection.transform(geom, fromProj, toProj);

Here is a readily usable RapidMiner process. It takes three parameters that can be specified as macros in the process context. You can overwrite them when calling the process in the Execute Process operator.

GEOM_ATT: Name of the attribute that contains the geometry to be transformed (in WKT format)

FROM_PROJECTION, TO_PROJECTION: The EPSG numbers of the source and target projections

With this process, you can easily transform geometries from a common coordinate system like WGS84 (Latitude and Longitude, EPSG:4326) to a special one, for example ETRS89/Austria Lambert (EPSG:3416). We will use this in the example process for calculating distances between objects in Vienna, Austria and also determine the area and circumference of Vienna’s 23 districts.

Calculating distance, area and circumference

GeoScript contains easy to use functions:

area = geom.getArea();
circumference = geom.getLength();
//We need a second geometry for calculating distance
distance = geom1.distance(geom2);

After having transformed the geometry object into a matching projection, the calculations are really simple.

getArea() returns the area of a polygon or a group of polygons (Multipolygon); getLength() gives the length of a line or the circumference of a polygon in the units of the used projection.

For calculating the distance, a second geometry object is required. It doesn’t need to be a point: it’s also possible to calculate the distance between lines and areas.

The example process fetches two data sets from the Vienna Open Data Portal: Museums (points) and district borders (polygons). The process transforms then from latitude and longitude coordinates into a projection used in Austria. One script calculates the area and circumference of the districts using getArea() and getLength(). The original data set already contains these measures so we can easily check that they’re correct. (Small differences are the consequence of rounding the coordinates for CSV export.)

After that, the first district (Inner City) is selected and joined with the museum data set. The combined data set contains two geometries in a common projection, so we can calculate the distance between the museum and the Inner City. Points in the first district have a distance of 0.

Calculating distances on the surface of Earth

The second calculation method (more precise but slower) can also be used quite easily. For this, we import the class GeodeticCalculator from the GeoTools library, a base component of GeoScript. (The GeoScript libraries installed in the introduction are enough for this, we don’t need to set up more stuff.)

For using this method, we need latitude and longitudes of two points, in other words WGS84 coordinates. (It would be possible to use transformed coordinates by specifying a coordinate system in the GeodeticCalculator.)

import org.geotools.referencing.GeodeticCalculator;

gcalc = new GeodeticCalculator();

gcalc.setStartingGeographicPoint(lon1, lat1);
gcalc.setDestinationGeographicPoint(lon2, lat2);

distance = gcalc.getOrthodromicDistance();

Be careful when specifying the coordinates. We usually write X and Y coordinates in this order but GIS tools often use the order Y, X.

The example process contains coordinate pairs of a few capital cities lying on different continents. We build a Cartesian Product of all cities and calculate their distances in kilometers. (The distances were verified with PostGIS, they are very precise.) On these distances, using the geometry method would result in huge inaccuracies, so it’s really better to use the GeodeticCalculator method there.

GIS in RapidMiner (1)

(English version)

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

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