<jupyter_start><jupyter_text>Módulos Científicos  Numpy A linguagem Python armazena dados de várias maneiras diferentes, mas o mais comum é o uso de **listas** e **dicionários**. O objeto **list** do Python pode armazenar praticamente qualquer tipo de objeto como elemento. Mas uma operação nos elementos de uma lista só pode ser feita através de laços iterativos, que são computacionalmente ineficientes no Python. O pacote **NumPy** permite que os usuários superem as deficiências das listas, provendo um objeto de armazenamento de dados chamado **ndarray**. O **NumPy** é um pacote fundamental para se fazer computação científica na linguagem Python.Algumas características importantes do **Numpy**: Facilidades para manipulação de matrizes N-dimensionaisFunções com operações do tipo elemento-a-elemento (*broadcasting*)Possui ferramentas para encapsular códigos C/C++ e FortranPossui módulos de funções para Álgebra Linear, para Transformada de Fourier e para Números Aleatórios.Além do uso científico, o **NumPy** também pode ser usado como um contêiner multidimensional eficiente para dados genéricos. Tipos de dados arbitrários (estruturas de dados - registros) podem ser definidos. Isso permite ao **NumPy** fácil e rápida integração a uma ampla variedade de bancos de dados. A seguir veremos como usar o pacote **NumPy** na manipulação de arranjos matriciais (*ndarray*).Antes de mais nada, precisamos importar o pacote **NumPy** para só então usarmos suas classes, funções e demais recursos.<jupyter_code>import numpy as np<jupyter_output><empty_output><jupyter_text>Criando um arranjo unidimensional (vetor) a partir de uma lista de elementos inteiros, usando a função **`array()`**:<jupyter_code>np.array([4,5,6])                    # converte uma lista num vetor (array)<jupyter_output><empty_output><jupyter_text>Criando um arranjo bidimensional (matriz) com elementos do tipo real a partir de uma lista de elementos inteiros:<jupyter_code>np.array([[4,5,6],[7,8,9],[10,11,12]], dtype = float)<jupyter_output><empty_output><jupyter_text>Verificando a forma de um arranjo (quantidade de linhas e de colunas da matriz), usando a propriedade **`shape`**:<jupyter_code>mat = np.array([[4,5,6],[7,8,9],[10,11,12]], dtype = float)
mat.shape<jupyter_output><empty_output><jupyter_text>Criando um vetor com valores de 1 a 59, uniformemente espaçados de 2 em 2, usando a função **`arange()`**:<jupyter_code>faixa = np.arange(1,60,2)
print(faixa)
faixa.shape<jupyter_output>[ 1  3  5  7  9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47
 49 51 53 55 57 59]<jupyter_text>Mudando a forma de apresentação de um array (não há mudança na memória), por exemplo, de vetor para matriz:<jupyter_code>print(faixa.reshape(5,6))
print(faixa)<jupyter_output>[[ 1  3  5  7  9 11]
 [13 15 17 19 21 23]
 [25 27 29 31 33 35]
 [37 39 41 43 45 47]
 [49 51 53 55 57 59]]
[ 1  3  5  7  9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47
 49 51 53 55 57 59]<jupyter_text>Gerando um vetor com 15 valores uniformemente espaçados de 1 a 8 (limites inclusivos), usando a função **`linspace()`**:<jupyter_code>x = np.linspace(1,8,15)
print(x)
print(x.shape)<jupyter_output>[1.  1.5 2.  2.5 3.  3.5 4.  4.5 5.  5.5 6.  6.5 7.  7.5 8. ]
(15,)<jupyter_text>Agora, vamos alterar a forma do vetor na memória (a função **`resize()`** altera a forma da matriz na memória, ao contrário da função **`reshape()`** que só muda a forma na apresentação da informação).<jupyter_code>print(x.shape)
x.resize(5,3)
print(x)<jupyter_output>(15,)
[[1.  1.5 2. ]
 [2.5 3.  3.5]
 [4.  4.5 5. ]
 [5.5 6.  6.5]
 [7.  7.5 8. ]]<jupyter_text>Criando um arranjo com todos os elementos iguais a um, usando a função **`ones()`**, e outro vetor com elementos iguais a zero, usando a função **`zeros()`**:<jupyter_code>y = np.ones((3,3,3))*(-5)
