2016-06-10 12 views
1

Ich renne in ein Problem, das ich noch nie zuvor gesehen habe, und es ist verdammt frustrierend von mir. Ich verwende rpy2, um mit R aus einem Python-Skript zu interferieren und ein Array zu normalisieren. Aus irgendeinem Grund, wenn ich meine Ausgabe zusammen stücken und in eine Datei drucken, dauert es Alter zu drucken. Es verlangsamt sich auch, wenn es weitergeht, bis es tropft vielleicht ein paar kb Daten pro Minute ausgeben.Python unglaublich langsam drucken

Meine Eingabedatei ist groß (366 MB), aber diese läuft auf einem Hochleistungsrechencluster mit nahezu unbegrenzten Ressourcen. Es sollte kein Problem haben, das durchzuspielen.

Hier ist, wo ich tatsächlich die Normalisierung tun:

matrix = sample_list # two-dimensional array 
v = robjects.FloatVector([ element for col in matrix for element in col ]) 
m = robjects.r['matrix'](v, ncol = len(matrix), byrow=False) 
print("Performing quantile normalization.") 
Rnormalized_matrix = preprocessCore.normalize_quantiles(m) 
normalized_matrix = np.array(Rnormalized_matrix) 

Wie Sie sehen können, habe ich mit einem numpy.array Objekt am Ende meine jetzt normalisierte Daten enthält. Ich habe eine andere Liste, die andere Zeichenketten enthält, die ich auch zum Ausgang drucken möchte, jedes Element, das einem Element des numpy Feldes entspricht. Ich wiederhole also, indem ich jede Zeile des Arrays zu einer Zeichenkette zusammenfüge und beide zur Ausgabe drucke.

for thing in pos_list: # List of strings corresponding with each row of array. 
    thing_index = pos_list.index(thing) 

    norm_data = normalized_matrix[thing_index] 
    out_data = "\t".join("{0:.2f}".format(piece) for piece in norm_data) 

    print(thing + "\t" + out_data, file=output) 

Ich bin kein Profi, aber ich habe keine Ahnung, warum die Dinge so sehr verlangsamen. Jeder Einblick oder Vorschläge wären sehr, sehr geschätzt. Ich kann mehr/den Rest des Skripts posten, wenn jemand denkt, dass es hilfreich sein könnte.

Update: Danke an @lgautier für seinen Profilierungsvorschlag. Unter Verwendung des line_profiler Modul, konnte ich mein Problem mit der Leitung lokalisieren: thing_index = pos_list.index(thing)

Dies macht Sinn, da diese Liste ist sehr lang, und es erklärt auch die Verlangsamung als das Skript abläuft. Stattdessen wurde einfach das Problem behoben.

Profilieren von Original-Code (das% für die angegebene Zeile bemerken):

