Python (12.11.2019 - 14.11.2019 in Graz)¶
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
- 1
Ich hatte von Bildverarbeitung keine Ahnung