y
z = np.zeros((2,5))
z<jupyter_output><empty_output><jupyter_text>Criando uma matriz diagonal unitária (matriz identidade), usando a função **`eye()`**:<jupyter_code>diag = np.eye(4)
diag
print(diag)<jupyter_output>[[1. 0. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 1. 0.]
 [0. 0. 0. 1.]]<jupyter_text>Criando *arrays*: a partir da repetição de uma lista, usando a função **`repeat()`**:<jupyter_code>r1 = np.array([1,2,3]*6)
r1
r2 = np.repeat([1,2,3],6)
r2<jupyter_output><empty_output><jupyter_text>Gerando dois *arrays* de dimensão 2x3, preenchidos com valores aleatórios entre 0 e 1, usando a função **`rand()`**:<jupyter_code>a = np.random.rand(4,2)
a<jupyter_output><empty_output><jupyter_text>**Exercício**: Gerar seis números aleatórios de 1 a 60 para apostar na MegaSena.<jupyter_code>np.int8(np.random.rand(1,6)*60)+1
w = 343.655
np.int
b = np.random.rand(4,2)
b<jupyter_output><empty_output><jupyter_text>Empilhando verticalmente as duas matrizes criadas anteriormente, a e b, usando a função **`vpstack()`**:<jupyter_code>vert = np.vstack([a,b])
vert<jupyter_output><empty_output><jupyter_text>Agora, horizontalmente, usando a função **`hstack()`**:<jupyter_code>hor = np.hstack((a,b))
hor<jupyter_output><empty_output><jupyter_text>Vamos fazer algumas operações **elemento a elemento** (*element-wise*) em arranjos de mesmas dimensões:<jupyter_code>A = np.array([[1, 2],[3, 4]])
A
B = -A                         # oposto
B
A + B                          # soma elemento a elemento
A * B                          # multiplicação elemento a elemento --> não é multiplicação matricial
A**3<jupyter_output><empty_output><jupyter_text>**Multiplicação matricial**:<jupyter_code>print('A =\n',A,"\nB =\n",B)
print('A x B =\n',A.dot(B))<jupyter_output>A =
 [[1 2]
 [3 4]] 
B =
 [[-1 -2]
 [-3 -4]]
A x B =
 [[ -7 -10]
 [-15 -22]]<jupyter_text>**Transposição matricial**:<jupyter_code>print(A.transpose())
print(A.T)<jupyter_output>[[1 3]
 [2 4]]
[[1 3]
 [2 4]]<jupyter_text>Agora, vamos verificar o tipo de dados dos elementos na matriz:<jupyter_code>print(A.dtype,a.dtype)<jupyter_output>int32 float64<jupyter_text>Mudando o tipo de dados da matriz, de inteiro para ponto flutuante (*float*):<jupyter_code>C = A.astype('f')
C
print(C)<jupyter_output>[[1. 2.]
 [3. 4.]]<jupyter_text>Agora, vamos ver algumas funções matemáticas aplicadas aos elementos de uma matriz, começando pela soma, depois valores máximo e mínimo, e por fim a média:<jupyter_code>print(A.sum(), A.max(), A.min(), A.mean())<jupyter_output>10 4 1 2.5<jupyter_text>Tabuada de 5, indexação e fatiamento:<jupyter_code>tab5 = np.arange(0,11)*5                          # ou: np.arange(0,51,5)
tab5
print(tab5[1:5])
print(tab5[-1])
print(tab5[::-1])<jupyter_output>[ 5 10 15 20]
50
[50 45 40 35 30 25 20 15 10  5  0]<jupyter_text>Criando um arranjo bidimensional a partir de um vetor:<jupyter_code>d = np.arange(21)
print(d)
d.reshape(3,7)
d.shape
d = np.arange(25)
print(d)
d.resize(5,5)
print(d)<jupyter_output>[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 24]
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]
 [15 16 17 18 19]
 [20 21 22 23 24]]<jupyter_text>Acessando a quarta e quinta colunas da quarta linha da matriz **d**. Observe que a numeração das linhas e colunas começam em 0 (zero):<jupyter_code>print(d[3,3:5])
