Ich bin hin- und hergerissen zwischen objektorientiertem und vektorbasiertem Design. Ich liebe die Fähigkeiten, die Struktur und die Sicherheit, die Objekte der gesamten Architektur verleihen. Gleichzeitig ist mir die Geschwindigkeit sehr wichtig, und einfache Float-Variablen in einem Array helfen wirklich bei vektorbasierten Sprachen / Bibliotheken wie Matlab oder Numpy in Python.
Hier ist ein Teil des Codes, den ich geschrieben habe, um meinen Standpunkt zu veranschaulichen
Problem: Hinzufügen von Tow-Volatilitätszahlen. Wenn x und y zwei Flüchtigkeitszahlen sind, ist die Summe der Flüchtigkeit (x ^ 2 + y ^ 2) ^ 0,5 (unter der Annahme bestimmter mathematischer Bedingungen, aber das ist hier nicht wichtig).
Ich möchte diese Operation sehr schnell durchführen und gleichzeitig sicherstellen, dass die Leute die Volatilität nicht einfach falsch addieren (x + y). Beides ist wichtig.
Das OO-basierte Design würde ungefähr so aussehen:
from datetime import datetime
from pandas import *
class Volatility:
def __init__(self,value):
self.value = value
def __str__(self):
return "Volatility: "+ str(self.value)
def __add__(self,other):
return Volatility(pow(self.value*self.value + other.value*other.value, 0.5))
(Nebenbei: Für diejenigen, die Python noch nicht kennen, __add__
ist dies nur eine Funktion, die den +
Operator außer Kraft setzt. )
Nehmen wir an, ich füge zwei Listen mit Volatilitätswerten hinzu
n = 1000000
vs1 = Series(map(lambda x: Volatility(2*x-1.0), range(0,n)))
vs2 = Series(map(lambda x: Volatility(2*x+1.0), range(0,n)))
(Übrigens: Wieder ist eine Reihe in Python eine Art Liste mit einem Index.) Nun möchte ich die beiden hinzufügen:
t1 = datetime.now()
vs3 = vs1 + vs2
t2 = datetime.now()
print t2-t1
Nur die Addition läuft in 3,8 Sekunden auf meinem Computer. Die von mir angegebenen Ergebnisse enthalten nicht die Objektinitialisierungszeit, sondern nur den zeitlich festgelegten Additionscode. Wenn ich dasselbe mit Numpy-Arrays ausführe:
nv1 = Series(map(lambda x: 2.0*x-1.0, range(0,n)))
nv2 = Series(map(lambda x: 2.0*x+1.0, range(0,n)))
t3 = datetime.now()
nv3 = numpy.sqrt((nv1*nv1+nv2*nv2))
t4 = datetime.now()
print t4-t3
Es läuft in 0.03 Sekunden. Das ist mehr als 100 mal schneller!
Wie Sie sehen, gibt mir der OOP-Weg eine Menge Sicherheit, dass die Leute Volatility nicht auf die falsche Weise hinzufügen, aber die Vektormethode ist einfach so verrückt, schnell! Gibt es ein Design, in dem ich beides bekommen kann? Ich bin sicher, dass viele von Ihnen ähnliche Designentscheidungen getroffen haben. Wie haben Sie das herausgefunden?
Die Wahl der Sprache ist dabei unerheblich. Ich weiß, dass viele von Ihnen raten würden, C ++ oder Java zu verwenden, und der Code kann sowieso schneller als vektorbasierte Sprachen laufen. Darum geht es aber nicht. Ich muss Python verwenden, da ich eine Vielzahl von Bibliotheken habe, die in anderen Sprachen nicht verfügbar sind. Das ist meine Einschränkung. Ich muss darin optimieren.
Und ich weiß, dass viele Leute Parallelisierung, GPGPU usw. vorschlagen würden. Aber ich möchte zuerst die Single-Core-Leistung maximieren und dann beide Codeversionen parallelisieren.
Danke im Voraus!
quelle
Antworten:
Entwerfen Sie größere Objekte. Ein
Pixel
Objekt hat keinen Freiraum für parallelisierte Loop- oder GPU-Bildtransformationen oder ähnliches. EinImage
nicht , sofern sie nicht durch die Barriere eines Teeny zu gehen habenPixel
Objekt an den Daten zu erhalten.quelle
Dies ist einer der Bereiche, in denen es unmöglich ist, endgültige Antworten zu geben, da es sich um einen Kompromiss handelt. Wie Sie herausgefunden haben, ist weder OO noch vektorbasiert immer überlegen, aber alles hängt davon ab, wie die Software verwendet wird.
Sie könnten versuchen, das Beste aus beiden zu kombinieren und sowohl ein
Volatility
Objekt als auch einVolatilitySeries
Objekt zu erstellen , wobei das zweite konzeptionell eine Reihe von Volatility-Objekten darstellt, aber intern eine Speichermethode verwendet, die sich viel besser für die Vektorisierung der Berechnungen eignet (eine Struktur von Arrays). . Dann müssen Sie nur noch Ihre Benutzer darüber informieren, dass die VerwendungVolatilitySeries
viel vorzuziehen istSeries(Volatility)
.quelle
VolatilitySeries
wie Sie vorschlagen, dann kann ich keinlist
, oder eintuple
oder (vorausgesetzt, Sie sind mit Python vertraut)DataFrame
von Volatilitätselementen haben. Das stört mich, denn dann lässt sich meine Architektur nicht gut skalieren und die Vorteile lassen nach einer Weile nach. Und genau das bringt mich hierher :).volatilitySeries[0] + 3.0
, was falsch sein wird. Sobald Sie die Werte von herausgerissen habenVolatilitySeries
, können Sie wahnsinnig werden, sodass die Sicherheit nur von kurzer Dauer ist. In einer polymorphen Umgebung, in der die Leute nicht immer wissen, welche Klasse genau verwendet wird, ist dies sehr gut möglich. Und Sie wissen, Sie können Ihre Benutzer nur so gut schulen. Ich weiß, dass Sie das sagen werden, hey, ich kann das auch tun, wenn ich mich windeVolatility.value
, aber Sie wissen, zumindest ist dem Benutzer jetzt bewusst, dass er einen speziellen Wert verwendet.Series
in geerbt wurden, außer Kraft gesetzt werdenVolatilitySeries
, aber das macht den ganzen Zweck zunichte. Was ich also aus diesem Weg gelernt habe, ist, dass einVolatilitySeries
Objekt auf lange Sicht nur dann wirklich funktioniert, wenn die einzelnen Zellen vom Typ sindVolatility
.VolatileSeries
Ansatz durchführbar ist. Wenn Sie es bereits ausprobiert haben und es nicht funktioniert hat, haben Sie eine schwierige Wahl zwischen Sicherheit und Geschwindigkeit. Wir können Ihnen dort nicht helfen. (es sei denn, jemand anderes hat eine brillante Antwort)