<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Tech - calcul matriciel avec numpy
numpy est la librairie incontournable pour faire des calculs en Python. Ces fonctionnalités sont disponibles dans tous les langages et utilisent les optimisations processeurs. Il est hautement improbable d'écrire un code aussi rapide sans l'utiliser.
numpy implémente ce qu'on appelle les opérations matricielles basiques ou plus communément appelées BLAS. Quelque soit le langage, l'implémentation est réalisée en langage bas niveau (C, fortran, assembleur) et a été peaufinée depuis 50 ans au gré des améliorations matérielles.
Step1:  Enoncé
La librairie numpy propose principalement deux types 
Step2:  La maîtrise du nan
nan est une convention pour désigner une valeur manquante. Elle réagit de façon un peut particulière. Elle n'est égale à aucune autre y compris elle-même.
Step3:  Il faut donc utiliser une fonction spéciale isnan.
Step4:  La maîtrise des types
Un tableau est défini par ses dimensions et le type unique des éléments qu'il contient.
Step5:  C'est le même type pour toute la matrice. Il existe plusieurs type d'entiers et des réels pour des questions de performances.
Step6:  Un changement de type et le calcul est plus long.
La maîtrise du broadcasting
Le broadcasting signifie que certaines opérations ont un sens même si les dimensions des tableaux ne sont pas tout à fait égales.
Step7:  La maîtrise des index
Step8:  La maîtrise des fonctions
On peut regrouper les opérations que numpy propose en différents thèmes. Mais avant il 
L'initialisation 
Step9:  Q2 
Step10:  Q3 
<ASSISTANT_TASK:>
Python Code:
from jyquickhelper import add_notebook_menu
add_notebook_menu()
%matplotlib inline
Explanation: Tech - calcul matriciel avec numpy
numpy est la librairie incontournable pour faire des calculs en Python. Ces fonctionnalités sont disponibles dans tous les langages et utilisent les optimisations processeurs. Il est hautement improbable d'écrire un code aussi rapide sans l'utiliser.
numpy implémente ce qu'on appelle les opérations matricielles basiques ou plus communément appelées BLAS. Quelque soit le langage, l'implémentation est réalisée en langage bas niveau (C, fortran, assembleur) et a été peaufinée depuis 50 ans au gré des améliorations matérielles.
End of explanation
import numpy
mat = numpy.array([[0, 5, 6, -3],
                   [6, 7, -4, 8],
                   [-5, 8, -4, 9]])
mat
mat[:2], mat[:, :2], mat[0, 3], mat[0:2, 0:2]
Explanation: Enoncé
La librairie numpy propose principalement deux types : array et matrix. Pour faire simple, prenez toujours le premier. Ca évite les erreurs. Les array sont des tableaux à plusieurs dimensions.
La maîtrise du slice
Le slice est l'opérateur : (décrit sur la page indexing). Il permet de récupérer une ligne, une colonne, un intervalle de valeurs.
End of explanation
numpy.nan == numpy.nan
numpy.nan == 4
Explanation: La maîtrise du nan
nan est une convention pour désigner une valeur manquante. Elle réagit de façon un peut particulière. Elle n'est égale à aucune autre y compris elle-même.
End of explanation
numpy.isnan(numpy.nan)
Explanation: Il faut donc utiliser une fonction spéciale isnan.
End of explanation
matint = numpy.array([0, 1, 2])
matint.shape, matint.dtype
Explanation: La maîtrise des types
Un tableau est défini par ses dimensions et le type unique des éléments qu'il contient.
End of explanation
%timeit matint * matint
matintf = matint.astype(numpy.float64)
matintf.shape, matintf.dtype
%timeit matintf * matintf
%timeit matintf * matint
Explanation: C'est le même type pour toute la matrice. Il existe plusieurs type d'entiers et des réels pour des questions de performances.
End of explanation
mat
mat + 1000
mat + numpy.array([0, 10, 100, 1000])
mat + numpy.array([[0, 10, 100]]).T
Explanation: Un changement de type et le calcul est plus long.
La maîtrise du broadcasting
Le broadcasting signifie que certaines opérations ont un sens même si les dimensions des tableaux ne sont pas tout à fait égales.
End of explanation
mat = numpy.array([[0, 5, 6, -3],
                   [6, 7, -4, 8],
                   [-5, 8, -4, 9]])
