Python : math.sqrt() versus numpy.sqrt()

Bonjour,
L'utilisation des exceptions est la règle en Python, mais dans le cas présent avec Numpy, je n'ai pas trouvé comme faire sans passer par un if/else en Python 3.8.5 (j'ai cherché sur la toile sans succès)

Autre point intéressant qui me fait préférer Numpy:
  • math ne semble pas accepter les vecteurs (une solution consiste à passer par l'exposant)
  • Numpy reste plus rapide dans cet exemple
  • les "nan" sont faciles à trouver avec numpy.isnan
Si quelqu'un a une solution pour l'exception, je suis preneur.
Bonnes fêtes
Paul
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import numpy as np
from math import sqrt
import time

############################################################################
val = -1.

## avec le module math
print("Avec le module math:")
try:
    sqrt(val)
except ValueError:
    print("\tValeur négative => impossible\n")
else:
    print("\tRacine = {}\n".format(sqrt(val)))

          
## avec le module Numpy + utilisation exception
print("Avec le module Numpy + exception:")
try:
    np.sqrt(val)
except ValueError:
    print("Valeur négative => impossible\n")
else:
    print("Racine = {}\n".format(np.sqrt(val)))
    

## A l'ancienne avec if
print("Avec le module Numpy + if/else:")
if (val < 0):
    print("Valeur négative => impossible\n")
else:
    print("Racine = {}\n".format(np.sqrt(val)))
    
############################################################################    
## test performance sur vecteur
n=1_000_000
A = np.random.random(n)

## Avec math
t0 = time.time()
B = np.copy(A)
# B = sqrt(B)## ne fonctionne pas avec un vecteur
B = B**0.5
t1 = time.time()
Duree1 = t1 - t0
print("Durée avec math : {}".format(Duree1))
del B, t0, t1

## avec numpy
t0 = time.time()
C = np.copy(A)
C = np.sqrt(C)  ## assez intuitif :-)
t1 = time.time()
Duree2 = t1 - t0
print("Durée avec numpy : {}".format(Duree2))
del C, t0, t1

## Ratio
print("ratio = {}".format(Duree1 / Duree2))

############################################################################
## utilisation de numpy.isnan
T = np.array([[ 1. , 2.],
             [ 3. , 0]])
T[1,1] = np.nan
print(T)
a = np.isnan(T)
T[a] = -999 # on remplace bien le nan, tout comme on pourrait aisément supprimer la ligne ou la colonne

Réponses

  • Tu peux écrire la ligne après else directement dans le bloc du try.
    Algebraic symbols are used when you do not know what you are talking about.
            -- Schnoebelen, Philippe
  • Dans la cas présent c'est inutile, il ne "déclenche" jamais "except"; il se contente d'afficher un warning:
    • bien sûr si val est positive ou nul, il va afficher la racine carrée
    • si val est négatif, il affichera un "nan"
    • en revanche le code dans "except" n'est jamais traité dans mon cas
    try:
        np.sqrt(val)
    except ValueError:
        print("Valeur négative => impossible\n")
    else:
        print("Racine = {}\n".format(np.sqrt(val)))
    
  • Les exceptions sont plus lentes qu’un test, il me semble.
    Algebraic symbols are used when you do not know what you are talking about.
            -- Schnoebelen, Philippe
  • @paul18 la doc de la fonction sqrt de numpy ici https://numpy.org/doc/stable/reference/generated/numpy.sqrt.html ne dit pas que cette fonction lève une exception si ton nombre est négatif. Elle dit : "If all of the elements in x are real, so is y, with negative elements returning nan..."

    Donc aucune chance d'obtenir une exception avec cette fonction.
  • @Raoul

    Oui j'avais bien lu, mais je me disais qu'il y avait peut-être une astuce. Avec la vectorisation, je n'en ai fondamentalement pas besoin, mais j'essaie de me forcer à utiliser les exceptions dans des cas simples pour rester dans une logique "pythonienne" ;-)

    Merci pour le retour
  • Bonjour,

    Il y a dans le code du premier message un commentaire qui me paraît quelque peu trompeur. Je parle de celui qui laisse comprendre que la ligne 47 :
    B = B**0.5
    
    repose sur le module 'math'. B étant un vecteur NumPy, il me semble que ce calcul est effectué par NumPy. D'ailleurs, la durée d'exécution est, à $\varepsilon$ près, la même que pour :
    C = np.sqrt(C)
    
    sur mon ordinateur. M'enfin, j'dis ça, j'dis rien... ;-)
  • j'avoue avoir mélangé plusieurs essais pour tester math.sqrt; maintenant je sais qu'il ne traite qu'un scalaire en entrée et ce n'est pas mon besoin B-)
Connectez-vous ou Inscrivez-vous pour répondre.