d.shape<jupyter_output>[18 19]<jupyter_text>Selecionando os valores maiores que 15 da matriz **d**, e atribuindo valor zero:<jupyter_code>print(d[d>15])
d[d>15] = 0
print(d)<jupyter_output>[16 17 18 19 20 21 22 23 24]
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]
 [15  0  0  0  0]
 [ 0  0  0  0  0]]<jupyter_text>Criando uma matriz 3x3 preenchida com números inteiros aleatórios entre 5 e 20:<jupyter_code>e = np.random.randint(5,20,(3,3))
e<jupyter_output><empty_output><jupyter_text>Construção Rápida de ArranjosExistem algumas instâncias de classe que fazem uso especial da funcionalidade do fatiamento (slicing) para fornecer meios eficientes na construção de arranjos (vetores, matrizes). Vamos ver a operação das funções **mgrid(), ogrid()** e dos comandos **r_ e c_** na construção rápida de arranjos. Por exemplo, ao invés de escrevermos:<jupyter_code>a = np.concatenate(([3], [0]*5, np.arange(-1, 1.002, 2/9.0)))
a<jupyter_output><empty_output><jupyter_text>Usando o comando **r_** podemos fazer a concatenação ou mesclagem de linhas (*row-wise merging*) escrevendo apenas:<jupyter_code># o resultado é o mesmo obtido na concatenação anterior!
b = np.r_[3,[0]*5,-1:1:10j]   
# o terceiro valor no slicing, 10j, indica a qtde de pontos a serem produzidos entre -1 e 1 (linspace)
b<jupyter_output><empty_output><jupyter_text>Essa forma facilita a digitação e torna o código mais legível. Observe como os objetos são concatenados e a sintaxe de fatiamento foi usada para construir intervalos. Outro termo que merece explicação é o número complexo **10j** que foi usado como o tamanho do passo na sintaxe do fatiamento. Esse uso não padrão permite que o número seja interpretado como o **número de pontos** a serem produzidos no intervalo, ao invés de um **tamanho de passo**. Esse uso não padrão pode ser desagradável para alguns, mas dá ao usuário a capacidade de construir rapidamente vetores complicados de forma simples. Quando o número de pontos é especificado dessa maneira, o ponto final do intervalo é inclusivo.A letra "**r**" significa **mesclagem de linha** (*row*), porque se os objetos entre vírgulas forem matrizes bidimensionais, eles serão empilhados em linhas (e, portanto, devem ter colunas proporcionais). Existe um comando equivalente **c_** que empilha *arrays* bidimensionais em colunas, **mesclagem em coluna** (*column*), com funcionamento idêntico ao **r_** para arranjos unidimensionais. Geraçao de Malhas (grades)Uma instância da classe nd_grid, **mgrid[ ]**, no seu formato mais simples, é usada para construir intervalos de faixas unidimensionais como substituta conveniente à função **arange()**. Também usa números complexos na indicação do **tamanho do passo** para indicar o número de pontos a serem colocados entre os pontos inicial e final (inclusivos). O propósito real dessa função, entretanto, é o de produzir grades N-dimensionais que forneçam matrizes de coordenadas para um volume N-dimensional. A maneira mais fácil de entender isso é com um exemplo de uso da função:<jupyter_code>from pylab import plot, axes

grade = np.mgrid[0:5,0:5]
print(grade.shape)

