# Ceci est le début d'une session Python gérée à l'aide d'un calepin.
# Le script est divisé en cellules avec généralement l'affichage d'au plus un résultat par cellule.
## Importer les librairies nécessaires 
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from pylab import *
import os 
## Définir si nécessaire le répertoire courant spécifique 
##  à l'utilisateur
os.chdir(r'.')
## Commande magique pour obtenir les graphiques dans le calepin
%matplotlib inline

#%% Créer un data frame avec pandas
data = pd.DataFrame({
    'Gender': ['f', 'f', 'm', 'f', 'm', 'm', 'f', 'm', 'f', 'm'],
    'TV': [3.4, 3.5, 2.6, 4.7, 4.1, 4.0, 5.1, 4.0, 3.7, 2.1]})
data

# Génération de variables aléatoires gaussiennes
xx = randn(100,100)
y = mean(xx,0)
# graphique
plot(y)
show()

"""
Explanation: <center>
<a href="http://www.insa-toulouse.fr/" ><img src="http://www.math.univ-toulouse.fr/~besse/Wikistat/Images/logo-insa.jpg" style="float:left; max-width: 120px; display: inline" alt="INSA"/></a> 
<a href="http://wikistat.fr/" ><img src="http://www.math.univ-toulouse.fr/~besse/Wikistat/Images/wikistat.jpg" style="float:right; max-width: 250px; display: inline"  alt="Wikistat"/></a>
</center>
<a href="https://www.python.org/"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Python_logo_and_wordmark.svg/390px-Python_logo_and_wordmark.svg.png" style="max-width: 200px; display: inline" alt="Python"/></a> pour Statistique et Science des Données
Introduction à <a href="https://www.python.org/"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Python_logo_and_wordmark.svg/390px-Python_logo_and_wordmark.svg.png" style="max-width: 150px; display: inline" alt="Python"/></a> pour Calcul Scientifique - Statistique
Résumé Présentation de pyhton, exécution de commandes interactives ou de scripts avec un IDE, utilisation d'un calepin; les types et structures élémentaires de données, les structures de contrôle, les fonctions, classes et modules. Introduction à l'utilisation des librairies scientifiques: Numpy, Matplotlib, Scipy et au type array.
1 Introduction
1.1 Prérequis
Ce calepin introduit le langage libre Python et décrit les premières commandes nécessaires au pré-traitement des données avant l'utilisation de méthodes statistiques avec ce langage ou avec R. Les aspects statistiques développés dans les différentes vignettes de Wikistat sont supposés acquis ainsi qu'une connaissance des principes élémentaires de programmation dans un langage matriciel comme R ou Matlab. 
Pour des approfondissements, il existe de très nombreuses ressources pédagogiques accessibles sur la toile dont le tutoriel officiel de Python 3.4., les sites pythontutor.com, courspython.com, le livre de Sheppard (2014) qui présentent une introduction à Python pour l'\'Econométrie et la Statistique et celui de Mac Kinney (2013), principal auteur de la bibliothèque pandas. 
1.2 Installation
Python et ses librairies peuvent être installés dans quasiment tout environnement matériel et système d'exploitation à partir du site officiel. Voici les principales librairies scientifiques définissant des structures de données et fonctions de calcul indispensables. 
- ipython: pour une utilisation interactive de Python, 
- numpy: pour utiliser vecteurs et tableaux, 
- scipy: intègre les principaux algorithmes numériques, 
- matplotlib: pour les graphes, 
- pandas: structure de données et feuilles de calcul, 
- patsy: formules statistiques,
- statsmodels: modélisation statistique,
- seaborn: visualisation de données,
- scikit-learn: algorithmes d'apprentissage statistique.
Néanmoins, compte tenu de la complexité de l'opération, il est plus simple pour le néophyte, surtout sous Windows, de faire appel à une procédure d'installation intégrant les principales librairies. Ces procédures sont développées par des entreprises commerciales mais libres de droits pour une utilisation académique.
- Continuum Analytics propose Anaconda avec au choix la version 3.4 ou celle 2.7. Conda est l'utilitaire (commande en ligne) qui permet les mises à jour et installations des librairies complémentaires.
- Enthought propose Canopy qui n'installe pour le moment que la version 2.7 et intègre un package manager avec interface graphique. Attention, certaines librairies même "collectives" ne sont disponibles que dans la version commerciale ou celle "académique" de Canopy après inscription. 
D'un point de vue légal, les propositions sont identiques mais Canopy nécessite la création d'un compte académique. Seul "souci", ces versions n'incluent que les versions dites stables des différentes librairies et donc avec un temps de retard vis-à-vis des versions encore développement.
C'est Anaconda qui est utilisée ici, car préférable pour un poste personnel, en version 2.7; C'est aussi la version installée par le CSN de l'INSA dans les salles de TP.
2 Utilisation de Python
Python exécute programmes ou scripts, programmes qui peuvent être pré-compilés pour plus d'efficacité. Ce langage s'exécute également à l'aide d'un interprète de commande (IDLE) ou {IPython) de manière interactive.  En situation pédagogique, c'est l'utilisation et la réalisation d'un notebook Ipython (calepin) ou plutôt maintenant Jupyter qui est privilégiée à partir d'un simple navigateur (éviter internet explorer).
2.1 Calepin Jupyter
Les commandes sont regroupées dans des cellules suivies de leur résultat après exécution. Ces résultats et commentaires sont  stockés dans un fichier spécifique .ipynb et sauvegardés. Les commandes LaTeX sont acceptées pour intégrer des formules, la mise en page est assurée par des balises HTML ou Markdown. 
La commande de sauvegarde permet également d'extraire les seules commandes Python dans un fichier d'extension .py. C'est une façon simple et efficace de conserver tout l'historique d'une analyse pour en faire une présentation ou créer un tutoriel. Le calepin peut être en effet chargé  sous un autre format: page html, fichier .pdf ou diaporama.
Le projet Jupyter propose cet environnement de calepin pour beaucoup de langages (Pyhton, Julia, Scala...) dont R. Il devient un outil indispensable pour assurer simplement la reproductibilité des analyses. 
L'ouverture d'un navigateur sur un calepin (Ipython ou Jupyter) est obtenu, selon l'installation,  à partir des menus ou en exécutant: 
jupyter notebook
ou 
ipython notebook 
dans une fenêtre de commande.
Une fois le calepin ouvert, 
- Entrer des commandes Python dans une cellule,
- Cliquer sur le bouton d'exécution de la cellule.
- Ajouter une ou des cellules de commentaires et balises HTML ou Markdown.
Itérer l'ajout de cellules. Une fois l'exécution terminée:
- Sauver le calepin .ipynb 
- Charger éventuellement une version .html pour une page web.
- Charger le fichier .py regroupant les commandes python pour une version opérationnelle.
Attention Un calepin de IPython ou Jupyter est un outil de travail exploratoire efficace et un compte rendu nécessairement chronologique d'exécution; ce n'est pas le rapport d'une étude statistique dont l'organisation suit des règles spécifiques. 
2.2 IDE  Spyder
Pour la réalisation d'applications et programmes plus complexes, l'usage d'un IDE (integrated Development Environment) libre comme Spyder est recommandé. Ce dernier est intégré à la distribution Anaconda et sa présentation  proche de celles de Matlab ou RStudio. Cet environnement exécutant IPython reconnaît évidemment les commandes précédentes. 
Comme pour RStudio, Spider ouvre plusieurs fenêtres:
- un éditeur de commandes dont les boutons du menu exécutent tout le fichier ou interactivement la cellule courante, sauvent le fichier, contrôlent le débogage. Une cellule débute par la balise: #%%.
- Un explorateur d'objets avec aide en ligne, des variables en cours, du répertoire courant. Les boutons de l'explorateur de variables permettent de supprimer, sauver les objets créés ou encore d'importer des données.
- La console IPython avec les résultats et son historique.
2.3 Exemple
En résumé, utiliser un calepin pour des analyses exploratoires élémentaires et un IDE Spyder ou Eclipse (un peu compliqué!) pour la construction de programmes et modules. 
Selon l'installation et à partir du répertoire de travail, exécuter la commande:
jupyter notebook 
qui ouvre le navigateur par défaut. 
Sur les postes géré par le CSN de l'INSA, si cela ne marche pas, il peut être nécessaire d'ajouter une variable d'environnement:
export PATH=/usr/local/insa/anaconda/bin:$PATH
Entrer les commandes ci-dessous dans le calepin et les exécuter cellule par cellule en cliquant sur le bouton d'exécution de la cellule courante.
End of explanation
"""


