terça-feira, 14 de abril de 2020

Ordenando elementos com NumPy

Ordenando elementos com NumPy


Ordenar os elementos de uma matriz é por os elementos em ordem. Por exemplo, a matriz [3, 7, 3, 4] é uma matriz desordenada. Uma matriz ordenada seria [3, 3, 4, 7]. Os objetos da ndarray da biblioteca numpy têm uma função chamada sort. A função sort recebe uma matriz desordenada e retorna uma matriz ordenada.
Exemplo
import numpy as np

array = np.array([1, 3, 5, 2, 4])
matriz_ordenada = np.sort(array)
print('Matriz não ordenada: ', array)
print('Matriz ordenada: ', matriz_ordenada)
Com o método sort também é possível ordenar outros tipos de dados, como a string.
Exemplo
import numpy as np

array = np.array(['banana', 'abacaxi', 'kiwi', 'melão'])
matriz_ordenada = np.sort(array)
print('Matriz ordenada: ', matriz_ordenada)
As strings são ordenadas seguindo a ordem do dicionário. Primeiro as palavras que começam com a, depois as que começam com b e assim por diante.
Se for passado uma matriz com duas dimensões os elementos serão ordenados com os elementos de sua dimensão. Assim os elementos das duas dimensões não se misturam. Cada dimensão é ordenada independente da outra.
Exemplo
import numpy as np

array = np.array([[2, 3, 1], [6, 5, 4]])
matriz_ordenada = np.sort(array)
print('Matriz ordenada: ', matriz_ordenada)
O mesmo vale para as matrizes com três ou mais dimensões.

Procurando valores numa array com NumPy

Procurando valores numa array com NumPy


A biblioteca numpy tem uma função chamada where que retorna uma tupla com os index onde a função achou elementos correspondentes à pesquisa. A busca é feita na matriz toda. Por isso se a matriz tiver mais de um numero correspondente à pesquisa o seu index vai estar na matriz.
Exemplo
import numpy as np

array = np.array([0, 1, 2, 0, 3, 4, 5, 0, 6])
a = np.where(array == 0)
print(a)
O resultado desse exemplo são os números zero, três e sete porque existem três elementos que correspondem à pesquisa e eles se encontram na posição zero, três e sete. Lembre-se que o index de uma matriz começa na posição zero.
Nesse exemplo o resultado é uma tupla com uma array indicando os index dos elementos correspondentes da pesquisa e o seu tipo de dado. No caso um inteiro de 32 bytes. Na versão do python 2.7 o resultado será apenas o index dos elementos da pesquisa.
Com a função where é possível localizar a posição de todos os números par da matriz.
Exemplo
import numpy as np

array = np.array([1, 2, 3, 4, 5, 6, 7, 8])
a = np.where(array%2 == 0)
print(a)
Também é possível localizar os números ímpares da matriz com a função where.
Exemplo
import numpy as np

array = np.array([1, 2, 3, 4, 5, 6, 7, 8])
a = np.where(array%2 == 1)
print(a)

Método Searchsorted

Searchsorted é um método que retorna o index onde um elemento deveria ser adicionado para manter uma ordem. Por exemplo, na matriz [1, 2, 5, 6] o elemento quatro deveria ser adicionado em qual index para a matriz continuar ordenada? Essa resposta você pode obter com o método searchsorted.
Exemplo
import numpy as np

array = np.array([1, 2, 5, 6])
a = np.searchsorted(array, 4)
print(a)
O método searchsorted recebe dois argumentos: a matriz onde a busca será feita e o numero que se deseja adicionar na matriz. O resultado desse exemplo é o numero dois. Porque se o numero quatro for adicionado no index dois a matriz continuará ordenada.
A função searchsorted começa a pesquisa do lado direito, do menor para o maior (na maioria dos casos). Para inverter esse comportamento podemos passar o valor do parâmetro side como right (direita). Assim a função começará a pesquisa do fim para o começo da matriz (da direita para a esquerda).
Exemplo
import numpy as np

array = np.array([1, 2, 5, 6, 8, 9])
a = np.searchsorted(array, 7, side='right')
print(a)

Múltiplos valores

A função searchsorted aceita a pesquisa por múltiplos valores. É só passar uma lista com os valores que se deseja pesquisar.
Exemplo
import numpy as np