plot(grade[0,:,:],grade[1,:,:],'*');
axes().set_aspect('equal')
np.mgrid[0:5:4j,0:5:4j]<jupyter_output><empty_output><jupyter_text>Ter matrizes de malha como esta é, por vezes, muito útil. No entanto, nem sempre é necessário avaliar algumas funções N-dimensionais numa grade, devido às regras de transmissão de arranjos do **Numpy** e do **SciPy**. Se este for o único propósito da geração de uma grade de malha, então você deve usar a outra instância da classe nd_grid, **ogrid[ ]** que gera uma grade “aberta” (esparsa) usando **newaxis** para criar ***N*** matrizes N-dimensionais, onde somente uma dimensão em cada arranjo tem comprimento maior que 1. Isso economiza memória e produz o mesmo resultado se a única finalidade da grade de malha for gerar pontos de amostra para avaliação de uma função N-dimensional. Polinômios Existem duas maneiras (intercambiáveis) de lidar com polinômios unidimensionais no Python. A primeira é usando a classe polinomial unidimensional, **poly1d** do **Numpy** (forma mais antiga).  A classe **poly1d** aceita coeficientes ou raízes polinomiais para inicializar um polinômio. O objeto polinomial pode então ser: manipulado em expressões algébricas, integrado, diferenciado, avaliado e até mostrado como um polinômio.<jupyter_code>from numpy import poly1d
p = poly1d([3,4,5])
print('Polinômio:\n',p, '\nRaízes:',p.roots, '\nOrdem:',p.order,'\np(0) =',p(0))
print('p(x)^2:\n',p*p)
print(p.integ())              # integração de p(x)
print(p.integ(k=6))           # cte de integração
print(p)
print(p.deriv())              # derivação de p(x)
p([3.1, 4, 5])             # avaliação do polinômio em x = 3.1, x = 4 e x = 5<jupyter_output><empty_output><jupyter_text>A outra maneira de lidar com polinômios é usando um vetor de coeficientes, com o primeiro elemento da matriz fornecendo o coeficiente de maior potência, usando o submódulo **Polynomial** do **Numpy** (forma mais recente). Existem funções explícitas para adicionar, subtrair, multiplicar, dividir, integrar, diferenciar e avaliar polinômios representados como sequências de coeficientes. Funções de Vetorização O **NumPy** fornece uma classe vetorizada para converter uma função **Python** comum, que aceita escalares e retorna escalares, em uma **`função vetorizada`** com as mesmas regras de transmissão das  funções **Numpy** (funções Universais ou ufuncs). Por exemplo, suponha uma função Python chamada **somasubtrai()**, assim definida:<jupyter_code>def somasubtrai(a,b):    # subtrai se a > b, e soma se a <= b
    if a > b:
        return a - b
    else:
        return a + b
    
print(somasubtrai(15,5))
print(somasubtrai(5,15))<jupyter_output>10
20<jupyter_text>A função **somasubtrai()** atua em duas variáveis escalares e retorna um resultado escalar. A classe **vectorize** pode ser usada para transformar esta função, de modo que possamos usar arranjos (vetores, matrizes) como argumentos e retorno da função:<jupyter_code>vec_somasubtrai = np.vectorize(somasubtrai)<jupyter_output><empty_output><jupyter_text>A função escalar **somasubtrai()** foi transformada na função **vec_somasubtrai()**, a qual recebe argumentos matriciais e retorna um resultado matricial:<jupyter_code>vec_somasubtrai([0,3,6,9],[1,3,5,7])<jupyter_output><empty_output><jupyter_text>Esta particular função poderia ter sido escrita em forma vetorial sem o uso de *vectorize*. No entanto, funções que empregam rotinas de otimização ou integração provavelmente só podem ser vetorizadas usando *vectorize*.  Manipulação de TiposObserve a diferença entre **np.iscomplex/np.isreal** e **np.iscomplexobj/np.isrealobj**. As funções **np.iscomplex/np.isreal** são baseadas em matrizes e retornam matrizes de uns e zeros fornecendo o resultado do teste elementar. As funções **np.iscomplexobj/np.isrealobj** são baseadas em objetos e retornam um escalar descrevendo o resultado do teste em todo o objeto.Frequentemente, é necessário obter apenas a parte real ou a imaginária de um número complexo. Enquanto números complexos e matrizes têm atributos (métodos) que retornam esses valores, se não tiver certeza se o objeto será ou não de valor complexo, é melhor usar as funções **np.real** e **np.imag**. Essas funções funcionam para qualquer coisa que possa ser transformada em um arranjo **Numpy**. Considere também a função **np.real_if_close** que transforma um valor complexo com pequena parte imaginária em um número real.Para verificar se um número é ou não escalar **((long) int, float, complex** ou matriz de *rank*-0) use a função **np.isscalar()** que retorna 1 ou 0. Rank ou Posto ou Característica de uma matriz: número de linhas ou colunas linearmente independentes da matriz.Para garantir que objetos sejam do tipo **Numpy** existe um dicionário predefinido de funções no **SciPy** específicas para isto: **np.cast**. As chaves do dicionário são os tipos de dados para os quais se deseja a conversão e os valores do dicionário armazenam funções para executar as conversões.<jupyter_code>np.pi
type(np.pi)
np.cast['f'](np.pi)
np.cast['i'](np.pi)
np.cast['l'](np.pi)<jupyter_output><empty_output><jupyter_text>Todos os tipos de dados armazenados no referido dicionário:<jupyter_code>print(np.cast.keys())<jupyter_output>dict_keys([<class 'numpy.uint32'>, <class 'numpy.int16'>, <class 'numpy.uint64'>, <class 'numpy.intc'>, <class 'numpy.int8'>, <class 'numpy.object_'>, <class 'numpy.float64'>, <class 'numpy.bool_'>, <class 'numpy.float32'>, <class 'numpy.datetime64'>, <class 'numpy.str_'>, <class 'numpy.complex64'>, <class 'numpy.uint16'>, <class 'numpy.bytes_'>, <class 'numpy.float16'>, <class 'numpy.clongdouble'>, <class 'numpy.int32'>, <class 'numpy.timedelta64'>, <class 'numpy.complex128'>, <class 'numpy.uintc'>, <class 'numpy.int64'>, <class 'numpy.void'>, <class 'numpy.longdouble'>, <class 'numpy.uint8'>])<jupyter_text>Exercício:  Criar uma matriz 4x4 e rotacioná-la para direita e para baixo, uma posição em cada dimensão.<jupyter_code>from numpy import arange, roll, copy
# Solução Perigosa: desenvolver código para a tarefa