a=3  # est un entier
b=1. # est un flottant
# Attention:
a/2  # a pour résultat 1.5 en Python 3.4 
     # mais 1 en 2.7

"""
Explanation: 3. Types de données
3.1 Scalaires et chaînes
La déclaration des variables est implicite ({integer, float, boolean, string), la syntaxe est très proche de celle de R mais il n'y a pas de type factor.
End of explanation
"""


# Comparaison
a==b  

#  affichage et type des variables
type(a)

# Chaîne de caractère
a='bonjour '
b='le '
c='monde'
a+b+c

"""
Explanation: Opérateurs de comparaison : ==, &gt;, &lt;, != de résultat booléen.
End of explanation
"""


a=u'bonjour' # encodage utf-8
type(a)

a='bonjour'  # encodage ascii
type(a)

"""
Explanation: Attention à l'encodage des caractères. Ce n'est pas le même en python 2 (ascii) et python 3 (utf-8). Ce n'est pas fait dans ces exemples élémentaires mais il est vivement recommander de gérer systématiquement des textes complexes avec caractères spéciaux (accents, guillements...) en utf-8
End of explanation
"""


# exemples de listes
liste_A = [0,3,2,'hi']
liste_B = [0,3,2,4,5,6,1]
liste_C = [0,3,2,'hi',[1,2,3]]    
# Elément d'une liste 
liste_A[1]