array = np.array([1, 3, 5])
a = np.searchsorted(array, [2, 4, 6])
print(a)
O resultado da função searchsorted, quando se passa uma lista para pesquisa, é uma lista com os index das posições onde os elementos da pesquisa devem ser adicionados para a matriz continuar ordenada.

segunda-feira, 13 de abril de 2020

Dividindo arrays com NumPy

Dividindo arrays com NumPy


Dividir uma matriz com a função Split é fácil. É só passar como primeiro argumento a matriz que deseja dividir e como segundo argumento o numero de divisão. A função Split vai retornar uma lista com o numero de matrizes desejado. Por exemplo, dividindo uma matriz com seis elementos em três pedaços, a função Split vai retornar uma lista com três matrizes separadas.
Exemplo
import numpy as np

array = np.array([1, 2, 3, 4, 5, 6])
matriz = np.split(array, 3)

print(matriz)
Se a divisão não for exata a função Split vai lançar um erro. Tentar dividir uma matriz com sete elementos em três matrizes diferentes causa um erro porque a divisão não é exata. Para corrigir isso podemos utilizar a função array_split.

Função array_split

A função array_split consegue dividir uma matriz em várias, mesmo que a divisão não seja exata. O elemento restante vai ser adicionado na primeira matriz. Por exemplo, se tentamos dividir uma matriz com sete elementos em três, vai sobrar um elemento. Na função Split ocorreria um erro, na função array_split a primeira matriz fica com mais elementos que as demais.
Exemplo
import numpy as np

array = np.array([1, 2, 3, 4, 5, 6, 7])
matriz = np.array_split(array, 3)

print(matriz)
Nesse exemplo se a matriz tivesse oito elementos, para dividir em três, as duas primeiras matrizes ficariam com mais elementos que as demais.
Exemplo
import numpy as np

array = np.array([1, 2, 3, 4, 5, 6, 7, 8])
matriz = np.array_split(array, 3)

print(matriz)
A função array_split tenta acomodar os elementos restantes nas primeiras matrizes. Por isso quando a divisão de elementos por matriz não for exata, as primeiras matrizes ficaram com mais elementos que as demais.

Acessando o resultado de array_split

Por ser uma lista de matrizes podemos acessar cada nova matriz diretamente com seu index.
Exemplo
import numpy as np

array = np.array([1, 2, 3, 4, 5, 6, 7, 8])
matriz = np.array_split(array, 3)

print(matriz[0])
print(matriz[1])
print(matriz[2])
Outro jeito de acessar essas array em uma lista é com o laço for.
Exemplo
import numpy as np

array = np.array([1, 2, 3, 4, 5, 6, 7, 8])
matriz = np.array_split(array, 3)

for i in matriz:
  print(i)
É bom lembrar que os elementos dessa matriz são objetos da classe numpy.

Juntando arrays com Numpy

Juntando arrays com Numpy


Podemos juntar duas ou mais matriz usando o método concatenate. O método concatenate recebe dois parâmetros. O primeiro é uma tupla com as matrizes que se deseja mesclar. E o segundo é o eixo. Se não for atribuído um valor para o parâmetro eixo o seu valor padrão é zero. Então a função concatenate retornará uma matriz com uma dimensão. Se for passado o valor um, a função retornará uma matriz com duas dimensões.
Exemplo
import numpy as np

array1 = np.array([1, 2, 3])
array2 = np.array([5, 6, 7])

# padrão axis=0
matriz = np.concatenate((array1, array2))

print(matriz)
Juntando duas matrizes 2D.
Exemplo
import numpy as np

array1 = np.array([[1, 2], [3, 4]])
array2 = np.array([[5, 6], [7, 8]])

matriz = np.concatenate((array1, array2), axis=1)

print(matriz)
Repare que o numero passado ao parâmetro axis define em quantas pastes cada matriz vai ser dividida. Nesse exemplo, passamos duas matrizes com duas dimensões cada, e passamos o valor um ao parâmetro axis. Assim as duas dimensões da array1 vão ser mescladas em um eixo, transformando a array1 numa matriz com uma dimensão. O mesmo acontece com a array2. Se, nesse exemplo, passássemos o valor zero (zero eixos) o resultado da função concatenate seria uma matriz com duas dimensões com quatro linhas e duas colunas. Passando o valor um o resultado seria uma matriz com duas linhas e quatro colunas. A mesma lógica se aplica quando passamos matrizes com três dimensões.
Exemplo
import numpy as np

