Direkt zum Hauptbereich

Python: Lambdas, Comprehensions

Einführung

Python ist quasi der de facto Standard, um Programme im Bereich KI und Data Science zu schreiben. In meinem Blogartikel "Künstliche Intelligenz - Python erlernen" habe ich für alle die Kenntnisse in einer anderen objektorientierten Sprache haben, versucht anhand objektorientierter Konzepte einen Python Schnellkurs zu geben. Python hat aber auch viele spezifische Eigenschaften, wie es mit Daten und Datenstrukturen umgeht. Daher fand ich es ein Muss einen Artikel zu diesen Thema zu verfassen. Das Resultat ist im Artikel "Künstliche Intelligenz:Python - Listen, Tupeln, Reguläre Ausdrücke und mehr" zu finden. Mit diesen zwei Artikeln habe ich quasi die objektorientierten Konzepte der Sprache abgehandelt (natürlich nicht vertieft). Wer sich dann intensiv mit Python auseinandersetzt muss sich grundlegend noch Kenntnisse aneignen über wichtige Details, die beispielsweise bei der Klassen-Mehrfachvererbung in Python auftauchen. 

Dieser Artikel hier, führt zwei moderne Konzepte ein, die in einigen anderen objektorientierten Sprachen teilweise auch realisiert sind, aber eigentlich mit den Paradigmen von Objektorientierung nichts zu tun haben. Ich spreche von Lambda Ausdrücken und von einem sehr Python-spezifischen, aber äusserst nützlichen Konzept, nämlich den Comprehensions, wo quasi die Vorschrift wie eine Datenstruktur zu konstruieren ist, in einer sehr kompakten Form angegeben wird. 

Lambda Ausdrücke halten seit längerem Einzug in die Welt der objektorientierten Sprache und kommen ursprünglich aus funktionalen Programmiersprachen wie beispielsweise LISP. Lambda Ausdrücke sind anonymisierte Funktionen, die beliebig viele Anzahl von Parametern enthalten können. Im Allgemeinen werden sie durch Verweise angesprochen. Lambda Ausdrücke wurden vom Python Erfinder van Rossum nur widerwillig in die Sprache aufgenommen, weil identische Resultate mit den Comprehensions auf einfachere Weise erzielt werden können.

Lambdas

Ein Lambda Ausdruck hat folgende Syntax:

Lambda <Argumenten Liste> : <Ausdruck>

In folgenden Beispielen wird von Lambda Ausdrücken Gebrauch gemacht. Allerdings ist anzumerken, dass wenn die Beispiele in PyCharm CE ausgeführt werden, teilweise Warnmeldungen kommen. Das weil eben die Lambda Ausdrücke nur widerwillig in Python integriert wurden.

x = lambda a : a + 10
print(x(5)) 
# 15
x = lambda a, b : a * b
print(x(5, 6))
# 30
def evaluator(f):
    return lambda x, y: f(x,y)


def multiplicate(x, y):
    return x * y


def add(x, y):
    return x + y


evaluate = evaluator(multiplicate)
print(evaluate(2, 5))
# 10
evaluate = evaluator(add)
print(evaluate(2, 5))
# 7
Oben deutlich ersichtlich, wie sich Lambda's für Transformationen eignen. Unten ein geläufigeres Beispiel für die Verwendung von Lambdas als anonyme Funktion.

def apply(f, list1, list2):
    result = []
    if len(list1) != len(list2):
        return result
    i = 0
    for el1 in list1:
        result.append(f(el1, list2[i]))
        i += 1
    return result


list1 = [1, 2, 3, 4, 5, 6, 7]
list2 = [1, 3, 4, 5, 8, 9, 10]
applier = apply((lambda x, y: x+y), list1, list2)
print(applier)

applier = apply((lambda x, y: x*y), list1, list2)
print(applier)
# [2, 5, 7, 9, 13, 15, 17]
# [1, 6, 12, 20, 40, 54, 70]

Map

Eine Map definiert eine Abbildung von einem iterierbaren Objekt auf ein anderes. Mit einer Map, kann obiges Beispiel wesentlich kompakter geschrieben werden:

