"Datenanalysen auf nem Mac."
=> Belastbare Erkenntnisse mittels Fakten liefern
=> Neue Erkenntnisse verständlich herausarbeiten
Data Science: Perfect match!
[(Daten + Code + Ergebnis) pro gedanklichen Schritt] + komplette Automatisierung
Schlüsselelement: Computational Notebooks
Meta-Ziel: Alles mal sehen anhand eines einfachen Show-Cases.
Unsere Heurisik: **Ändert** **ein Team** hauptsächlich Module?
In [1]:
from ozapfdis import git
log = git.log_numstat("../../../dropover/")
log.head(3)
Out[1]:
Was haben wir hier eigentlich?
In [2]:
log.info()
1 DataFrame (~ programmierbares Excel-Arbeitsblatt), 6 Series (= Spalten), 2403 Rows (= Einträge)
Wir machen nur mit Java-Produktionscode weiter
In [3]:
java = log.copy()
java = java[java['file'].str.startswith("backend/src/main/java")]
java = java[~java['file'].str.contains("package-info.java")]
java.head()
Out[3]:
Wir extrahiere Modulnamen aus den Dateinamen.
In [4]:
java['module'] = java['file'].str.split("/").str[6]
java.head()
Out[4]:
Wir ordnen bei uns Autoren zu Teams zu.
Schritt 1: Weitere Datenquelle einlesen.
In [5]:
import pandas as pd
orga = pd.read_excel("../dataset/Teamorganisation.xlsx", index_col=0)
orga
Out[5]:
Wir ordnen bei uns Committer zu Teams zu.
Schritt 2: Datenquellen joinen
In [6]:
java = java.join(orga, on='author')
java.head()
Out[6]:
Wir zählen die Änderungen aller Klassen pro Modul und Team.
In [7]:
changes = java.groupby(['module', 'team'])[['sha']].count()
changes.head()
Out[7]:
Wir berechnen alle erfolgten Änderungen pro Modul...
In [8]:
changes['all'] = changes.groupby('module').transform('sum')
changes.head()
Out[8]:
...und damit die Änderungsverhältnisse pro Team.
In [9]:
changes['ratio'] = changes['sha'] / changes['all']
changes.head()
Out[9]:
Wir bauen uns ein Balkendiagramm mit den Verhältnissen der Teamänderungen.
In [10]:
changes['ratio'].unstack().plot.bar(stacked=True);
Frage 2: Wie gut passt die Modularisierung zur Arbeitweise der Teams?
Unsere Heuristik: Werden fachliche Komponenten **zusammengehörig geändert**?
Unsere Ausgangsbasis
In [11]:
java.head()
Out[11]:
Wir zeigen für jeden Commit die geänderten Dateien.
In [12]:
java['changed'] = 1 # markiere Änderungen
commit_matrix = java.pivot('file', 'sha', 'changed').fillna(0)
commit_matrix.iloc[:5,50:55]
Out[12]:
Wir berechnen den Abstand zwischen den vorgenommmenen Commits pro Datei (=Vektor)...
In [13]:
from sklearn.metrics.pairwise import cosine_distances
dis_matrix = cosine_distances(commit_matrix)
dis_matrix[:5,:5]
Out[13]:
...und machen die Darstellung schöner...
In [14]:
class_name = commit_matrix.index.str.split("/").str[-1].str.split(".").str[0]
dis_df = pd.DataFrame(dis_matrix, class_name, class_name)
dis_df.iloc[:5,:2]
Out[14]:
Wir brechen nun die Matrix auf 2D herunter
In [15]:
from sklearn.manifold import MDS
model = MDS(dissimilarity='precomputed', random_state=0)
dis_2d = model.fit_transform(dis_df)
dis_2d_df = pd.DataFrame(dis_2d, commit_matrix.index, ["x", "y"])
dis_2d_df.head(3)
Out[15]:
Wir fügen eine Sicht auf die Module hinzu.
In [16]:
dis_2d_df['module'] = dis_2d_df.index.str.split("/").str[6]
dis_2d_df.head()
Out[16]:
Wir erzeugen uns eine interaktive Grafik.
Helferlein: An Unifying Software Integrator
In [17]:
from ausi import pygal
xy = pygal.create_xy_chart(dis_2d_df, "module")
xy.render_in_browser()
Unsere Heuristik: Wie würde sich das System rein nach seinen **Änderungen** strukturieren?
Unsere Ausgangsbasis
In [18]:
commit_matrix.iloc[:5,50:55]
Out[18]:
Wir nutzen hierarchisches Clustering, um anhand der Änderungsmuster alternative Modulestrukturen zu erkennen...
In [19]:
from sklearn.cluster import AgglomerativeClustering
clustering = AgglomerativeClustering()
model = clustering.fit(commit_matrix)
model
Out[19]:
...und visualisieren das Ergebnis.
In [20]:
from ausi.scipy import plot_dendrogram
plot_dendrogram(model, labels=commit_matrix.index)
https://upload.wikimedia.org/wikipedia/commons/thumb/7/71/062-exploding-head.svg/600px-062-exploding-head.svg.png
Oder auch: Softwarewelt -> Data Science Welt -> Softwarewelt
Markus Harrer
innoQ Deutschland GmbH
E-Mail: markus.harrer@innoq.com
Twitter: @feststelltaste
Blog: feststelltaste.de