liste_C[-1] #  dernier élément

liste_C[-1][0]

liste_C[-2]

liste_B[0:2] #  Sous-liste

liste_B[0:5:2]  # début:fin:pas

liste_B[::-1]

# Fonctions de listes
List=[3,2,4,1]
List.sort() 
print(List)

List.append('hi')
print(List)

List.count(3) 

List.extend([7,8,9])
print(List)

List.append([10,11,12])
print(List)

"""
Explanation: 3.2 Structures de base
Listes
Les listes permettent des combinaisons de types. 
Attention, le premier élément d'une liste ou d'un tableau est indicé par 0, pas par 1.
End of explanation
"""


MyTuple=(0,3,2,'h')
MyTuple[1]

MyTuple[1]=10 # TypeError: "tuple" object

"""
Explanation: t-uple
Un tuple est similaire à une liste mais ne peut être modifié, il est défini par des parenthèses.
End of explanation
"""


months = {'Jan':31 , 'Fev': 28, 'Mar':31}
months['Jan'] 	

months.keys()

months.values()

months.items()

"""
Explanation: Dictionnaire
Un dictionnaire est similaire à une liste mais chaque entrée est assignée par une clé / un nom, il est défini avec des accolades. Cet objet est utilisé pour la construction de l'index des colonnes (variables) du type DataFrame de la librairie pandas.
End of explanation
"""


# si alors sinon
a=2
if a>0:
    b=0
    print(b)
else:
    b=-1
print(b)

"""
Explanation: 4. Syntaxe de Python
4.1 Structures de contrôle élémentaires
Un bloc de commandes ou de codes est défini par deux points suivis d'une indentation fixe.  Cela oblige à l'écriture de codes faciles à lire mais à être très attentif sur la gestion des indentations car la fin d'indentation signifie la fin d'un bloc de commandes.
Structure conditionnelle
End of explanation
"""


for i in range(4):
    print(i)

for i in range(1,8,2):
    print(i)

# Définition d'une fonction
def pythagorus(x,y):
    """ Calcule l'hypotenuse d'un triangle """
    r = pow(x**2+y**2,0.5)
    return x,y,r
pythagorus(3,4)

"""
Explanation: Structure itérative
End of explanation
"""


# exemple d'appel
pythagorus(x=3,y=4)

# aide intégrée
help(pythagorus)

pythagorus.__doc__

# Valeurs des paramètres par défaut
def pythagorus(x=1,y=1):
    """ calcule l'hypoténuse d'un triangle """
    r = pow(x**2+y**2,0.5)
    return x,y,r
pythagorus()

"""
Explanation: 4.2 Fonctions
End of explanation
"""


import testM
testM.DitBonjour()

print(testM.DivBy2(10))

from testM import *
DitBonjour()

print(DivBy2(10))