adder = list(map(lambda x, y: x+y, list1, list2))
print(adder)

Selbst mit bestehenden Funktionen von Python funktioniert map:

print(list(map(len, ["Eins", "Zwei", "Drei", "Sechs"])))
# [4, 4, 4, 5]

Filter

Mit Filter werden Daten gefiltert, das heisst Bedingungen legen fest, ob das iterierbare Objekt im Resultat landet oder nicht. Auch hier einige Beispiele:


import math as m

def prim(ls):
    while ls[0] < 2:
        del ls[0]
    newrange = range(2, int(m.sqrt(max(ls))+1))
    n = 0
    for i in newrange:
        while ls[n] <= i:
            n = n+1
        filterit = filter(lambda x: x % i > 0, ls[n:len(ls)])
        templs = list(ls[0:n])
        templs.extend(list(filterit))
        ls = templs
        n = ls[0]
    return ls

list1 = range(150)
print(prim(list1))

Obiges Beispiel verwendet einen filter-Ausdruck und zwar werden alle Elemente in einer Subliste geprüft, ob sie Modulo i dividierbar sind. Die gesamte Funktion hat zum Zweck, alle Primzahlen in einem bestimmten Range zurückzugeben.

Filter akzeptieren prinzipiell alle Funktionen, die für ein iterables Objekt eine Boolschen Wert zurückgeben:


def findEvens(x):
    if x % 2 == 0:
        return True
    return False


list2 = list(range(21))
print(list(filter(findEvens, list2)))
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

Reduce

Während Map eine Abbildung auf eine gleichmächtige Menge vornimmt und Filter spezifische Elemente selektiert und eine reduzierte Liste zurückgibt, gibt Reduce nur ein Element zurück. Reduce nimmt eine Funktion entgegen und berechnet einen spezifischen Wert aus den Elementen des iterierbaren Objekts. Dabei wird die Funktion zuerst auf die ersten beiden Werte angewendet und dann das Resultat auf den dritten Wert und das neue Resultat auf den vierten Wert usf. Damit Reduce verwendet werden kann, muss das Modul functools importiert werden.

Nachfolgend ein Beispiel zur Verwendung von Reduce:


from functools import reduce


def add(x, y):
    return x + y


print(reduce(add, range(0, 11)))
# 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = 55

# oder als Einzeiler
print(reduce(lambda x,y: x+y, range(0, 11)))

Comprehensions

Comprehensions sind abstrakte Listen. Dabei wird in eckigen Klammern angegeben wie die Liste algorithmisch konstruiert werden soll. Dank der Mächtigkeit von Comprehensions kann auf die Verwendung von Lambda Ausdrücken verzichtet werden. Auch die Funktionen Map, Reduce und Filter können sehr einfach durch Comprehensions ersetzt werden.

Die allgemeine Syntax ist folgende:

[Ausdruck von 1 oder mehreren For-Anweisungen und eventuell If-Bedingungen]

Obschon meines Erachtens gerade die Reduce Funktion nicht so sehr trivial mit List Comprehensions ersetzt werden kann, scheint es offenbar möglich zu sein. Obiges Beispiel einer Addition von den Elementen einer Liste ist jedenfalls ohne die Verwendung der Funktion sum nicht möglich.

Auch hier einige Beispiel dazu:

Heraussuchen aller Pythagoräischen Zahlentripel:

print([(x, y, z) for x in range(1, 27) for y in range(x, 27) for z in range(y, 27) if x*x + y*y == z*z])
# [(3, 4, 5), (5, 12, 13), (6, 8, 10), (7, 24, 25), (8, 15, 17), (9, 12, 15), (10, 24, 26), (12, 16, 20), (15, 20, 25)]

Map ist ganz einfach zu realisieren, wie folgendes Beispiel zeigt. Allerdings bitte nicht verwenden, um effektiv Primzahlen zu berechnen. Die Idee dahinter ist, alle Vielfache einer Primzahl aus der Liste zu entfernen:


def findPrimes(list):
    list2 = list.copy()
    notPrimes = [[]]
    for i in range(2, int(m.sqrt(len(list))) + 1):
        notPrimes.append([x*i for x in list])
    i = 0
    result = set(list2)
    while i < len(notPrimes):
        result = result.difference(set(notPrimes[i]))
        i += 1
    return result


print(list(findPrimes(list(range(2, 100)))))

Einige Reduktionsfunktionen sind direkter Bestandteil von Python: sum, max, min.

Ich wünsche nun viel Vergnügen beim Training!

Kommentare

Beliebte Posts aus diesem Blog

Python : Einführung in pygame

Einführung Pygame ist eine Bibliothek in Python, die es erlaubt grafisch anspruchsvolle Spiele zu erstellen. Damit pygame effektiv eingesetzt werden kann, braucht es doch einiges an Basiswissen, das in diesem Blog vermittelt wird. Gerade für Spiele wird vielmals von Elementen der Künstlichen Intelligenz Gebrauch gemacht. Teilweise handelt es sich nur um offensichtliche KI-Routinen aber andererseits auch um hochkomplexe Algorithmen, die nicht so trivial zu verstehen sind. Vor etlichen Jahren habe ich ein Buch gekauft, mit dem ansprechenden Namen " AI for Game developers " von David M. Bourg und Glenn Seemann. Das Ziel war es, herauszufinden, wie einfach ein Spiel unter Java 5 realisiert werden könnte. Das ganze sollte ein Kundenprojekt werden, ist aber dann nie zustande gekommen, weil der Aufwand zu gross war, das Projekt mit den bestehenden Java Bibliotheken umzusetzen. Für meine weitere "Forschung" hinsichtlich KI habe ich dieses Buch wieder zur Hand genomm...

Terraform und Ansible - ein starkes Gespann

Einführung Terraform (IaaS - Infrastructure as a Service) und Ansible (CaaS - Configuration as a Service) bilden zusammen ein starkes Gespann, um schnell konfigurierte Ressourcen auf der Microsoft Azure Cloud zu provisionieren. In meinen bisherigen Blogartikeln habe ich bisher Terraform vorgestellt https://thomkerle.blogspot.com/2019/02/azure-infrastruktur-erstellen-mit.html https://thomkerle.blogspot.com/2019/03/azure-service-principal.html https://thomkerle.blogspot.com/2019/03/eine-komplette-terraform-pipeline-mit.html https://thomkerle.blogspot.com/2019/08/terraform-12-ist-da.html und zwar wie mit Terraform effizient Ressourcen aus Azure DevOps ( https://dev.azure.com ) provisioniert werden können. Während sich Terraform vor allem im Bereich "Ressourcen-Deployment" etabliert hat, scheint sich Ansible im Bereich "Configuration as a Service" zu etablieren. In diesem Artikel präsentiere ich ein Beispiel, wie mit Terraform Ansible Code - nach de...

Gnome Desktop auf Azure

Einleitung DaaS heisst nichts anderes als Desktop as a Service. Darunter wird die Bereitstellung eines Desktops in der Cloud verstanden. Anstatt Windows 10 zu Hause zu nutzen, wird Windows in der Cloud genutzt. Also anstatt leistungsfähige Hardware zu Hause zu horten, kann die Hardware in der Cloud genutzt werden. Mit geeigneter Software kann dann ein virtueller Desktop zur virtuellen Maschine in der Cloud lokal auf dem eigenen Rechner genutzt werden.  Im Moment ist dabei klar Citrix der Marktführer dicht gefolgt von anderen Herstellern unter anderem auch Microsoft. Schaut man in die Linux Welt, so wird mit Spice ein Protokoll angeboten, mit dem eine unter KVM laufende virtuelle Maschine angesprochen werden kann. Das Desktop Experiment übernimmt der virt-viewer, der unter unter  https://www.spice-space.org/download.html heruntergeladen werden kann. Hier gehen wir aber von einem leicht anderen Setup aus. Wir wollen den virt-viewer nutzen, um eine in Azure deployte U...