<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Datenanalyse I
Python hat u.a. einen sehr guten Ruf als Programmiersprache für die Datenanalyse. Das liegt unter anderem an diesen Bibliotheken
Step1:  Auch bei arrays greifen wir über den Index auf die Elemente zu
Step2:  numpy-arrays unterscheiden sich in einigen Punkten sehr deutlich von Pythons eingebauter Liste
Step3:  nd steht für n-dimensional
Step4:  Im folgenden werde ich anstatt von 1-dimensionalen Arrays auch von Vektoren sprechen und einen mehrdimensionalen Array als Matrix bezeichnen. Das sind mathematische Konzepte, die später noch ausführlicher erläutert werden. 
Erzeugen von numpy-Arrays
Es gibt mehrere Wege, wie man numpy-Arrays erzeugen kann
Step5:  2) Von einer Datei lesen, z.B. im HDF5 or FITS-format oder von csv-Dateien, deren Lesen von Pythons Standardbibliothek unterstützt wird,
Step6:  Die Parameter
Step7:  Bei einem Vektor erhalten wir nur eine Zahl, die die Länge des Vektors anzeigt. Im Fall einer Matrix erhalten wir n Zahlen, wobei n der Anzahl der Dimensionen der Matrix entspricht.
Aufgaben
1) Erzeugen Sie einen Vektor mit den Zahlen von 0-5 und fragen Sie seine Form ab.<br/>
2) Erzeugen Sie einen numpy-Array, der mit den Zahlen von 1-12 gefüllt ist und die Form 4x3 hat.
Indexing und Slicing
Wir können jedes Element eines numpy-Arrays ebenso adressieren wie bei einer python-Liste
Step8:  Oder auch  slicen
Step9:  Im Fall von zweidimensionalen Arrays funktioniert das ganz genau so
Step10:  Wir können Zeilen und Spalten aus einem Array herausschneiden. Hier die 2. Reihe
Step11:  Im folgenden Beispiel schneiden wir die 3. Spalte heraus
<img src="files/images/numpy_column.png" width=300>
Step12:  Wir können auf diese Weise offensichtlich auch Reihen und Spalten angeben, um einzelne Werte oder Wertgruppen herauszuschneiden. Im folgenden Beispiel schneiden wir den Wert heraus, der in der Zelle liegt, die durch die 2. Reihe und die 2. Spalte indexiert ist
Step13:  Aufgaben
1) Schneiden Sie die erste Reihe heraus<br/>
2) Schneiden Sie die letzte Spalte heraus (wie kann man das machen, wenn man die Anzahl der Spalten nicht kennt?<br/>
3) Schneiden Sie die Gruppe 17,45,13,22 heraus
Exkurs
Step14:  Mit der Funktion reshape() können wir einen Vektor oder eine Matrix umformen
Step15:  Das funktioniert nur, wenn die Gesamtlänge der alten Matrix auch genau die neue Matrix ausfüllt - sonst wird eine Exception geworfen.
Aufgabe
1) Legen Sie mit np.arange(start, stop[, step]) ein 1-dimensionales Array mit den Zahlen von 200 bis 1000 an.<br/>
2)Verfünffachen Sie alle Werte des Arrays. <br/>
3) Erzeugen Sie einen Vektor mit der Größe 100, der ungerade Zahlen beginnend bei 11 enthält.<br/>
4) Geben Sie die letzte Zahl des Vektors aus.<br/>
5) Erzeugen Sie eine Matrix der Form 40x 25 mit den Zahlen von 0-999 als Inhalt. <br/>
6) Lassen Sie sich die erste Zeile der Matrix anzeigen.<br/>
7) Geben die drei Spalten aus, die die Zahlen 150,151,152 enthalten - von Anfang an.  <br/>
Broadcasting
Ein weiterer Unterschied zwischen Python-Listen und numpy Arrays besteht darin, dass Arrays - im Gegensatz zu Python Listen - Vektorisierung und Broadcasting unterstützen. Will man z.B. zwei Python-Listen einfach multiplizieren, so könnte man versucht sein, folgendes zu schreiben
Step16:  Genau das aber kann man mit numpy Arrays machen
Step17:  Die Arrays werden elementweise multipliziert. Arrays verhalten sich also wie mathematische Vektoren.  
Wir können in Python zwar eine Liste mit einer Zahl multiplizieren, aber was dann passiert, ist folgendes
Step18:  Multipliziert man einen Vektor mit einem Skalar (also einer einzelnen Zahl), dann wird jeder Wert des Vektors multipliziert
Step19:  Unter Broadcasting versteht man generell das Verhalten aller Operationen, die stets elementweise angewandt werden.
Step20:  Wenn man Rohwerte einer Erhebung in einer Tabelle hat, dann besteht der erste Schritt oft darin, diese zu normalisieren. Nehmen wir an, die Werte oben stellen insgesamt die Anzahl der Worte in einem Text dar, dann würden wir die Werte so normalisieren, dass wir ausrechnen, wieviel Prozent Anteil das jeweilige Wort an der Gesamtheit hat.
Step21:  Man kann auch zwei Matrizen broadcasten, z.B.
Step22:  Dabei muss man allerdings beachten, dass die Länge der Dimension, immer gleich sind oder 1. Wenn eine der Dimensionen die Länge 1 hat und sie trifft auf eine längere, dann wird sie auf deren Länge erweitert.
Step23:  Das ist alles andere als einfach zu verstehen. Siehe "General Broadcasting Rules" im numpy-Handbuch. 
Aufgaben
1) Erzeugen Sie einen Array mit der Form 4 x 5, der mit den Zahlen der 4er Reihe (4,8,12 usw.) gefüllt ist. Normalisieren Sie die Daten, indem Sie sie durch die Summe teilen. <br/>
2) Finden Sie den höchsten Wert der Matrix und jeder Reihe.
Datentypen in Numpy Arrays
Numpy Arrays bestehen, wie oben erwähnt, aus Daten mit dem gleichen Datentypen. Arrays mit mehreren Datentypen nennt man strukturierte Arrays oder Records (s.u.). Man kann den Datentypen auch explizit angeben, (mit den bekannten Nebeneffekten)
Step24:  Außerdem gibt es noch
Step25:  Arrays mit nan oder anderen ungültigen Werten verhalten sich nicht wie gewohnt
Step26:  Um mit solchen Daten umzugehen, muss man ein Array maskieren. Das Bild entsteht daruch, dass man über alle Werte eine Maske legt, die an einigen Stellen die (unbrauchbaren) Werte so einkleidet, dass man trotzdem mit dem Array insgesamt rechnen kann
Step27:  Die Maske hat an den Stellen den Wahrheitswert True, wo der darunterliegende Wert die normalen Array-Operationen stören würde. Man kann übrigens, wenn man will, selbst entscheiden, wie die Maske aussieht. Siehe im numpy-Handbuch den Abschnitt 3.19 masked array operations.
Step28:  Aufgabe
1) Laden Sie die Daten aus der Datei missing.csv, maskieren Sie ungültige Werte und berechnen Sie die Summe der Zeilen.
Funktionales Programmieren mit Arrays
numpy bietet eine große Menge an Funktionen, die man mittels broadcasting auf Arrays anwenden lassen kann. Man kann aber auch in vergleichbarer Weise bzw. in einer Art, die an die Verwendung von map im funktionalen Programmieren erinnert, jede selbstgeschriebene Funktion auf numpy-Arrays anwenden. Dazu dient die Funktion np.apply_along_axis().  <br/>
np.apply_along_axis(func1d, axis, arr, *args)
<br/>Diese Funktion verarbeitet eine Matrix in der Weise, dass in der angegebenen Achse jeweils ein Vektor, also ein 1-dimensionaler Array, herausgeschnitten wird und mit der Funktion verarbeitet wird, d.h. die Funktion sollte als Input einen Vektor erwarten.
Step29:  Deskriptive Statistik
numpy bringt auch von Haus aus eine Reihe von Funktionen für die deskriptive Statistik mit. Ich gehe davon aus, dass die grundlegenden Konzepte noch aus der Schule bekannt sind (sonst bitte
Step30:  <b>Varianz</b><br/> 
Varianz ist ein Streumaß, das uns eine Einschätzung erlaubt, wie sehr die Daten vom Mittelwert abweichen. Offensichtlich haben die Datenreihen [6,6,6,6] und [1,11,2,10] den gleichen Mittelwert, aber eine ganz unterschiedliche Varianz. Berechnet wird die Varianz einer Population folgendermaßen
Step31:  <b>Standardabweichung</b> (standard deviation) <br/>
Die Standardabweichung ist die Wurzel aus der Varianz, hat also den Vorteil, dass ihre Einheit und Größenverhältnisse intuitiv einsichtig interpretierbar sind. 
$$
\sigma = \sqrt{\sum_{i=0}^n \frac {(\mu - x_i)^2} {n}}
$$
<ASSISTANT_TASK:>
Python Code:
#übliche Art und Weise numpy zu importieren
import numpy as np
a = np.array([1,2,3,4,5])
a
Explanation: Datenanalyse I
Python hat u.a. einen sehr guten Ruf als Programmiersprache für die Datenanalyse. Das liegt unter anderem an diesen Bibliotheken:
<ul>
<li>ipython</li>
<li>numpy</li>
<li>pandas</li>
<li>scipy</li>
<li>scikit.learn</li>
<li>matlpotlib</li>
</ul>
Wir werden uns dieser Sitzung vor allem numpy ansehen und in den nachfolgenden Sitzungen die anderen Bibliotheken.  
ipython
Sie benutzen ja schon ipython notebooks. ipython ist außerdem eine sehr viel komfortablere shell als idle. Schon allein das tab-completion (erste Buchstaben des Kommandos eingeben, dann auf Tab) ist sehr nützlich. 
Nützliche Kommandos:<br/>
%hist  -  Zeigt die history an, also alle bisher eingegebenen Befehle. Mit %hist -g "dir" suchen Sie nach allen Befehlszeilen, die den String dir enthalten. <br/>
%cd dir - wechselt ins Directory dir
numpy
numpy ist ein Modul, dass vor allem eine sehr effiziente und schnelle Datenstruktur zur Verfügung stellt sowie eine ganze Reihe von Funktionen, um die Daten zu bearbeiten oder auszuwerten. Die Datenstruktur, die im Zentrum steht, ist ein Array, also eine Art Liste. In der einfachsten Form können wir Arrays so ähnlich wie Python-Listen verwenden:
End of explanation
a[3]
Explanation: Auch bei arrays greifen wir über den Index auf die Elemente zu:
End of explanation
type(a)
Explanation: numpy-arrays unterscheiden sich in einigen Punkten sehr deutlich von Pythons eingebauter Liste:
<ul>
<li>numpy Arrays haben bei der Erzeugung eine festgelegte Größe. Verändert man das Array wird eine neue Kopie angelegt und die alte verworfen. </li>
<li>Alle Elemente des Arrays müssen denselben Datentyp haben. </li>
<li>numpy Arrays sind dazu ausgelegt, mehrdimensional verwendet zu werden:</li>
End of explanation
#wir erzeugen einen zweidimensionalen Array
b = np.array([[1,2,3],[4,5,6]])
b
Explanation: nd steht für n-dimensional
End of explanation
x = np.array((1, 3, 6, 7.1, 8.55, 2.94))
x
Explanation: Im folgenden werde ich anstatt von 1-dimensionalen Arrays auch von Vektoren sprechen und einen mehrdimensionalen Array als Matrix bezeichnen. Das sind mathematische Konzepte, die später noch ausführlicher erläutert werden. 
Erzeugen von numpy-Arrays
Es gibt mehrere Wege, wie man numpy-Arrays erzeugen kann:
1) Aus einer Python-Datenstruktur, z.B. einer Liste (wie oben) oder einem Tuple:
End of explanation
#schauen wir uns die Datei einmal mit Python's Bordmitteln an:
import csv
with open('inutzung.csv') as f:
    reader = csv.reader(f)
    for l in reader:
        print(l)