"""
Explanation: 4.4 Modules et librairies
Modules
Un module contient plusieurs fonctions et commandes qui sont regroupées dans un fichier d'extension .py. Insérer un fichier vide de nom _init_.py dans chaque dossier et sous-dossier contenant un module à importer.  Un module est appelé par la commande import. Un module est considéré comme un script s'il contient des commandes. Lors de l'import d'un script, les commandes sont exécutées tandis que les fonctions sont seulement chargées.
Commencer par définir un module dans un fichier texte contenant les commandes suivantes.
def DitBonjour():
    print("Bonjour")
def DivBy2(x):
    return x/2
Sauver le fichier avec pour nom testM.py dans le répertoire courant.
Il est possible d'importer toutes les fonctions en une seule commande import.
End of explanation
"""


import testM as tm
tm.DitBonjour()

print(tm.DivBy2(10))
# délétion des objets
%reset 

from testM import DitBonjour
DitBonjour()

print(DivBy2(10)) # erreur

"""
Explanation: Ou seulement celles qui seront utilisées. Préférer cette dernière méthode pour les grosses librairies.
End of explanation
"""


# Importation
import numpy as np
from pylab import *
gaussian = lambda x: np.exp(-(0.5-x)**2/1.5)
x=np.arange(-2,2.5,0.01)
y=gaussian(x)
plot(x,y)
xlabel("x values")
ylabel("y values")
title("Gaussian function")
show()

"""
Explanation: Lors de son premier appel, un module est pré-compilé dans un fichier .pyc qui est utilisé pour les appels suivants. Attention, si le fichier a été modifié / corrigé, il a besoin d'être rechargé par la commande reload(name).
Une librairie (package) regroupe plusieurs modules dans différents sous-répertoires. Le chargement spécifique d'un des modules se fait en précisant le chemin. 
import sound.effects.echo
5. Calcul scientifique
Voici trois des principales librairies indispensables au calcul scientifique. Deux autres librairies: pandas, scikit-learn, sont exposées en détail dans des calepins spécifiques.
5.1 Principales librairies ou packages
NumPy
Cette librairie définit le type de données array ainsi que les fonctions de calcul qui y sont associées. Il contient aussi quelques fonctions d'algèbre linéaire et statistiques. 
Il n'est finalement utilisé que pour la définition du type array car les fonctions numériques sont beaucoup plus développées dans  SciPy. 
Matplotlib
Celle-ci propose des fonctions de visualisation / graphs avec des commandes proches de celles de Matlab. Aussi connue sous le nom de pylab. La gallerie de cette librairie propose tout un ensemble d'exemples de graphiques avec le code Python pour les générer.
End of explanation
"""


# Importation
import numpy as np
my_1D_array = np.array([4,3,2])
print(my_1D_array)

my_2D_array = np.array([[1,0,0],[0,2,0],[0,0,3]])
print(my_2D_array)

myList=[1,2,3]
my_array = np.array(myList)
print(my_array)

a=np.array([[0,1],[2,3],[4,5]])
a[2,1]

a[:,1]

"""
Explanation: SciPy
Cette librairie est un ensemble très complet de modules d'algèbre linéaire, statistiques et autres algorithmes numériques. Le site  de la documentation en fournit la liste. 
5.2 Type Array
C'est de loin la structure de données la plus utilisée pour le calcul scientifique sous Python. Elle décrit des tableaux ou matrices multi-indices de dimension $ n = 1, 2, 3, \ldots , 40$. Tous les éléments sont de même type (booléen, entier, réel, complexe). 
Il est possible de contrôler précisément le type d'un array, par exemple pour gagner  de la place en mémoire, en codant les entiers sur 8, 16, 32 ou 64 bits, de même pour les réels (float) ou les complexes.
Les tableaux ou tables de données (data frame), bases d'analyses statistiques et regroupant des objets de types différents  sont décrits avec la librairie pandas.
Définition du type array
End of explanation
"""


np.arange(5)

np.ones(3)

np.ones((3,4))

np.eye(3)

np.linspace(3, 7, 3)

np.mgrid[0:3,0:2]

D=np.diag([1,2,4,3])
print(D)
print(np.diag(D))

M=np.array([[10*n+m for n in range(3)] 
for m in range(2)]) 
print(M)

"""
Explanation: Fonctions de type array
End of explanation
"""


from numpy import random
random.rand(4,2) #tirage uniforme

random.randn(4,2) #tirage selon la loi N(0,1)

v=random.randn(1000)
import matplotlib.pyplot as plt
h=plt.hist(v,20) # histogramme à 20 pas
show()

