Python (12.11.2019 - 14.11.2019 in Graz)¶
Eine Einführung in Python und NumPy, zur Beantwortung der Frage, “Ist die Herrschaft von MATLAB absolut?”. Gestellt von einer Firma aus dem Raum Graz, gehalten in den Schulungsräumen von tecTrain (Graz), über die der Kurs gebucht wurde. Platzhirsche sind schwer zu schlagen, haben wir herausgefunden, aber Python ist auf einem sehr guten Weg. Spass hatten wir allemal.
“Die Schulung war unglaublich lustig und hat mir einen sehr guten Überblick über Python vermittelt, ich habe gelernt wie ich es auf für mich relevante Probleme anwende und was es dabei zu beachten gilt.
Zudem war der Kursleiter sehr sympathisch und kompetent. Ich würde es also jederzeit weiterempfehlen bzw. wiederholen.”
Danke Christoph, sowas nettes hat noch nie jemand zu mir gesagt!
Standardthemen¶
Die Datentypen, und das “Normale” an Python waren schnell erklärt. Ich kanns nicht lassen, bevor die Anfängerthemen vorbei sind, auf dem Besten von Python herumzureiten: Iteration und Generatoren. Hier hatte ich eine kleine Demo gehackt - zum x-ten mal. Das ganze Fibonacci-Zeug gibts jetzt als Live-Hacking-Screenplay
Das Hauptthema: Numerik, NumPy¶
Siehe dazu auch ein Jupyter Notebook “BigPlan”
(download
).
Der Chef hat mir bei einem Vorgespräch ein Übungsbeispiel für die Teilnehmer mitgegeben: ausgehend von einem Spektralbild (sagt man so?), verwende den K-Means Clusteringalgorithmus, um die Bereiche auf dem Bild zu kategorisieren (die abgebildeten Stücke zu erkennen).
Ich hab mir erlaubt, für die Kursvorbereitung [1] so quasi als Appetizer das Problem etwas zu reduzieren: Farbreduktion eines Bildes (auf 8 Farben). Das Programm (siehe unten) verwendet
Pillow, um Bilddaten zu lesen und schreiben. Die Library interoperiert nahtlos mit NumPy, was sicher kein Zufall ist.
NumPy, um die Alpha-Plane des Ausgangsbildes abzuschneiden und zu restoren.
Den K-Means Algorithmus aus scikit-learn, um das Clustering jemand anders machen zu lassen.
Das Programm ist überschaubar - es verwendet nur Libraries und macht
nichts selbst (das ist der Plan, immer, beim Programmieren). Die
Ausdrucksstärke von Python macht sich hier bemerkbar durch z.B. die
Slice-Syntax (wegschneiden der Alpha-Plane), oder beim Iterieren
mittels enumerate()
.
#!/usr/bin/env python
import numpy
import PIL.Image
from sklearn.cluster import KMeans
import sys
img = PIL.Image.open('veggie.png')
imgarray = numpy.array(img)
nrows, ncols, nrgba = imgarray.shape
# disregard alpha plane for clustering
alpha = imgarray[:,:,3:]
rgb = imgarray[:,:,0:3]
# change view to a linear sequence of (r,g,b) points. (K-Means cannot
# take arbitrarily dimensioned spaces, he likes it linear.)
linear_rgb = rgb.reshape((nrows*ncols, 3))
km = KMeans(n_clusters=8)
km.fit(linear_rgb)
# reduce: let cluster centers be their members
for idx, label in enumerate(km.labels_):
linear_rgb[idx] = km.cluster_centers_[label]
# stack saved alpha plane on top of it
imgarray = numpy.concatenate((rgb, alpha), axis=2)
reduced_img = PIL.Image.fromarray(imgarray, 'RGBA')
reduced_img.save('veggie-reduced.png')
Lesen von .mat
Files¶
Das Spektralbild liegt im .mat
Format vor - was immer das ist, hat
wahrscheinlich mit MATLAB zu tun. Etwas Recherche hat ergeben, dass
die Funktion
scipy.io.loadmat()
das kann. Hier ein kleines Testprogramm,
#!/usr/bin/python
from scipy.io import loadmat
import sys
mat = loadmat(sys.argv[1])
print(type(mat['imnData']))
print(mat['imnData'])
print(mat['imnData'].dtype)
# obviously "imnData" is what we want
data = mat['imnData']
# ...
Lösen einer Uni-Übung¶
Eine Teilzeitmitarbeiterin der Firma, sie studiert Physik neben der Arbeit, muss für eine Übung … was weiss ich … machen. Wie auch immer, der Input für ihre Arbeit liegt in folgendem bekackten Inputformat vor, das es zu parsen gilt. War eine nette Zwischendurch-Gruppenarbeit.
---------------------------- Atom information ----------------------------
atom # X Y Z mass
--------------------------------------------------------------------------
O 1 0.0000000E+00 0.0000000E+00 -1.2662399E-01 1.5994910E+01
H 2 1.4391972E+00 0.0000000E+00 1.0048070E+00 1.0078250E+00
H 3 -1.4391972E+00 0.0000000E+00 1.0048070E+00 1.0078250E+00
--------------------------------------------------------------------------
--------------------------------------------------------
MASS-WEIGHTED PROJECTED HESSIAN (Hartree/Bohr/Bohr/Kamu)
--------------------------------------------------------
1 2 3 4 5 6 7 8 9
----- ----- ----- ----- -----
1 4.05054E+01
2 -1.61610E-24 0.00000E+00
3 1.20781E-07 8.08051E-25 2.83024E+01
4 -8.06829E+01 4.42629E-24 -4.65256E+01 3.52600E+02
5 -7.69570E-24 0.00000E+00 2.91733E-24 2.04388E-23 0.00000E+00
6 -6.34292E+01 8.04780E-25 -5.63758E+01 2.19019E+02 6.41217E-24 2.11622E+02
7 -8.06829E+01 3.21912E-24 4.65256E+01 -3.11752E+01 1.04198E-23 3.36702E+01 3.52600E+02
8 -8.14839E-24 0.00000E+00 2.71613E-24 1.96373E-23 8.40456E-19 7.21369E-24 1.24236E-23 0.00000E+00
9 6.34292E+01 -1.60956E-24 -5.63758E+01 -3.36702E+01 -1.84350E-23 1.29686E+01 -2.19019E+02 -1.92365E-23 2.11622E+02
Der Code, mit dem wir nach einigen Runden Nachdenkens einigermaßen zufrieden waren, sieht so aus,
import numpy as np
def load_dat(filename):
'''load a .dat file (whatever that is) into a numpy matrix and returns
that matrix.
'''
matrix_lines = []
with open(filename) as f:
for line in f:
if '----- ----- ----- ----- -----' in line:
matrix_lines = f.readlines()
break
else:
raise RuntimeError('file format vergeigt')
# split matrix_lines into elements
matrix_elements = []
for l in matrix_lines:
if len(l.strip()) == 0:
continue
elems = l.split()
del elems[0] # line-number column, unnecessary
matrix_elements.append(elems)
# determine dimensions of (triangular?) matrix
x = len(matrix_elements)
y = max((len(l) for l in matrix_elements))
matrix = np.zeros((x,y))
for row_no, row in enumerate(matrix_elements):
matrix[row_no,0:len(row)] = row
return matrix
if __name__ == '__main__':
print(load_dat(sys.argv[1]))
Footnotes