array1 = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
array2 = np.array([[[9, 10], [11, 12]], [[13, 14], [15, 16]]])

print('axis=0')
matriz = np.concatenate((array1, array2))
print(matriz)
print('axis=1')
matriz = np.concatenate((array1, array2), axis=1)
print(matriz)
print('axis=2')
matriz = np.concatenate((array1, array2), axis=2)
print(matriz)
Lembre-se que a função concatenate só funciona com matrizes com o mesmo numero de dimensões. Se for passado uma matriz com o numero de dimensões diferente das outras um erro será lançado.

Juntando matrizes com a função stack

A função stack empilhar os elementos de uma matriz, um em cima do outro, de acordo com o eixo passado para a função como argumento. A função concatenate junta as matrizes na horizontal e a função stack junta os elementos da matriz na horizontal.
Exemplo
import numpy as np

array1 = np.array([1, 2, 3])
array2 = np.array([4, 5, 6])

print('Função stack: Vertical')
matriz = np.stack((array1, array2), axis=1)
print(matriz)

print('Função concatenate: Horizontal')
matriz = np.concatenate((array1, array2))
print(matriz)

Juntando matrizes com a função hstack

Se você quiser empilhar os elementos da matriz por linha a função hstack pode ser útil.
Exemplo
import numpy as np

array1 = np.array([1, 2, 3])
array2 = np.array([4, 5, 6])

array3 = np.array([[1, 2, 3], [4, 5, 6]])
array4 = np.array([[7, 8, 9], [10, 11, 12]])

print('Matrizes com uma dimensão')
matriz = np.hstack((array1, array2))
print(matriz)

print('Matrizes com duas dimensões')
matriz = np.hstack((array3, array4))
print(matriz)

Juntando matrizes com a função vstack

Para empilhar os elementos das matrizes por coluna a função é a vstack.
Exemplo
import numpy as np

array1 = np.array([[1, 2, 3], [4, 5, 6]])
array2 = np.array([[7, 8, 9], [10, 11, 12]])

matriz = np.vstack((array1, array2))
print(matriz)

Juntando matrizes com a função dstack

A função dstack mescla os elementos da array por profundidade (eixo z). Por isso ela retorna uma array com três dimensões.
Exemplo
import numpy as np

array1 = np.array([1, 2, 3])

array2 = np.array([4, 5, 6])

matriz = np.dstack((array1, array2))
print(matriz)
print(matriz.ndim)
Para ficar mais claro tente passar para as funções concatenate, stack, hstack, vstack e dstack matrizes com diferentes números de dimensões.

domingo, 12 de abril de 2020

Iterando matrizes com a biblioteca NumPy

Iterando matrizes com a biblioteca NumPy


Iterar é percorrer os elementos de um objeto um após o outro. Iterar uma matriz da numpy pode ser feita com o loop for. O loop for também pode percorrer matrizes multidimensionais, é só aninhar os loop. Se for usado apenas um loop for numa matriz 3D o resultado será algumas matrizes 2D. Nas matriz com apenas uma dimensão podemos acessar os elementos da matriz um por um só com um laço for.
Exemplo
import numpy as np

array = np.array([1, 2, 3, 4, 5, 6])

for i in array:
  print(i)

Iterando numa array 2D

Iterando com um único laço for, numa matriz com duas dimensões, o resultado será uma matrizes com uma dimensão em cada execução do laço.
Exemplo
import numpy as np

array = np.array([[1, 2, 3], [4, 5, 6]])

for i in array:
  print(i)

Iterando numa array 3D

Iterando com um único laço for, numa matriz com três dimensões, o resultado será uma matriz com duas dimensões em cada execução do laço.
Exemplo
import numpy as np

array = np.array([[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]])

for i in array:
  print(i)

Cada elemento de uma array multidimensional

