Eigentlich wollte ich Zahlen in 〇〇 einfügen und es wie ein Geschäftsbuch aussehen lassen, Ich habe es geschafft, weil ich die Nummer nicht richtig entschieden habe und ich werde sie von Zeit zu Zeit hinzufügen: unschuldig :.
Dies ist für Anfänger, die gerade erst mit Python anfangen Für diejenigen, die kürzlich etwas über Numpy oder Scipy gelernt haben. Wenn Sie mit Python vertraut sind, können Sie einige Ratschläge geben. Ich wäre Ihnen dankbar, wenn Sie mir einen anderen Fall oder einen besseren Weg nennen könnten: smiley :.
Außerdem war die Ausführungsumgebung ** Python 3.5.3 **. Seien Sie also besonders vorsichtig, wenn Sie ** Python 2-Serie ** verwenden. (Weil der Rückgabewert von Map oder Filter unterschiedlich ist)
Mit dem jüngsten Boom des maschinellen Lernens haben viele Menschen möglicherweise begonnen, Python zu lernen. Möglicherweise stellen Sie fest, dass Bibliotheken wie numpy vorhanden sind, insbesondere wenn es sich um einfache numerische Verarbeitung und tatsächliche Daten handelt.
Mir ist jedoch klar, dass ich Daten einer bestimmten Größe verarbeite. Die Ausführung kann jedoch einige Zeit dauern, wenn ich keine Schreibweise entwerfe (ich persönlich bin der Meinung, dass es sich beim ersten Programmieren oder vor Python um eine statisch typisierte Sprache handelt. Ich denke, es ist einfach aufzustehen, wenn du es tust.
Besonders wenn ich lerne, möchte ich verschiedene Dinge ausprobieren. Wenn die Ausführung also lange dauert, kann ich es nicht tun. Ich hasse Programmierung: wütend :.
Daher hier durch Verwendung von ** numpy ** usw. in dem Fall, in dem es scheint, dass es "relativ leicht" beschleunigt werden kann. Ich werde es vorstellen.
Ich persönlich bin vorsichtig. Wenn es aufgrund von Schreibproblemen langsam ist, ist es wahrscheinlich, dass Sie mit einem der folgenden Probleme konfrontiert sind:
Das folgende Beispiel ist für diejenigen, die den folgenden Teilen folgen, nicht erforderlich.
Die folgenden Bibliotheken werden vorab importiert.
import numpy as np
import pandas as pd
import scipy as sp
Sample.py
def func1(n):
a = []
for i in range(n):
a.append(i)
return a
def func2(n):
a = [0 for i in range(n)] #Liste der mit n initialisierten Länge n
for i in range(n):
a[i] = i
return a
def func3(n):
a = [i for i in range(n)] #Initialisieren Sie zuerst mit der Einschlussnotation
return a
def func4(n):
return [i for i in range(n)] #Direkt definieren und zurückgeben
%time a = func1(10000000)
%time b = func2(10000000)
%time c = func3(10000000)
%time d = func4(10000000)
result
CPU times: user 660 ms, sys: 100 ms, total: 760 ms
Wall time: 762 ms
CPU times: user 690 ms, sys: 60 ms, total: 750 ms
Wall time: 760 ms
CPU times: user 290 ms, sys: 90 ms, total: 380 ms
Wall time: 388 ms
CPU times: user 320 ms, sys: 90 ms, total: 410 ms
Wall time: 413 ms
Wenn Sie die Länge der Liste kennen, die im Voraus zurückgegeben werden soll, verwenden Sie die Einschlussnotation Es wird schneller sein. Tatsächlich halbiert dies allein die Ausführungszeit. Es ist eine gute Idee, sich dessen bewusst zu sein, insbesondere wenn Sie eine for-Anweisung auf eine lange Liste setzen.
Hier wird angenommen, dass die folgenden Vektoren vordefiniert sind.
a = np.array([i for i in range(10000000)])
Stellen Sie sich eine Funktion vor, die alle Elemente im Vektor für diesen Vektor verdoppelt und zurückgibt.
Sample.py
def func1(x):
y = x.copy()
for i in range(len(y)):
y[i] *= 2
return y
def func2(a):
return a * 2
%time b = func1(a)
%time c = func2(a)
result
CPU times: user 2.33 s, sys: 0 ns, total: 2.33 s
Wall time: 2.33 s
CPU times: user 10 ms, sys: 10 ms, total: 20 ms
Wall time: 13 ms
Auf diese Weise kann numpy vier Regeln für jeden Vektor ausführen Achten Sie darauf, nicht zu zirkulieren.
Verwenden Sie den gleichen Vektor wie oben. Angenommen, Sie möchten nur Elemente, die ein Vielfaches von 3 sind, aus dem obigen Vektor abrufen. Dann denken Sie vielleicht: "Ich habe keine andere Wahl, als die if-Anweisung in der for-Anweisung zu verwenden!" Sie können auch wie folgt schreiben.
Sample.py
def func1(a):
ans = []
for i in range(len(a)):
if a[i] % 3 == 0:
ans.append(a[i])
return np.array(ans)
def func2(a):
return a[a % 3 == 0]
%time b = func1(a)
%time c = func2(a)
result
CPU times: user 3.44 s, sys: 10 ms, total: 3.45 s
Wall time: 3.45 s
CPU times: user 120 ms, sys: 10 ms, total: 130 ms
Wall time: 131 ms
Wenn Sie anstelle eines Vektors aus einer Liste abrufen möchten, können Sie die Funktion ** Filter ** verwenden. Wenn Sie ** numpy ** nicht verwenden können oder wollen, sollten Sie dies berücksichtigen.
Sie können sich "Lambda x: y" im Beispiel als eine unbenannte Funktion vorstellen, die "x" als Argument verwendet und "y" zurückgibt.
Sample.py
x = [i for i in range(10000000)]
%time y = list(filter(lambda x: x % 3 == 0, x))
result
CPU times: user 1.67 s, sys: 10 ms, total: 1.68 s
Wall time: 1.68 s
Es ist langsamer als die Verwendung von ** numpy **, aber schneller als die Verwendung von append in einer for-Anweisung!
Als nächstes sollten Sie eine Funktion auf jedes Element der Liste anwenden. Hier stellen wir die Funktion ** map ** vor. Dies ist eine Funktion, die das Ergebnis der Anwendung der angegebenen Funktion auf jedes Element in der Liste zurückgibt (Map-Objekt in Python3).
Außerdem ist die unten stehende Funktion eine Funktion, die $ x ^ 2 + 2x + 1 $ zurückgibt.
Sample.py
a = np.array([i for i in range(10000000)])
def func(x):
return x**2 + 2*x + 1
def func1(a):
return np.array([func(i) for i in a])
def func2(a):
return np.array(list(map(func, a.tolist())))
%time b = func1(a)
%time c = func2(a)
%time d = a**2 + 2*a + 1
result
CPU times: user 5.14 s, sys: 90 ms, total: 5.23 s
Wall time: 5.23 s
CPU times: user 4.95 s, sys: 170 ms, total: 5.12 s
Wall time: 5.11 s
CPU times: user 20 ms, sys: 30 ms, total: 50 ms
Wall time: 51.2 ms
Ich habe die Kartenfunktion eingeführt, aber sie unterschied sich nicht so sehr von der Einschlussnotation: cry :. Sie haben es vielleicht schon mitten im Lesen bemerkt, aber im obigen Beispiel war es eine einfache Funktion, sodass die direkte Vektorberechnung überwältigend schneller ist!
Bisher haben wir uns mit eindimensionalen Arrays (Vektoren) befasst. Im folgenden Beispiel möchte ich mich mit einem zweidimensionalen Array (Matrix) befassen.
In den folgenden Fällen wird davon ausgegangen, dass Sie jeden numerischen Wert durch Vorverarbeitung wie maschinelles Lernen in eine Punktzahl umwandeln möchten. Definieren Sie zunächst die folgende Matrix.
a = np.array([[i % 100 for i in range(1000)] for j in range(10000)])
Bereiten Sie als Nächstes eine Liste vor, die in eine Partitur konvertiert werden soll. In der folgenden Liste 0, wenn die ursprüngliche Zahl kleiner als 20 ist, 1, wenn sie 20 oder mehr beträgt, und weniger als 50, 4, wenn sie 90 oder mehr beträgt. Angenommen, Sie möchten die Zahlen in der Matrix konvertieren, z.
scores = [20, 50, 70, 90]
Zunächst möchte ich meinen Kopf leeren und gehorsam umsetzen.
Sample.py
def func1(x):
y = np.zeros(x.shape)
for s in scores:
for i in range(x.shape[0]):
for j in range(x.shape[1]):
if x[i, j] >= s:
y[i, j] += 1
return y
%time b = func1(a)
Das Ergebnis ist eine schöne Dreifachschleife: unschuldig :. (Deep Loops sind nicht nur langsamer, sondern auch schwieriger zu lesen und zu befolgen. Machen Sie nicht zu viele Deep Loops für Menschen.)
Der Inhalt der Funktion wird für jedes Element in der Matrix um 1 erhöht, wenn er größer als die angegebene Punktzahl ist.
result1
CPU times: user 14 s, sys: 10 ms, total: 14 s
Wall time: 14 s
Wie erwartet hat die Ausführungszeit auch ** 10 Sekunden ** überschritten: cry :.
Als nächstes werde ich eine Funktion vorstellen, die entwickelt wurde.
Sample2.py
def func2(x):
y = np.zeros(x.shape)
for s in scores:
y += (x >= s)
return y
%time c = func2(a)
Folgendes machen wir:
x> = s
ist ** wahr ** wenn Element> = s
, ** falsch ** wenn nicht ** Matrix ** für jedes Element der Matrix x
y
ist eine Zahl, und wenn Sie versuchen, der Zahl ** Wahr ** oder ** Falsch ** hinzuzufügen, erhalten Sie ** 1 ** und ** 0 **.Wie oben erwähnt, ist der Code kurz, enthält jedoch verschiedene Elemente. Es ist jedoch ** 100-mal schneller ** um den Betrag, um den die for-Anweisung nicht mehr umgedreht wird: smile :.
result
CPU times: user 90 ms, sys: 20 ms, total: 110 ms
Wall time: 111 ms
An diesem Punkt könnten Sie das Gefühl haben, "Ich möchte alle ** für ** Sätze löschen, bevor sie geboren werden: wütend:". Also habe ich es als Versuch geschrieben.
Sample3.py
def func3(x):
len_score = len(scores)
y = x * np.array([[np.ones(len_score)]]).T
s = np.array(scores).reshape(len_score, 1, 1)
z = (y >= s)
return z.sum(axis=0)
result
CPU times: user 200 ms, sys: 30 ms, total: 230 ms
Wall time: 235 ms
... spät: weinen: (vielleicht wegen schlechten Schreibens) Dies ist langsam, erfordert viel Speicher (da alles zuerst erweitert wird) und vor allem wird es schwer zu verstehen. Daher fand ich, dass es keine gute Idee ist, die for-Anweisung mit Gewalt zu löschen.
Ich erinnerte mich daran, als ich einen kürzlich erschienenen Artikel sah, also machte ich mir eine Notiz.
In Python können Sie mit in
überprüfen, ob sich ein Element in der Liste befindet.
Wenn Sie dies jedoch auf eine Liste anwenden, ist dies $ O (n) $ für eine Listenlänge von $ n $. Wenn Sie also einen Fehler machen, erhalten Sie einen Unfall.
Wenn Sie die Existenz wiederholt überprüfen möchten, ist es besser, sie durch "set" usw. zu ersetzen, wie unten gezeigt.
JupyterNotebook(GoogleColaboratory)Bestätigt in
L = 100000
x = list(range(L))
def sample1(list_tmp):
j = 0
for i in list_tmp:
if i in list_tmp:
j += 1
print("sample1 j: ", j)
def sample2(list_tmp):
j = 0
set_tmp = set(list_tmp) #In Set konvertieren
for i in list_tmp:
if i in set_tmp: #Überprüfen Sie, ob es eingestellt ist
j += 1
print("sample2 j: ", j)
%time sample1(x)
print("----------------------------------------")
%time sample2(x)
Ergebnis
sample1 j: 100000
CPU times: user 1min 7s, sys: 16 ms, total: 1min 7s
Wall time: 1min 7s
----------------------------------------
sample2 j: 100000
CPU times: user 8 ms, sys: 6 ms, total: 14 ms
Wall time: 14 ms
Ich sagte oben, dass ich nicht so viel für Aussagen verwenden sollte, Trotzdem denke ich, dass es Situationen gibt, in denen man es benutzen muss oder es leichter zu verstehen ist.
Öffnen Sie es in diesem Fall erneut und verwenden Sie * numba *. * numba * ist ein kleiner Compiler.
"Nun, gibt der Compiler alle Variablen an? Muss ich einen Kompilierungsbefehl eingeben?"
Du denkst vielleicht, aber mach dir keine Sorgen. Fügen Sie einfach eine Zeile hinzu (zwei Zeilen, wenn Sie "Import" einschließen).
Sehen wir uns ein aktuelles Anwendungsbeispiel an.
import numba
def sample1(n):
ans = 0
for i in range(n):
ans += i
return ans
@numba.jit
def sample2(n):
ans = 0
for i in range(n):
ans += i
return ans
@numba.jit('i8(i8)', nopython=True)
def sample3(n):
ans = 0
for i in range(n):
ans += i
return ans
%time a = sample1(100000000) #Wenn du nichts tust
%time b = sample2(100000000) #Bei Verwendung von jit
%time c = sample3(100000000) # jit(Typenspezifikation)Beim Benutzen
Von oben nach unten: "Ich habe nichts getan", "Ich habe Numba verwendet" und "Ich habe Numba verwendet (Typenspezifikation)". Es ist eine Funktion. Innerhalb der Funktion befindet sich eine Funktion, die 0 zu $ n -1 $ hinzufügt und von diesen zurückgibt.
Eine Typspezifikation finden Sie im Blog von Python Acceleration Numba Introduction Part 2-tkm2261.
Die Ausführungszeit ist wie folgt. Wenn Sie nichts tun, dauert es 5 Sekunden, aber wenn Sie "numba (Typenspezifikation)" verwenden, dauert es ungefähr 5,5 Mikrosekunden. Es ist nur eine andere Ziffer (in diesem Beispiel ist es ** ungefähr 940.000 Mal schneller **: unschuldig :).
CPU times: user 5.16 s, sys: 0 ns, total: 5.16 s
Wall time: 5.16 s
CPU times: user 30 ms, sys: 0 ns, total: 30 ms
Wall time: 25.9 ms
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 5.48 µs
Ich habe das Gefühl, dass ich viel geschrieben habe, aber im obigen Fall habe ich das Gefühl, dass es mit "Nicht für Aussage verwenden" endete. In Zukunft möchte ich verschiedene Dinge wie ** scipy ** und ** pandas ** zusammenstellen.
Recommended Posts