def rotacDir(A):
    ult = A.shape[1]-1        # qtde de colunas
    vc = copy(A[:,ult])       # preserva a última coluna
    for i in range(ult,0,-1):
        A[:,i] = A[:,i-1]     # coluna à direita recebe coluna à esquerda
    A[:,0] = vc               # primeira coluna recebe últ. coluna preservada
    return A

def rotacAbaixo(A):
    ult = A.shape[0]-1        # qtde de linhas
    vl = copy(A[ult,:])       # preserva a última linha
    for i in range(ult,0,-1):
        A[i,:] = A[i-1,:]     # linha debaixo recebe linha acima
    A[0,:] = copy(vl)         # primeira linha recebe última linha preservada
    return A

A = arange(1,17).reshape(4,4)
B = copy(A)
print("Matriz Original: A = \n", A)
print("Matriz A Rotacionada uma linha para baixo:\n", rotacAbaixo(A))
print("Matriz A Rotacionada mais uma linha para baixo:\n", rotacAbaixo(A))
print('- '*35)
print("Matriz Original: B = \n", B)
print("Matriz B Rotacionada uma coluna para direita:\n", rotacDir(B))
print("Matriz B Rotacionada mais uma coluna para direita:\n", rotacDir(B))
print('- '*35)<jupyter_output>Matriz Original: A = 
 [[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]
 [13 14 15 16]]