Para acessar cada elemento de uma matriz multidimensional, precisamos criar um laço for para cada nível. Por exemplo, para acessar todos os elementos de uma matriz com duas dimensões precisamos utilizar dois laços for. Um que retorna uma matriz com uma dimensão, e outro que itera sobre essa matriz retornada pelo primeiro laço for. Do mesmo jeito é feito com matriz com três dimensões.
Exemplo: Array com duas dimensões
import numpy as np

array = np.array([[1, 2, 3], [4, 5, 6]])

for x in array:
  for y in x:
    print(y)
Exemplo: Array com três dimensões
import numpy as np

array = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])

for x in array:
  for y in x:
    for z in y:
      print(z)

Iterando arrays usando a função nditer

Com a função nditer você não precisar se preocupar com quantas dimensões uma matriz tem. Imagine que a função nditer retorna uma matriz com uma dimensão. Não importa o numero de dimensões da matriz passada como argumento para a função. O resultado vai ser sempre uma matriz com uma única dimensão. Com essa matriz com uma dimensão fica fácil acessar cada elemento da matriz com laço for.
Exemplo
import numpy as np

array = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])

for i in np.nditer(array):
  print(i)

Iterando saltando elementos

Se por algum motivo precisamos saltar um ou mais elementos podemos utilizar os exemplos abaixo.
Exemplo: Arrays com uma dimensão
import numpy as np

array = np.array([1, 2, 3, 4, 5, 6])

for x in np.nditer(array[::2]):
  print(x)
Exemplo: Arrays com duas dimensões
import numpy as np

array = np.array([[1, 2, 3], [4, 5, 6]])

for x in np.nditer(array[:, ::2]):
  print(x)
Exemplo: Arrays com três dimensões
import numpy as np

array = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])

for x in np.nditer(array[:, :, ::2]):
  print(x)

Index da iteração

Se durante uma iteração você precisar do index do objeto iterado a função ndenumerate pode ser usada. A função ndenumerate retorna uma tupla com o index do objeto e o próprio objeto.
Exemplo
import numpy as np

array = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])

for index, i in np.ndenumerate(array):
  print(index, i)
Nesse exemplo a tupla retornada pela função ndenumerate tem três números, cada um referente ao index de cada matriz. Com uma matriz de duas dimensões a tupla teria dois números e com uma matriz de uma dimensão, teria apenas um numero.

sábado, 11 de abril de 2020

Forma da matriz com NumPy

Forma da matriz com NumPy


A forma da matriz é definida pelo numero de elementos de cada dimensão. Para saber qual é a forma de uma matriz podemos utilizar o atributo shape dos objetos numpy. O atributo shape retorna uma tupla com o numero de dimensões da matriz e o numero de elementos em cada dimensão. Se o numero de elementos for diferente em cada dimensão a tupla só retorna o numero de dimensões.
Exemplo
import numpy as np

matriz = np.array([[1, 2, 3], [9, 8, 7]])
print(matriz.shape)
Nesse exemplo o resultado é uma tupla com os valores dois e três. O primeiro valor (2) se refere ao numero de dimensões da matriz. E o segundo número (3) se refere ao número de elementos de cada matriz. Lembre-se que se os números de elementos em cada matriz for diferente o valor de shape só terá um numero, o de dimensões.

Mais dimensões

Vamos entender melhor o funcionamento do atributo shape criando uma matriz mais complexa com cinco dimensões.
Exemplo
import numpy as np

matriz = np.array([[1, 2, 3], [9, 8, 7]], ndmin=5)
print(matriz)
print('Forma da matriz: ', matriz.shape)
O resultado desse exemplo será uma tupla com cinco números referentes ao números de dimensões e ao número de elementos em cada matriz (o último). Os primeiros três números têm o valor um. Porque esse é o numero de dimensões nessas dimensões (uma dimensão). O quarto numero se refere a dimensão com duas dimensões por isso o seu valor é dois. E o último numero se refere ao numero de elementos em cada dimensão.

Alterando a forma de uma matriz

Alterar a forma de uma matriz é transformá-la em uma matriz com o numero de dimensões diferente. Os elementos da matriz ficaram intactos, apenas a forma como eles estão dispostos na matriz é que vai mudar.

1D para 2D

Vamos pegar uma matriz com uma dimensão e alterar a sua forma para duas dimensões. Por exemplo, vamos pegar uma matriz de uma dimensão com oito elementos e transformá-la numa matriz com duas dimensões e com quarto elementos a dimensão mais interna. Isso será feito com o método reshape.
Exemplo
import numpy as np

