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.

sexta-feira, 10 de abril de 2020

Tipos de dados da biblioteca NumPy

Tipos de dados da biblioteca NumPy


A linguagem python tem alguns tipos de variáveis já definidos. Cada tipo de variável é utilizada para trabalhar com um tipo de dado especifico. Uma variável do tipo string é utilizada para trabalhar com sequências de caracteres. Enquanto uma variável do tipo inteiro é utilizada para trabalhar com números.
A biblioteca Numpy também tem seus tipos de dados definido. Cada um definido para trabalhar com um tipo de dado especifico.
Veja abaixo os tipos de dados que podem ser usados com a biblioteca numpy.
  • i - números inteiros
  • u - números inteiros sem sinal
  • b - boolean
  • f - números com ponto flutuante
  • c - números com ponto flutuante complexos
  • m - timedelta
  • M - datetime
  • O - object
  • S - string
  • U - string sem sinal
  • V - void

Verificando o tipo de dado de uma matriz

Com a propriedade dtype, dos objetos matriz da numpy, é possível saber qual é o tipo de dado da matriz. Essa propriedade guarda o tipo de dado da matriz. Podemos acessar essa propriedade diretamente no objeto.
Exemplo
import numpy as np

matriz = np.array([1, 2, 3])
print(matriz.dtype)
Com uma matriz de string o processo é o mesmo.
Exemplo
import numpy as np

matriz = np.array(['Melão', 'Abacaxi', 'Maçã'])
print(matriz.dtype)

Criando uma matriz com o tipo definido

Imagine que você precisa dos números 1, 2 e 3 como strings e não como inteiros. Se for criada a matriz do jeito tradicional os números vão ser do tipo int64 (inteiro). Podemos mudar esse comportamento passando o tipo de dado desejado no argumento dtype da função array.
Exemplo
import numpy as np

matriz = np.array([1, 2, 3], dtype='S')
print(matriz.dtype)
Se um elemento da matriz não poder ser convertido o erro ValueError vai ser lançado.
Exemplo
import numpy as np
try:
  matriz = np.array([1, 2, 3, 'a'], dtype='i')
except ValueError:
  print('Erro: ValueError')

Tamanho da variável

Com os tipos de dados i, u, f, S e U podemos informar o tamanho que a variável vai ocupar na memoria do computador.
Exemplo
import numpy as np

matriz = np.array([1, 2, 3], dtype='i4')

print(matriz)
print(matriz.dtype)
Nesse exemplo cada elemento da matriz vai ocupar 4 bytes na memoria do computador. Quanto maior for o tamanho da memoria ocupada pela variável, maior é a faixa de números que podem ser guardados. Nesse exemplo, cada elemento da matriz pode guardar um numero compreendido entre -2,147,483,648 a +2,147,483,647.
Exemplo
import numpy as np

a = np.array([9, 32767], dtype='i2')
b = np.array([2, 2147483647], dtype='i4')
c = np.array([1, 9223372036854775807], dtype='i8')

# 16 bytes -32,768 a +32,767
print(a)
print(a.dtype)

# 32 bytes -2,147,483,648 a +2,147,483,647
print(b)
print(b.dtype)

# 64 bytes -9,223,372,036,854,775,808 a +9,223,372,036,854,775,807
print(c)
print(c.dtype)
É interessante notar que mesmo quando criamos uma variável do tipo inteiro, de 8 bytes, e salvamos nela um numero pequeno, como o dois, ela ainda vai ocupar os 8 bytes.

quinta-feira, 9 de abril de 2020

Partindo uma matriz com NumPy

Partindo uma matriz com NumPy



Não é sempre que precisamos apenas de um elemento da matriz ou de uma matriz inteira. Muitas vezes precisamos de pedaços da matriz. Para obter esses pedaços da matriz precisamos fatiar a matriz. Quando vamos pegar um pedaço da matriz precisamos indicar de que elemento vai começar o nosso “corte” e o elemento final.
Exemplo
import numpy

matriz = numpy.array([1, 2, 3, 4, 5, 6])
print(matriz[1:4])
Nesse exemplo vamos obter os números dois, três e quatro. Isso porque o fatiamento da matriz começou no segundo elemento e foi até o quarto elemento. Lembre-se que o index da matriz começa em zero. Uma boa maneira de entender melhor é imaginar uma divisão antes de cada numero. Assim os números que colocamos entre os colchetes não contam os elementos e sim essas divisões imaginarias. Por isso é apresentado três números e não quatro.
É possível pegar os elementos do começo de uma matriz até um determinado elemento. Ou de um determinado elemento até o fim da matriz.
Exemplo
import numpy

matriz = numpy.array([1, 2, 3, 4, 5, 6])
# do primeiro elemento até o quarto elemento
print(matriz[:4])
# do quinto elemento até o último
print(matriz[4:])
Repare que na segunda vez que chamamos a função print o quarto elemento não aparece. Isso porque não contamos os elementos, mas sim a divisão imaginaria entre cada número.

Partes de uma matriz com index negativo

É possível utilizar index negativo para acessar uma parte de uma matriz. A única diferença desse modo é que o index negativo começa do fim da matriz para o começo. E o index um faz referencia ao penúltimo elemento.
Exemplo
import numpy

matriz = numpy.array([1, 2, 3, 4, 5, 6])
print(matriz[-3:-1])

Pulando elementos de um pedaço da matriz

Com as matrizes da biblioteca numpy é possível acessar um determinado numero de elementos dentro de uma faixa predefinida. Na matriz além de definir a faixa de elementos que você que acessar é possível definir o numero de elementos que vão ser salteados. Por exemplo, no exemplo acima se você quisesse obter os números um, três e cinco era só definir a faixa do elemento zero até o sexto elemento e o passo sendo dois. Lembre que nas faixas contamos as divisões imaginarias antes dos números.
Exemplo
import numpy

matriz = numpy.array([1, 2, 3, 4, 5, 6])
print(matriz[0:6:2])
Não é preciso indicar uma faixa se quiséssemos acessar todos os elementos da matriz de acordo com o passo. Assim só precisamos definir o passo.
Exemplo
import numpy

matriz = numpy.array([1, 2, 3, 4, 5, 6, 7, 8])
print(matriz[::2])

Partindo uma matriz de duas dimensões

Com as matrizes de duas dimensões o conceito é o mesmo. Primeiro indicamos o index da matriz de uma dimensão e depois indicamos a faixa que queremos acessar. Imagine que precisamos pegar os três últimos elementos dessa matriz: [[1, 2, 3], [4, 5, 6]]. Assim vamos indicar o index da matriz com uma dimensão que queremos acessar, no caso um, e definimos a faixa que queremos.
Exemplo
import numpy

matriz = numpy.array([[1, 2, 3], [4, 5, 6]])
print(matriz[1, 0:3])

Acessando dois elementos com o mesmo index

Numa matriz com duas dimensões é possível acessar dois elementos, um elemento de cada matriz, com o mesmo index. Para isso indicamos o intervalo (que deve abranger as duas matrizes) e o index dos dois elementos das matrizes.
Exemplo
import numpy

matriz = numpy.array([[1, 2, 3], [4, 5, 6]])
print(matriz[0:2, 1])
Note que o intervalo se refere às duas matrizes e o index ao index do elemento em cada matriz. Nesse caso o intervalo são as duas matrizes e o index é o do número dois e do número cinco.