A=random.randn(64,64)
plt.imshow(A,interpolation="nearest")
plt.colorbar
plt.show()

# Sauver, écrire dans un fichier, lire un fichier
M=random.randn(10,10)
np.savetxt('data.csv',M,fmt='%2.2f',delimiter=',')
#au format propre à numpy : npy

np.save('data.npy',M)
np.load('data.npy')

"""
Explanation: Le module numpy.random fournit toute une liste de fonctions pour la génération de matrices aléatoires.
End of explanation
"""


v=np.array([1,2,3,4,5])
print(v)

v[1:4]

v[1:4:2]

v[::]

v[ : :2] # par pas de 2

v[ : 3] 

v[3 :] # à partir de l'indice 3

v[-1] # dernier élément

v[-2 :] # deux derniers éléments 

M=random.rand(4,3) 
print(M)

ind=[1,2]
M[ind] # lignes d'indices 1 et 2

M[:,ind] # colonnes d'indices 1 et 2

M[[0,2],[1,2]] # renvoie M[0,1] et M[2,2]

M[np.ix_([0,2],[1,2])]

(M>0.5)

M[M>0.5]

"""
Explanation: Slicing
End of explanation
"""


a=np.array([[0,1],[2,3],[4,5]])
np.ndim(a) # Nombre de dimensions)

np.size(a) # Nombre d’éléments

np.shape(a) # Tuple contenant la dimension de a

np.transpose(a) # Transposée

a.T # autre façon de définir la transposée

a.min(), np.min(a)  # Valeur min

a.sum(), np.sum(a)  # Somme des valeurs

a.sum(axis=0)  # Somme sur les colonnes

a.sum(axis=1)  # sur les lignes

"""
Explanation: Autres fonctions
End of explanation
"""


np.r_[1:4,10,11]  # Concaténation en ligne

np.c_[1:4,11:14]  # Concaténation en colonne

np.c_[1:4,11:15]  # erreur

np.arange(6).reshape(3,2)

A=np.array([[1,2],[3,4]])
np.tile(A,(3,2)) # Répétition de la matrice A

A=np.array([[1,2],[3,4]])
B=np.array([[11,12],[13,14]])
#Concaténation en ligne
np.concatenate((A,B),axis=0)

# Equivalent à
np.vstack((A,B))

# Concaténation en colonne
np.concatenate((A,B),axis=1)

# Equivalent à
np.hstack((A,B))

"""
Explanation: Quelques manipulations:
End of explanation
"""


# somme
a=np.arange(6).reshape(3,2)
b=np.arange(3,9).reshape(3,2)
c=np.transpose(b)
a+b

a*b # produit terme à terme

np.dot(a,c) # produit matriciel

np.power(a,2)

np.power(2,a)

a/3

"""
Explanation: Opérations sur les arrays
End of explanation
"""


# Importation
import numpy as np
from scipy import linalg
A = np.array([[1,2],[3,4]])
linalg.inv(A)

linalg.det(A)

la,v = linalg.eig(A)
l1,l2 = la
# valeurs propres
print(l1, l2)

# 1er vecteur propre
print(v[:,0])

# SVD de A
U,s,V = linalg.svd(A) 
print(s**2)

linalg.eig(np.dot(np.transpose(A),A))

"""
Explanation: Les fonctions genfromtxt, avetxt permettent de lire, écrire des fichiers textes par exemple au format .csv mais ces fonctionnalités sont plus largement abordées avec la librairie pandas.
Fonctions d'algèbre linéaire
End of explanation
"""


# Importation
import scipy.stats
rvs1 = scipy.stats.norm.rvs(loc=5, scale=10,size=500)
rvs2 = scipy.stats.norm.rvs(loc=5, scale=10,size=500)
rvs3 = scipy.stats.norm.rvs(loc=8, scale=10,size=500)
# t-test returns: t-statistic/two-tailed p-value
scipy.stats.ttest_ind(rvs1, rvs2)

scipy.stats.ttest_ind(rvs1, rvs3)

# Kolmogorov-Smirnov test
# returns: KS statistic / two-tailed p-value
scipy.stats.ks_2samp(rvs1, rvs2)

scipy.stats.ks_2samp(rvs1, rvs3)

"""
Explanation: Tests élémentaires de Statistique
End of explanation
"""