matriz = np.array([1, 2, 3, 4, 5, 6, 7, 8])
nova_matriz = matriz.reshape(2, 4)
print(nova_matriz)
O primeiro argumento do método reshape é o numero de matrizes desejada e o segundo o numero de elementos em cada matriz. É importante lembrar que a divisão deve ser exata. Caso contrario o erro ValueError vai ser lançado.

1D para 3D

Para remodelar uma matriz com uma dimensão para uma de três, também utilizamos o método reshape. A única diferença é o numero de argumentos passado para a função.
Exemplo
import numpy as np

matriz = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
nova_matriz = matriz.reshape(2, 3, 2)
print(nova_matriz)
Fica mais fácil entender se você imaginar que o primeiro argumento divide a matriz ao meio no eixo x. O segundo argumento divide as duas matriz ao meio no eixo y. E o terceiro argumento colocas essas duas matriz (com três matrizes cada) uma atrás da outra. Assim você tem uma matriz com três dimensões.

Copia ou visualização

O método reshape não retorna uma nova matriz com o numero desejado de dimensões. Ele apenas da uma visualização da matriz com uma outra forma.
Exemplo
import numpy as np

matriz = np.array([1, 2, 3, 4, 5, 6, 7, 8])
nova_matriz = matriz.reshape(2, 4)
print(nova_matriz)
print(nova_matriz.base)
Nesse exemplo se o objeto nova_matriz fosse uma cópia da matriz o valor do atributo base seria None.

3D, 2D para 1D

O processo de transformar matriz 1D para 2D e 3D pode seguir o caminho inverso. Fazer isso com o método reshape é muito fácil. Basta passar como argumento o numero menos um. Assim teremos uma visualização da matriz 3D, 2D em 1D.
Exemplo
import numpy as np

matriz = np.array([[1, 2, 3], [4, 5, 6]])
print(matriz.reshape(-1))
matriz = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
print(matriz.reshape(-1))
Lembre-se que o método reshape não altera a matriz apenas retorna uma visualização dela com um numero diferente de dimensões.

Copiar e ler uma matriz com NumPy

Copiar e ler uma matriz com NumPy


Quando é feita uma copia de uma matriz, qualquer alteração feita nessa matriz não afeta a original. E quando a matriz é acessada o seu conteúdo fica intacto, sem alterações. Os objetos da biblioteca numpy tem os métodos copy e view. O método copy faz uma copia da matriz e retorna uma nova matriz. Já o método view monstra a matriz do objeto, sem alterá-lo ou criar um novo.
Exemplo
import numpy as np

matriz = np.array([1, 2, 3])
copia_matriz = matriz.copy()

copia_matriz[0] = 42

print('Matriz original: ', matriz)
print('Cópia da matriz: ', copia_matriz)
Com esse exemplo é possível perceber que alterando a cópia da matriz, que foi feita com o método copy, as alterações não afetam a matriz original. As alterações são feitas apenas na cópia da matriz, que é uma matriz independente. O que não ocorre com o método view.
Exemplo
import numpy as np

matriz = np.array([1, 2, 3])
mesma_matriz = matriz.view()

mesma_matriz[0] = 42

print('Matriz original: ', matriz)
print('Cópia da matriz: ', mesma_matriz)
O método view apenas torna possível acessar a mesma matriz com duas variáveis diferentes. Na pratica a nova variável se torna apenas uma apelido para a matriz. Todas as alterações feitas na matriz original afetam o seu “apelido” e vice-versa.

Como saber se um objeto da classe numpy tem dados ou não?

É possível saber se um objeto tem dados ou é só um apelido para um objeto com o atributo base. Se um objeto tiver dados o valor do atributo base vai ser None. E se não tiver o valor retornado será o conteúdo da matriz.
Exemplo
import numpy as np

matriz = np.array([1, 2, 3])
a = matriz.copy()
b = matriz.view()

print('Cópia de um objeto (Tem dados): ', a.base)
print('Apelido de um objeto (Não tem dados): ', b.base)
print('Objeto (Tem dados): ', matriz.base)
Com o método copy o valor do atributo base será None e com o método view o valor será o conteúdo da matriz base.