Line #  Hits   Time Per Hit % Time Line Contents 
    115   1  16445761 16445761.0  15.5  header, pos_list, normalized_matrix = Quantile_Normalize(in 
    117   1   54  54.0  0.0   print("Creating output file...") 
    120   1   1450 1450.0  0.0   output = open(output_file, "w") 
    122   1   8  8.0  0.0   print(header, file=output) 
    124             # Iterate through each position and print QN'd data 
    125 100000  74600  0.7  0.1   for thing in pos_list: 
    126  99999  85244758 852.5  80.3     thing_index = pos_list.index(thing) 
    129  99999  158741  1.6  0.1     norm_data = normalized_matrix[thing_index] 
    130  99999  3801631  38.0  3.6     out_data = "\t".join("{0:.2f}".format(piece) for pi 
    132  99999  384248  3.8  0.4     print(thing + "\t" + out_data, file=output) 
    134   1   3641 3641.0  0.0   output.close() 

neuen Code Profilierungs:

Line #  Hits   Time Per Hit % Time Line Contents 
    115   1  16177130 16177130.0  82.5  header, pos_list, normalized_matrix = Quantile_Normalize(input_file, data_start) 
    116 
    117   1   55  55.0  0.0   print("Creating output file...") 
    118 
    119 
    120   1  26157 26157.0  0.1   output = open(output_file, "w") 
    121 
    122   1   11  11.0  0.0   print(header, file=output) 
    123 
    124             # Iterate through each position and print QN'd data 
    125   1   1  1.0  0.0   count = 0 
    126 100000  62709  0.6  0.3   for thing in pos_list: 
    127  99999  58587  0.6  0.3     thing_index = count 
    128  99999  67164  0.7  0.3     count += 1 
    131  99999  85664  0.9  0.4     norm_data = normalized_matrix[thing_index] 
    132  99999  2877634  28.8  14.7     out_data = "\t".join("{0:.2f}".format(piece) for piece in norm_data) 
    134  99999  240654  2.4  1.2     print(thing + "\t" + out_data, file=output) 
    136   1   1713 1713.0  0.0   output.close() 
+0

Enthält pos_list R-Objekte? Ich verwende rpy2 nicht häufig, aber aus meiner Erfahrung sind die Interaktionen zwischen den beiden Sprachen ziemlich langsam. –

+0

Welcher Teil ist eigentlich langsam? Versuchen Sie, Teile auskommentieren, um zu sehen, was es schneller macht. Ich würde erwarten, dass [Element für Spalte in Matrix für Element in Spalte] 'ziemlich langsam ist. –

+0

Nein, 'pos_list' enthält nur Zeichenfolgen. Das '[Element für Spalte in Matrix für Element in Spalte]' Bit ist langsam, aber es ist vor jeder tatsächlichen Ausgabe in Datei, so ist es hier nicht der Flaschenhals. –

Antwort

2

Wenn ich diese richtig bin Verständnis alles läuft gut und mit einer guten Leistung bis zu (einschließlich) die Zeile:

normalized_matrix = np.array(Rnormalized_matrix) 

Zu dieser Linie die resultierende Matrix in eine numpy Array gedreht wird (wörtlich - es kann sogar schneller sein, wenn Sie vermeiden, die Daten zu kopieren, wie in http://rpy2.readthedocs.io/en/version_2.8.x/numpy.html?from-rpy2-to-numpy).

Ich kann die Leistungsprobleme im Rest des Skripts nicht sehen, das zu rpy2 gehört.

Nun, was passieren könnte ist, dass dies nicht ist, weil es auf dem Etikett "HPC" steht, dass es in jeder Situation mit allem Code eine hohe Leistung ist. Haben Sie darüber nachgedacht, diese langsame letzte Schleife durch einen Code-Profiler zu führen?Es würde dir sagen, wo die Zeit verbracht wird.

+0

Mit dem 'line_profiler'-Modul konnte ich feststellen, dass ~ 80% der Zeit für diese Zeile ausgegeben wird:' thing_index = pos_list.index (thing) ', was meiner Meinung nach offensichtlich sein sollte, da die Datei ist Millionen von Zeilen lang und wie es verlangsamt, wie es weiter und weiter suchen muss, wie es weiter geht. Ich ersetzte es nur durch eine Zählung und sah eine massive Beschleunigung. Ein enormes Versehen meinerseits, aber da Ihre Antwort mich zu der richtigen Strategie geführt hat, stehe ich für die Antwort. Ich werde meine Frage aktualisieren, um die Profilerstellung und Änderungen widerzuspiegeln. –

1

Für eine Sache, ich in der Regel einen Generator verwenden, um die temporäre Liste zu vermeiden von vielen kleinen Saiten.

out_data = "\t".join("{0:.2f}".format(piece) for piece in norm_data) 

Aber es ist schwer zu sagen, ob dieser Teil der langsame war.

+0

Danke, das ist ein guter Tipp. Ich habe meinen obigen Code aktualisiert, obwohl das Problem dadurch nicht behoben wurde. –

Verwandte Themen