Matriz A Rotacionada uma linha para baixo:
 [[13 14 15 16]
 [ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
Matriz A Rotacionada mais uma linha para baixo:
 [[ 9 10 11 12]
 [13 14 15 16]
 [ 1  2  3  4]
 [ 5  6  7  8]]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Matriz Original: B = 
 [[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]
 [13 14 15 16]]
Matriz B Rotacionada uma coluna para direita:
 [[ 4  1  2  3]
 [ 8  5  6  7]
 [12  9 10 11]
 [16 13 14 15]]
Matriz B Rotacionada mais uma coluna para direita:
 [[ 3  4  1  2]
 [ 7  8  5  6]
 [11 12  9 10]
 [15 16 13 14]]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<jupyter_text>Outra solução (mais indicada):<jupyter_code># Solução Indicada: reutilizar código existente
A = arange(1,17).reshape(4,4)
print("Matriz Original:\n", A)
print("Matriz A Rotacionada uma linha para baixo:\n", roll(A,1,0))
print("Matriz A Rotacionada mais uma linha para baixo:\n", roll(A,2,0))
print("Matriz Original:\n", A)
print("Matriz A Rotacionada uma coluna para direita:\n", roll(A,1,1))
print("Matriz A Rotacionada mais uma coluna para direita:\n", roll(A,2,1))<jupyter_output>Matriz Original:
 [[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]
 [13 14 15 16]]
Matriz A Rotacionada uma linha para baixo:
 [[13 14 15 16]
 [ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
Matriz A Rotacionada mais uma linha para baixo:
 [[ 9 10 11 12]
 [13 14 15 16]
 [ 1  2  3  4]
 [ 5  6  7  8]]
Matriz Original:
 [[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]
 [13 14 15 16]]
Matriz A Rotacionada uma coluna para direita:
 [[ 4  1  2  3]
 [ 8  5  6  7]
 [12  9 10 11]
 [16 13 14 15]]
Matriz A Rotacionada mais uma coluna para direita:
 [[ 3  4  1  2]
 [ 7  8  5  6]
 [11 12  9 10]
 [15 16 13 14]]<jupyter_text>Aplicação em PDS Sinal DiscretoUso de vetor para armazenamento das abscissas e das ordenadas para traçado de gráficos de linha, por exemplo:<jupyter_code>from pylab import stem
n = np.arange(-16,17)
x = np.cos(np.pi*n/8)
stem(n,x,use_line_collection=True);<jupyter_output><empty_output><jupyter_text>Sinal Contínuo<jupyter_code>import numpy as np
from pylab import plot, figure
figure(figsize=(6.4, 4.8))     # medidas em polegadas (larg x Alt)
t = np.arange(-16,17,1.3)
x = np.cos(np.pi*t/8)
plot(t,x);<jupyter_output><empty_output><jupyter_text>Elementos NumPy abordados:Funções:- array()- arange(), linspace()- zeros(), ones(), eye()- repeat()- vstack(), hstack()- roll()- poly1d()Atributos:- shape- dtype- TMétodos:- reshape()- resize()- dot()- astype()- sum(), min(), max(), mean()- transpose()**Subpacote: random**Funções:- random.rand()- random.randint() Até agora vimos como criar, como acessar e como manipular arranjos numéricos (vetores e matrizes) em **Numpy**. Na sequencia, veremos os pacotes `SCIPY, MATPLOTLIB` e `PANDAS`, todos eles construídos a partir do pacote **Numpy**. O pacote **SciPy** possui funções úteis à manipulação de sinais na análise de sistemas de Engenharia, em geral.O pacote **Matplotlib** permite a apresentação de dados na forma gráfica. Possui extensa variedade de tipos de gráficos, muito usados também na exibição de sinais contínuos e discretos.O pacote **Pandas** é direcionado à manipulação e análise de dados em Python, além de oferecer estruturas de dados e operações para tabelas numéricas e séries temporais. **Exercício**: Dada a matriz A, gere a matriz **sub_A** e a inversa de A (A-1):  Anexos Outras Funções Úteis Para processar a fase de um número complexo use as funções ***angle()*** e ***unwrap()***. Além disso, as funções ***linspace()*** e ***logspace()*** retornam amostras igualmente espaçadas numa escala linear ou logarítmica.  Por fim, é útil estar ciente dos recursos de indexação do **Numpy**. Deve-se mencionar a função ***select()*** que estende a funcionalidade do ***where*** para incluir várias condições e várias opções.  select(listacond, listaescolha, default = 0) A função ***select()*** é uma forma vetorizada da declaração **if** múltipla. Permite a construção rápida de uma função que retorna uma matriz de resultados com base em uma lista de condições. Cada elemento da matriz de retorno é retirado da matriz numa lista de opções correspondente à primeira condição na *listacond* que é verdadeira. Por exemplo:<jupyter_code>x = np.r_[-2:3]
x
np.select([x > 3, x >= 0], [0, x+2])
y = np.r_[-2:5]
y
np.select([y > 3, y >= 0], [-3, y+2])<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11998168917372397, 'fraction_numerical': 0.04664682993820096, 'mean_word_length': 4.532033426183844, 'pattern_counts': {'":': 0, '<': 168, '<?xml version=': 0, '>': 176, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 9, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '40', 'dir': 'jupyter-structured-clean-dedup', 'id': '621323', 'license': 'Apache-2.0', 'n_tokens_mistral': 9031, 'n_tokens_neox': 8339, 'n_words': 2786, 'path': 'notebooks/2_Packages/0.Numpy.ipynb', 'repo_name': 'kaw19/python', 'size': '21845'}