<jupyter_start><jupyter_text>Tech - calcul matriciel avec numpy[numpy](https://numpy.org/) 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](https://numpy.org/) implémente ce qu'on appelle les opérations matricielles basiques ou plus communément appelées [BLAS](https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms). 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.<jupyter_code>from jyquickhelper import add_notebook_menu
add_notebook_menu()
%matplotlib inline<jupyter_output><empty_output><jupyter_text>EnoncéLa librairie [numpy](https://numpy.org/) propose principalement deux types : [array](https://numpy.org/doc/stable/reference/generated/numpy.array.html) et [matrix](https://numpy.org/doc/stable/reference/generated/numpy.matrix.html). Pour faire simple, prenez toujours le premier. Ca évite les erreurs. Les [array](https://numpy.org/doc/stable/reference/generated/numpy.array.html) sont des tableaux à plusieurs dimensions.  La maîtrise du sliceLe slice est l'opérateur ``:`` (décrit sur la page [indexing](https://numpy.org/doc/stable/reference/arrays.indexing.html)). Il permet de récupérer une ligne, une colonne, un intervalle de valeurs.<jupyter_code>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]<jupyter_output><empty_output><jupyter_text>La maîtrise du nan[nan](https://numpy.org/doc/stable/reference/constants.html) 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.<jupyter_code>numpy.nan == numpy.nan
numpy.nan == 4<jupyter_output><empty_output><jupyter_text>Il faut donc utiliser une fonction spéciale [isnan](https://numpy.org/doc/stable/reference/generated/numpy.isnan.html).<jupyter_code>numpy.isnan(numpy.nan)<jupyter_output><empty_output><jupyter_text>La maîtrise des typesUn tableau est défini par ses dimensions et le type unique des éléments qu'il contient.<jupyter_code>matint = numpy.array([0, 1, 2])
matint.shape, matint.dtype<jupyter_output><empty_output><jupyter_text>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.<jupyter_code>%timeit matint * matint
matintf = matint.astype(numpy.float64)
matintf.shape, matintf.dtype
%timeit matintf * matintf
%timeit matintf * matint<jupyter_output>894 ns ± 78.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)<jupyter_text>Un changement de type et le calcul est plus long.  La maîtrise du broadcastingLe [broadcasting](https://numpy.org/doc/stable/user/basics.broadcasting.html) signifie que certaines opérations ont un sens même si les dimensions des tableaux ne sont pas tout à fait égales.<jupyter_code>mat
mat + 1000
mat + numpy.array([0, 10, 100, 1000])
mat + numpy.array([[0, 10, 100]]).T<jupyter_output><empty_output><jupyter_text>La maîtrise des index<jupyter_code>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)<jupyter_output><empty_output><jupyter_text>La maîtrise des fonctionsOn peut regrouper les opérations que [numpy](https://numpy.org/) propose en différents thèmes. Mais avant il * L'**initialisation** : [array](https://numpy.org/doc/stable/reference/generated/numpy.array.html), [empty](https://numpy.org/doc/stable/reference/generated/numpy.empty.html), [zeros](https://numpy.org/doc/stable/reference/generated/numpy.zeros.html), [ones](https://numpy.org/doc/stable/reference/generated/numpy.ones.html), [full](https://numpy.org/doc/stable/reference/generated/numpy.full.html), [identity](https://numpy.org/doc/stable/reference/generated/numpy.identity.html), [rand](https://numpy.org/doc/stable/reference/random/generated/numpy.random.rand.html), [randn](https://numpy.org/doc/stable/reference/random/generated/numpy.random.randn.html), [randint](https://numpy.org/doc/stable/reference/random/generated/numpy.random.randint.html)* Les **opérations basiques** : `+`, `-`, `*`, `/`, `@`, [dot](https://numpy.org/doc/stable/reference/generated/numpy.dot.html)* Les **transformations** : [transpose](https://numpy.org/doc/stable/reference/generated/numpy.transpose.html), [hstack](https://numpy.org/doc/stable/reference/generated/numpy.hstack.html), [vstack](https://numpy.org/doc/stable/reference/generated/numpy.vstack.html), [reshape](https://numpy.org/doc/stable/reference/generated/numpy.reshape.html), [squeeze](https://numpy.org/doc/stable/reference/generated/numpy.squeeze.html), [expend_dims](https://numpy.org/doc/stable/reference/generated/numpy.expand_dims.html)* Les **opérations de réduction** : [minimum](https://numpy.org/doc/stable/reference/generated/numpy.minimum.html), [maximum](https://numpy.org/doc/stable/reference/generated/numpy.maximum.html), [argmin](https://numpy.org/doc/stable/reference/generated/numpy.argmin.html), [argmax](https://numpy.org/doc/stable/reference/generated/numpy.argmax.html), [sum](https://numpy.org/doc/stable/reference/generated/numpy.sum.html), [mean](https://numpy.org/doc/stable/reference/generated/numpy.mean.html), [prod](https://numpy.org/doc/stable/reference/generated/numpy.prod.html), [var](https://numpy.org/doc/stable/reference/generated/numpy.var.html), [std](https://numpy.org/doc/stable/reference/generated/numpy.std.html)* Tout le reste comme la génération de matrices aléatoires, le calcul des valeurs, vecteurs propres, des fonctions commme [take](https://numpy.org/doc/stable/reference/generated/numpy.take.html), ...  Q1 : calculer la valeur du $\chi_2$ d'un tableau de contingenceLa formule est [là](https://en.wikipedia.org/wiki/Pearson%27s_chi-squared_testTesting_for_statistical_independence). Et il faut le faire sans boucle. Vous pouvez comparer avec la fonction [chisquare](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.chisquare.html) de la librairie [scipy](https://www.scipy.org/) qui est une extension de [numpy](https://numpy.org/).$$\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èreLa fonction [histogram](https://numpy.org/doc/stable/reference/generated/numpy.histogram.html) permet de calculer la distribution empirique de variables. Pour cette question, on tire un vecteur aléatoire de taille 10 avec la fonction [rand](https://numpy.org/doc/stable/reference/random/generated/numpy.random.rand.html), 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 millionVous pouvez essayer sans réfléchir ou lire cette page d'abord : [csr_matrix](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.csr_matrix.html).  Q4 : vous devez créer l'application StopCovidIl 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 contingenceLa formule est [là](https://en.wikipedia.org/wiki/Pearson%27s_chi-squared_testTesting_for_statistical_independence). Et il faut le faire sans boucle. Vous pouvez comparer avec la fonction [chisquare](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.chisquare.html) de la librairie [scipy](https://www.scipy.org/) qui est une extension de [numpy](https://numpy.org/).$$\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$$<jupyter_code>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)<jupyter_output><empty_output><jupyter_text>Q2 : calculer une distribution un peu particulièreLa fonction [histogram](https://numpy.org/doc/stable/reference/generated/numpy.histogram.html) permet de calculer la distribution empirique de variables. Pour cette question, on tire un vecteur aléatoire de taille 10 avec la fonction [rand](https://numpy.org/doc/stable/reference/random/generated/numpy.random.rand.html), 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.<jupyter_code>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());<jupyter_output><empty_output><jupyter_text>Q3 : on veut créer une matrice identité un million par un millionVous pouvez essayer sans réfléchir ou lire cette page d'abord : [csr_matrix](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.csr_matrix.html). $(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.<jupyter_code>import numpy
from scipy.sparse import csr_matrix
ide = csr_matrix((1000000, 1000000), dtype=numpy.float64)
ide.setdiag(1.)<jupyter_output>c:\python395_x64\lib\site-packages\scipy\sparse\_index.py:125: SparseEfficiencyWarning: Changing the sparsity structure of a csr_matrix is expensive. lil_matrix is more efficient.
  self._set_arrayXarray(i, j, x)
{'fraction_non_alphanumeric': 0.14117983963344788, 'fraction_numerical': 0.016800305460099276, 'mean_word_length': 5.173836181496759, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 44, 'https://': 52, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '237168', 'license': 'MIT', 'n_tokens_mistral': 3742, 'n_tokens_neox': 3631, 'n_words': 849, 'path': '_doc/notebooks/td1a_home/2020_numpy.ipynb', 'repo_name': 'sdpython/ensae_teaching_cs', 'size': '10476'}