Capítulo 15, Básico
Funções universais (ufuncs)
Raiz quadrada, logaritmo, exponencial, trigonometria: toda a matemática elementar aplicada ao array inteiro de uma vez, em código compilado, com broadcasting incluído.
Código deste capítulo: básico/cap15_ufuncs.py
Matemática sobre o array inteiro
Uma ufunc (função universal) aplica uma operação a cada elemento. Os operadores +, -, * e / são, por baixo, np.add, np.subtract, np.multiply e np.divide:
import numpy as np
a = np.array([1.0, 4.0, 9.0])
print(np.sqrt(a), np.exp(np.array([0, 1])), np.log(np.array([1, np.e])))
print(np.add(a, 1), np.multiply(a, a))
print(np.abs(np.array([-3, 2])), np.round(np.array([1.234, 5.678]), 1))
print(np.clip(np.array([-5, 3, 12]), 0, 10))
[1. 2. 3.] [1. 2.71828183] [0. 1.]
[ 2. 5. 10.] [ 1. 16. 81.]
[3 2] [1.2 5.7]
[ 0 3 10]
O np.clip(x, mínimo, máximo) "aperta" os valores para dentro de um intervalo: tudo abaixo do mínimo vira o mínimo, e tudo acima do máximo vira o máximo. É muito usado para limpar dados com valores impossíveis.
Resultados impossíveis viram `nan` e `inf`
Uma conta impossível (raiz de número negativo, divisão por zero) não derruba o programa: o NumPy emite um aviso e devolve um valor especial, nan ("não é um número") ou inf (infinito). A execução continua:
import warnings
with warnings.catch_warnings(record=True) as avisos:
warnings.simplefilter("always")
resultado = np.sqrt(np.array([4.0, -4.0]))
print(resultado, avisos[0].category.__name__)
[ 2. nan] RuntimeWarning
Esse comportamento é conveniente, e também perigoso: o nan se espalha. Qualquer conta com um nan produz nan, e o erro aparece longe de onde nasceu. O capítulo 25 trata dos dados ausentes. Se você sabe o que está fazendo, o np.errstate silencia os avisos em um trecho:
with np.errstate(invalid="ignore", divide="ignore"):
print(np.array([1.0, 0.0]) / np.array([0.0, 0.0]))
[inf nan]
Escolher onde calcular: `where` e `out`
As ufuncs aceitam dois parâmetros que economizam memória e evitam contas indesejadas. O where diz em quais posições calcular, e o out diz onde guardar o resultado, em vez de criar um array novo. Onde o where é falso, o valor de out permanece:
x = np.array([1.0, 4.0, 9.0, 16.0])
saida = np.zeros_like(x)
np.sqrt(x, out=saida, where=x > 5)
print(saida)
[0. 0. 3. 4.]
Divisão inteira e resto
Os operadores // e % também são ufuncs, e a divisão inteira arredonda para baixo, mesmo com números negativos:
print(np.array([7, -7]) // 2, np.mod(-7, 3))
[ 3 -4] 2
Não misture math com NumPy
O módulo
mathtrabalha com um número por vez e falha com arrays (capítulo 12). O NumPy não só aceita arrays como também aceita um número isolado, então, em código numérico, prefiranp.sqrt,np.expe companhia, mesmo para valores únicos, e o código serve para os dois casos.
Exercício 1
A função sigmoide
Escreva sigmoide(x), igual a 1 / (1 + e^(-x)). É a função que "comprime" qualquer número para o intervalo entre 0 e 1, e é a base de muita coisa em aprendizado de máquina.