#und so laden wir sie in numpy:
data = np.genfromtxt("inutzung.csv", delimiter=",", skiprows=1, usecols=(range(1,6)))
data
Explanation: 2) Von einer Datei lesen, z.B. im HDF5 or FITS-format oder von csv-Dateien, deren Lesen von Pythons Standardbibliothek unterstützt wird,
End of explanation
a
np.shape(a)
b = np.array([[38,19,35,32, 41], [39,22,22,33,34], [28,34,28,17,45], [12,23,49,13,22]])
b
np.shape(b)
Explanation: Die Parameter:<br/>
delimiter - Welches Zeichen trennt die Felder einer Reihe in der csv-Datei<br/>
skiprows  - Welche Zeilen übersprungen werden sollen, falls die Datei wie hier Kolumnentitel enthält<br/>
usecols  -  Welche Spalten sollen verwendet werden. Kann man weglassen, wenn alles geladen werden soll. Hier können wir die erste nicht gebrauchen.<br/>
Gestalt eines Arrays
Ein Array hat soviele Achsen wie er Dimensionen hat. Bei manchen Operationen werden wir die Information, welche Achse nun behandelt werden soll, angeben müssen. Hier das Beispiel eines zweidimensionalen Arrays:
<img src="/files/images/numpy_array.png" width=300>
Unter 'Form' der Matrix versteht man die Anzahl der Zellen in die jeweilige Richtung der Achse. Die Form kann man mit dem Befehl shape abfragen:
End of explanation
a = np.array([1,2,3,4,5,6,7,8,9])
a[0]
Explanation: Bei einem Vektor erhalten wir nur eine Zahl, die die Länge des Vektors anzeigt. Im Fall einer Matrix erhalten wir n Zahlen, wobei n der Anzahl der Dimensionen der Matrix entspricht.
Aufgaben
1) Erzeugen Sie einen Vektor mit den Zahlen von 0-5 und fragen Sie seine Form ab.<br/>
2) Erzeugen Sie einen numpy-Array, der mit den Zahlen von 1-12 gefüllt ist und die Form 4x3 hat.
Indexing und Slicing
Wir können jedes Element eines numpy-Arrays ebenso adressieren wie bei einer python-Liste:
End of explanation
a[:3]
a[1:7:2]
Explanation: Oder auch  slicen: array[start:stop:step]
End of explanation
b = np.array([[38,19,35,32, 41], [39,22,22,33,34], [28,34,28,17,45], [12,23,49,13,22]])
b
Explanation: Im Fall von zweidimensionalen Arrays funktioniert das ganz genau so: array[start:stop:step,start:stop:step]
End of explanation
#hier kann man den Doppelpunkt auch weglassen
b[1,:]
Explanation: Wir können Zeilen und Spalten aus einem Array herausschneiden. Hier die 2. Reihe:
<img src="files/images/numpy_row.png" width=300/>
End of explanation
#der Doppelpunkt ist notwendig - wir wollen ja alle Werte über die Reihen
b[:,2]
Explanation: Im folgenden Beispiel schneiden wir die 3. Spalte heraus
<img src="files/images/numpy_column.png" width=300>
End of explanation
b[2,2]
Explanation: Wir können auf diese Weise offensichtlich auch Reihen und Spalten angeben, um einzelne Werte oder Wertgruppen herauszuschneiden. Im folgenden Beispiel schneiden wir den Wert heraus, der in der Zelle liegt, die durch die 2. Reihe und die 2. Spalte indexiert ist:
<img src="files/images/numpy_row+columns.png" width=300>
End of explanation
c = np.arange(2,22,2)
c
Explanation: Aufgaben
1) Schneiden Sie die erste Reihe heraus<br/>
2) Schneiden Sie die letzte Spalte heraus (wie kann man das machen, wenn man die Anzahl der Spalten nicht kennt?<br/>
3) Schneiden Sie die Gruppe 17,45,13,22 heraus
Exkurs: Arange und reshape
Mit dem Befehl np.arange(n) können wir einen Vektor erzeugen, der mit 0 bis n gefüllt wird (Die Befehl funktioniert ähnlich wie range, d.h. man kann Anfangswerte setzen oder auch Schrittweiten.
End of explanation
c.reshape(2,5)
b
b.reshape(4,3)
Explanation: Mit der Funktion reshape() können wir einen Vektor oder eine Matrix umformen:
End of explanation
a = [1,2,3]
b = [4,5,6]
#a * b
Explanation: Das funktioniert nur, wenn die Gesamtlänge der alten Matrix auch genau die neue Matrix ausfüllt - sonst wird eine Exception geworfen.
Aufgabe
1) Legen Sie mit np.arange(start, stop[, step]) ein 1-dimensionales Array mit den Zahlen von 200 bis 1000 an.<br/>
2)Verfünffachen Sie alle Werte des Arrays. <br/>
3) Erzeugen Sie einen Vektor mit der Größe 100, der ungerade Zahlen beginnend bei 11 enthält.<br/>
4) Geben Sie die letzte Zahl des Vektors aus.<br/>
5) Erzeugen Sie eine Matrix der Form 40x 25 mit den Zahlen von 0-999 als Inhalt. <br/>
6) Lassen Sie sich die erste Zeile der Matrix anzeigen.<br/>
7) Geben die drei Spalten aus, die die Zahlen 150,151,152 enthalten - von Anfang an.  <br/>
Broadcasting
Ein weiterer Unterschied zwischen Python-Listen und numpy Arrays besteht darin, dass Arrays - im Gegensatz zu Python Listen - Vektorisierung und Broadcasting unterstützen. Will man z.B. zwei Python-Listen einfach multiplizieren, so könnte man versucht sein, folgendes zu schreiben:
End of explanation
a = np.array([1,2,3])
b = np.array([4,5,6])
a * b
Explanation: Genau das aber kann man mit numpy Arrays machen:
End of explanation
c = 3
a * c
Explanation: Die Arrays werden elementweise multipliziert. Arrays verhalten sich also wie mathematische Vektoren.  
Wir können in Python zwar eine Liste mit einer Zahl multiplizieren, aber was dann passiert, ist folgendes: die Liste wird entsprechend oft wiederholt
End of explanation
b = np.array([3])
a * b
Explanation: Multipliziert man einen Vektor mit einem Skalar (also einer einzelnen Zahl), dann wird jeder Wert des Vektors multipliziert:
End of explanation
#wir erzeugen eine Matrix
d = np.arange(0,21).reshape(7,3)
d
#wir können nun mit einem Befehl alle Elemente der Matrix verändern, z.B.:
d * 5
#führen wir noch eine einfache Funktion ein:
d.sum()
Explanation: Unter Broadcasting versteht man generell das Verhalten aller Operationen, die stets elementweise angewandt werden.
End of explanation
dsum = d / d.sum()
#test! :-)
dsum.sum()
Explanation: Wenn man Rohwerte einer Erhebung in einer Tabelle hat, dann besteht der erste Schritt oft darin, diese zu normalisieren. Nehmen wir an, die Werte oben stellen insgesamt die Anzahl der Worte in einem Text dar, dann würden wir die Werte so normalisieren, dass wir ausrechnen, wieviel Prozent Anteil das jeweilige Wort an der Gesamtheit hat.
End of explanation
a = np.array([[1,2,3],[4,5,6]])
b = np.array([7,8,9])
a * b
Explanation: Man kann auch zwei Matrizen broadcasten, z.B.:
End of explanation
a = np.array([[1,2,3],[4,5,6]])
b = np.array([7,8,9,10])
#erzeugt einen Fehler
#a * b
b = np.arange(3).reshape(1, 3)
b
a * b
Explanation: Dabei muss man allerdings beachten, dass die Länge der Dimension, immer gleich sind oder 1. Wenn eine der Dimensionen die Länge 1 hat und sie trifft auf eine längere, dann wird sie auf deren Länge erweitert.
End of explanation
c = np.array([1.2,2.3,3.4], dtype=int)
c
c.dtype
c = np.array([1.2,2.3,3.4])
c.dtype
Explanation: Das ist alles andere als einfach zu verstehen. Siehe "General Broadcasting Rules" im numpy-Handbuch. 
Aufgaben
1) Erzeugen Sie einen Array mit der Form 4 x 5, der mit den Zahlen der 4er Reihe (4,8,12 usw.) gefüllt ist. Normalisieren Sie die Daten, indem Sie sie durch die Summe teilen. <br/>
2) Finden Sie den höchsten Wert der Matrix und jeder Reihe.
Datentypen in Numpy Arrays
Numpy Arrays bestehen, wie oben erwähnt, aus Daten mit dem gleichen Datentypen. Arrays mit mehreren Datentypen nennt man strukturierte Arrays oder Records (s.u.). Man kann den Datentypen auch explizit angeben, (mit den bekannten Nebeneffekten):
End of explanation
data = np.genfromtxt("missing.csv")
data
data = np.genfromtxt("missing.csv", filling_values=0)
data
Explanation: Außerdem gibt es noch: bool (für Wahrheitswerte), complex (für komplexe Zahlen) u.a.m.
3) Legen Sie ein Array mit den graden Zahlen von 1-10 an. Teilen Sie alle Werte durch 3 und legen das Ergebnis in einem neuen Array an
Structured Arrays / Records
Numpy unterstützt auch strukturierte Arrays, die es erlauben Spalten- und Zeilentitel zu behalten. Wir werden für diese Daten vor allem pandas verwenden. 
NA
Wirkliche Daten sind oft schmutzig und nicht durchgehend einheitlich. 
Der Inhalt der Datei missing.csv sieht so aus:
<table>
<tr><td>12</td> <td>3</td>  <td>10</td> <td>6   </td></tr>
<tr><td>10</td> <td>n/a</td>    <td>12</td> <td>8</td></tr>
<tr><td></td>   <td>7</td>  <td>10</td> <td>9</td></tr>
<tr><td>11</td> <td>9</td>  <td>12</td> <td>4</td></tr>
</table>
In der zweitn Zeile ist anstelle eines Wertes n/a notiert; in der dritten Zeile fehlt der erste Wert ganz. Wenn man solche Dateien einfach so importiert, wird der fehlende und der falsche Wert als nan (not a number) notiert. (Wenn überhaupt kein Wert in der Datei steht, also auch keine leeren Anführungszeichen, dann wirft die Funktion übrigens eine Exception):
End of explanation
data.sum()
for i in data:
    print(i.sum())
