Ich habe gerade mit Python angefangen und habe keine Ahnung, was Memoisierung ist und wie man es verwendet. Kann ich auch ein vereinfachtes Beispiel haben?
Antworten
Zu viele Anzeigen?Nicht zu vergessen sind die eingebauten hasattr
Funktion, für diejenigen, die handwerklich arbeiten wollen. Auf diese Weise können Sie den Zwischenspeicher innerhalb der Funktionsdefinition halten (im Gegensatz zu einer globalen).
def fact(n):
if not hasattr(fact, 'mem'):
fact.mem = {1: 1}
if not n in fact.mem:
fact.mem[n] = n * fact(n - 1)
return fact.mem[n]
Memoisierung ist die Umwandlung von Funktionen in Datenstrukturen. Normalerweise möchte man, dass die Umwandlung inkrementell und träge erfolgt (auf Anforderung eines bestimmten Domänenelements - oder "Schlüssels"). In faulen funktionalen Sprachen kann diese faule Konvertierung automatisch erfolgen, und somit kann Memoisierung ohne (explizite) Seiteneffekte implementiert werden.
Memoisierung bedeutet im Grunde, dass die Ergebnisse früherer Operationen, die mit rekursiven Algorithmen durchgeführt wurden, gespeichert werden, um die Notwendigkeit zu verringern, den Rekursionsbaum zu durchlaufen, wenn die gleiche Berechnung zu einem späteren Zeitpunkt erforderlich ist.
siehe http://scriptbucket.wordpress.com/2012/12/11/introduction-to-memoization/
Beispiel für die Fibonacci-Memoisierung in Python:
fibcache = {}
def fib(num):
if num in fibcache:
return fibcache[num]
else:
fibcache[num] = num if num < 2 else fib(num-1) + fib(num-2)
return fibcache[num]
Nun, ich sollte den ersten Teil zuerst beantworten: Was ist Memoisierung?
Das ist nur eine Methode, um Erinnerung gegen Zeit zu tauschen. Denken Sie an Multiplikationstabelle .
Die Verwendung eines veränderlichen Objekts als Standardwert in Python wird normalerweise als schlecht angesehen. Aber wenn man es mit Bedacht einsetzt, kann es tatsächlich nützlich sein, ein memoization
.
Hier ist ein Beispiel aus http://docs.python.org/2/faq/design.html#why-are-default-values-shared-between-objects
Mit einer veränderbaren dict
in der Funktionsdefinition können die berechneten Zwischenergebnisse zwischengespeichert werden (z. B. bei der Berechnung von factorial(10)
nach Berechnung factorial(9)
können wir alle Zwischenergebnisse wiederverwenden)
def factorial(n, _cache={1:1}):
try:
return _cache[n]
except IndexError:
_cache[n] = factorial(n-1)*n
return _cache[n]
Hier ist eine Lösung, die mit Argumenten vom Typ Liste oder Diktat funktioniert, ohne zu jammern:
def memoize(fn):
"""returns a memoized version of any function that can be called
with the same list of arguments.
Usage: foo = memoize(foo)"""
def handle_item(x):
if isinstance(x, dict):
return make_tuple(sorted(x.items()))
elif hasattr(x, '__iter__'):
return make_tuple(x)
else:
return x
def make_tuple(L):
return tuple(handle_item(x) for x in L)
def foo(*args, **kwargs):
items_cache = make_tuple(sorted(kwargs.items()))
args_cache = make_tuple(args)
if (args_cache, items_cache) not in foo.past_calls:
foo.past_calls[(args_cache, items_cache)] = fn(*args,**kwargs)
return foo.past_calls[(args_cache, items_cache)]
foo.past_calls = {}
foo.__name__ = 'memoized_' + fn.__name__
return foo
Beachten Sie, dass dieser Ansatz natürlich auf jedes beliebige Objekt ausgeweitet werden kann, indem Sie Ihre eigene Hash-Funktion als Spezialfall in handle_item implementieren. Um diesen Ansatz zum Beispiel für eine Funktion zu verwenden, die ein Set als Eingangsargument nimmt, könnten Sie zu handle_item hinzufügen:
if is_instance(x, set):
return make_tuple(sorted(list(x)))
289 Stimmen
Wenn der zweite Satz des entsprechenden Wikipedia-Artikels den Satz "Mutually-recursive descent parsing[1] in einem allgemeinen Top-Down-Parsing-Algorithmus[2][3], der Mehrdeutigkeit und linke Rekursion in polynomialer Zeit und polynomialem Raum berücksichtigt" enthält, ist es meiner Meinung nach durchaus angebracht, SO zu fragen, was hier los ist.
14 Stimmen
@Clueless: Vor diesem Satz steht: "Die Memoisierung wurde auch in anderen Zusammenhängen (und zu anderen Zwecken als zur Geschwindigkeitssteigerung) verwendet, z. B. in". Es ist also nur eine Liste von Beispielen (und muss nicht verstanden werden); es ist nicht Teil der Erklärung der Memoisierung.
0 Stimmen
Hier ist eine gute Erklärung mit angehängten Beispielen der Memoisierung und wie man sie in einen Dekorator einbaut: pycogsci.info/?p=221
1 Stimmen
@StefanGruenwald Der Link ist tot. Können Sie bitte ein Update finden?
3 Stimmen
Neuer Link zur pdf-Datei, da pycogsci.info nicht erreichbar ist: people.ucsc.edu/~abrsvn/NLTK_parsing_demos.pdf
0 Stimmen
Sie können sich meinen Blogbeitrag unter u8y7541.github.io/blog_posts/lambdas_recursion_memoizing.html ansehen.
8 Stimmen
@Clueless, Der Artikel sagt eigentlich " einfach wechselseitig rekursives Descent-Parsing[1] in einem allgemeinen Top-Down-Parsing-Algorithmus[2][3], der Mehrdeutigkeit und linke Rekursion in polynomieller Zeit und polynomialem Raum berücksichtigt". Sie haben das einfach was dieses Beispiel natürlich viel klarer macht :).
1 Stimmen
Wenn ich sehe, wie viele Leute diese Frage beantwortet haben und immer noch beantworten, glaube ich an den "BIKE SHED EFFECT". de.wikipedia.org/wiki/Gesetz_der_Trivialität
1 Stimmen
@A_P zu dem Zeitpunkt, als Sie das geschrieben haben, waren alle 13 Antworten bis auf eine 5 Jahre alt (2014) und die letzte 3 Jahre alt (2016). Ich bin mir nicht sicher, ob das als "immer noch Antworten" zählt. Die Antwort, die ich gerade gepostet habe, fügt Überlegungen zur Geschwindigkeit hinzu, die ich in anderen Antworten noch nicht gesehen habe, und führt keine neue Methode oder ähnliches ein. Es gibt sicherlich Beispiele für das von Ihnen beschriebene Phänomen, aber ich bin mir nicht sicher, ob es das hier ist.