mat
mat == 5
mat == numpy.array([[0, -4, 9]]).T
(mat == numpy.array([[0, -4, 9]]).T).astype(numpy.int64)
mat * (mat == numpy.array([[0, -4, 9]]).T).astype(numpy.int64)
Explanation: La maîtrise des index
End of explanation
import numpy
O = numpy.array([[15., 20., 13.], [4., 9., 5.]])
O
def chi_square(O):
    N = numpy.sum(O)
    pis = numpy.sum(O, axis=1, keepdims=True) / N
    pjs = numpy.sum(O, axis=0, keepdims=True) / N
    pispjs = pis @ pjs
    chi = pispjs * ((O / N - pispjs) / pispjs) ** 2
    return numpy.sum(chi) * N
chi_square(O)
Explanation: La maîtrise des fonctions
On peut regrouper les opérations que numpy propose en différents thèmes. Mais avant il 
L'initialisation : array, empty, zeros, ones, full, identity, rand, randn, randint
Les opérations basiques : +, -, *, /, @, dot
Les transformations : transpose, hstack, vstack, reshape, squeeze, expend_dims
Les opérations de réduction : minimum, maximum, argmin, argmax, sum, mean, prod, var, std
Tout le reste comme la génération de matrices aléatoires, le calcul des valeurs, vecteurs propres, des fonctions commme take, ...
Q1 : calculer la valeur du $\chi_2$ d'un tableau de contingence
La formule est là. Et il faut le faire sans boucle. Vous pouvez comparer avec la fonction chisquare de la librairie scipy qui est une extension de numpy.
$$\chi_2 = N \sum_{i,j} p_{i.} p_{.j} \left( \frac{\frac{O_{ij}}{N} - p_{i.} p_{.j}}{p_{i.} p_{.j}}\right)^2$$
Q2 : calculer une distribution un peu particulière
La fonction histogram permet de calculer la distribution empirique de variables. Pour cette question, on tire un vecteur aléatoire de taille 10 avec la fonction rand, on les trie par ordre croissant, on recommence plein de fois, on calcule la distribution du plus grand nombre, du second plus grand nombre, ..., du plus petit nombre.
Q3 : on veut créer une matrice identité un million par un million
Vous pouvez essayer sans réfléchir ou lire cette page d'abord : csr_matrix.
Q4 : vous devez créer l'application StopCovid
Il existe une machine qui reçoit la position de 3 millions de téléphones portable. On veut identifier les cas contacts (rapidement).
Réponses
Q1 : calculer la valeur du $\chi_2$ d'un tableau de contingence
La formule est là. Et il faut le faire sans boucle. Vous pouvez comparer avec la fonction chisquare de la librairie scipy qui est une extension de numpy.
$$\chi_2 = N \sum_{i,j} p_{i.} p_{.j} \left( \frac{\frac{O_{ij}}{N} - p_{i.} p_{.j}}{p_{i.} p_{.j}}\right)^2$$
End of explanation
rnd = numpy.random.rand(10)
rnd
numpy.sort(rnd)
def tirage(n):
    rnd = numpy.random.rand(n)
    trie = numpy.sort(rnd)
    return trie[-1]
tirage(10)
def plusieurs_tirages(N, n):
    rnd = numpy.random.rand(N, n)
    return numpy.max(rnd, axis=1)
plusieurs_tirages(5, 10)
t = plusieurs_tirages(5000, 10)
hist = numpy.histogram(t)
hist
import matplotlib.pyplot as plt
plt.plot(hist[1][1:], hist[0] / hist[0].sum());
Explanation: Q2 : calculer une distribution un peu particulière
La fonction histogram permet de calculer la distribution empirique de variables. Pour cette question, on tire un vecteur aléatoire de taille 10 avec la fonction rand, on les trie par ordre croissant, on recommence plein de fois, on calcule la distribution du plus grand nombre, du second plus grand nombre, ..., du plus petit nombre.
End of explanation
import numpy
from scipy.sparse import csr_matrix
ide = csr_matrix((1000000, 1000000), dtype=numpy.float64)
ide.setdiag(1.)
Explanation: Q3 : on veut créer une matrice identité un million par un million
Vous pouvez essayer sans réfléchir ou lire cette page d'abord : csr_matrix.
$(10^6)^2=10^{12}$>10 Go, bref ça ne tient pas en mémoire sauf si on a une grosse machine. Les matrices creuses (ou sparses en anglais), sont adéquates pour représenter des matrices dont la grande majorité des coefficients sont nuls car ceux-ci ne sont pas stockés. Concrètement, la matrice enregistre uniquement les coordonnées des coefficients et les valeurs non nuls.
End of explanation
<END_TASK>