Explanation: Arrays mit nan oder anderen ungültigen Werten verhalten sich nicht wie gewohnt:
End of explanation
import numpy.ma as ma
masked_data = ma.fix_invalid(data)
masked_data
Explanation: Um mit solchen Daten umzugehen, muss man ein Array maskieren. Das Bild entsteht daruch, dass man über alle Werte eine Maske legt, die an einigen Stellen die (unbrauchbaren) Werte so einkleidet, dass man trotzdem mit dem Array insgesamt rechnen kann:
End of explanation
masked_data.sum()
for i in masked_data:
    print(i.sum())
Explanation: Die Maske hat an den Stellen den Wahrheitswert True, wo der darunterliegende Wert die normalen Array-Operationen stören würde. Man kann übrigens, wenn man will, selbst entscheiden, wie die Maske aussieht. Siehe im numpy-Handbuch den Abschnitt 3.19 masked array operations.
End of explanation
def simple_mean(a):
    return a.sum() /len(a)
a = np.array([[1,4,2,7,5], [3,1,4,6,3], [6,1,4,2,4]])
print(a)
np.apply_along_axis( simple_mean,axis=0,arr=a)  #axis u arr kann man natürlich weglassen, hier zur Erläuterung
#Im folgenden Beispiel wird die Axis auf 1 gesetzt:
np.apply_along_axis( simple_mean,axis=1,arr=a)
#wir können so auch numpy Funktionen auf Arrays anwenden
g = np.array([2,12,5,2,4,9])
print(np.max(g))
print(np.max(a))
np.apply_along_axis(np.max,axis=0,arr=g)
Explanation: Aufgabe
1) Laden Sie die Daten aus der Datei missing.csv, maskieren Sie ungültige Werte und berechnen Sie die Summe der Zeilen.
Funktionales Programmieren mit Arrays
numpy bietet eine große Menge an Funktionen, die man mittels broadcasting auf Arrays anwenden lassen kann. Man kann aber auch in vergleichbarer Weise bzw. in einer Art, die an die Verwendung von map im funktionalen Programmieren erinnert, jede selbstgeschriebene Funktion auf numpy-Arrays anwenden. Dazu dient die Funktion np.apply_along_axis().  <br/>
np.apply_along_axis(func1d, axis, arr, *args)
<br/>Diese Funktion verarbeitet eine Matrix in der Weise, dass in der angegebenen Achse jeweils ein Vektor, also ein 1-dimensionaler Array, herausgeschnitten wird und mit der Funktion verarbeitet wird, d.h. die Funktion sollte als Input einen Vektor erwarten.
End of explanation
data = np.array([34, 12, 77, 90, 34, 67, 52])
np.mean(data)
Explanation: Deskriptive Statistik
numpy bringt auch von Haus aus eine Reihe von Funktionen für die deskriptive Statistik mit. Ich gehe davon aus, dass die grundlegenden Konzepte noch aus der Schule bekannt sind (sonst bitte: Wikipedia!).  
<b>Mittelwert</b> (mean)<br/>
Der Mittelwert ist ein Zentralitätsmaß und soll einen Eindruck vermitteln, wo der Mittelpunkt der Datenreihe ist. In der Praxis wichtiger ist der Mittelwert allerdings als Faktor in anderen Maßen, z.B. in der Standardabweichung, oder als Information im Rahmen eines Boxplots. Berechnet wird der Mittelwert folgendermaßen:
$$
\mu = \sum_{i=0}^n \frac {x_i} {n}
$$
Wobei: <br/>
i - der Indexwert des Datenpunkts ist, x<sub>0</sub> ist also der Wert des ersten Datenpunkts usw.<br/>
n - die Anzahl der Datenpunkte
End of explanation
np.var(data)
a = [6,6,6,6] 
b = [1,11,2,10]
print("Mittelwert a: ", np.mean(a))
print("Mittelwert b: ", np.mean(b))
print("Varianz a: ", np.var(a))
print("Varianz b: ", np.var(b))
Explanation: <b>Varianz</b><br/> 
Varianz ist ein Streumaß, das uns eine Einschätzung erlaubt, wie sehr die Daten vom Mittelwert abweichen. Offensichtlich haben die Datenreihen [6,6,6,6] und [1,11,2,10] den gleichen Mittelwert, aber eine ganz unterschiedliche Varianz. Berechnet wird die Varianz einer Population folgendermaßen:
$$
v = \sum_{i=0}^n \frac {(\mu - x_i)^2} {n}
$$
Die Quadrierung der Werte ist notwendig, um zu vermeiden, dass sich positive und negative Werte gegenseitig aufwiegen. Allerdings erschwert die Quadrierung die Interpretation einer Varianz (Wenn wir die Varianz der Körpergröße gemessen in cm anschauen, dann haben wir einen Wert in Quadratzentimeter vor uns...), außerdem sind die Werte recht groß.
End of explanation
np.std(data)
print("Mittelwert a und b: ", np.mean(a))
print("Standardabweichung a: ", np.std(a))
print("Standardabweichung b: ", np.std(b))
Explanation: <b>Standardabweichung</b> (standard deviation) <br/>
Die Standardabweichung ist die Wurzel aus der Varianz, hat also den Vorteil, dass ihre Einheit und Größenverhältnisse intuitiv einsichtig interpretierbar sind. 
$$
\sigma = \sqrt{\sum_{i=0}^n \frac {(\mu - x_i)^2} {n}}
$$
End of explanation
<END_TASK>