{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# NumPy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O NumPy é uma das principais bibliotecas para computação científica em Python. Com ela é possível criar arrays multidimensionais de alta performance, além de possuir ferramentas para manipular estes arrays. O NumPy serve de base para outras bibliotecas e frameworks na área de ciência de dados e inteligência artificial." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O NumPy é frequentemente importado da seguinte forma:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Arrays\n", "\n", "Os arrays do NumPy podem armazenar dados multidimensionais, porém todos os dados devem ser do mesmo tipo.\n", "\n", "Vamos criar um array a partir de uma lista." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "a = np.array([1, 2, 3])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Podemos acessar os valores do array e alterá-los." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 2 3\n", "[9 2 3]\n" ] } ], "source": [ "print(a[0], a[1], a[2])\n", "\n", "a[0] = 9\n", "\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A propriedade `shape` retorna o tamanho do array." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(3,)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.shape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vamos agora criar um array com duas dimensões." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[1 2 3]\n", " [4 5 6]]\n", "(2, 3)\n" ] } ], "source": [ "b = np.array([[1, 2, 3], [4, 5, 6]])\n", "\n", "print(b)\n", "print(b.shape)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A propriedade `shape` agora traz o tamanho do array em cada uma das dimensões. Nesse caso, interpretamos o tamanho como: 2 linhas e 3 colunas." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A indexação para arrays com 2 ou mais dimensões é feita através de uma tupla." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 2 3\n", "4 5 6\n" ] } ], "source": [ "print(b[0, 0], b[0, 1], b[0, 2])\n", "print(b[1, 0], b[1, 1], b[1, 2])" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "9 2 3\n", "4 5 6\n" ] } ], "source": [ "b[0, 0] = 9\n", "print(b[0, 0], b[0, 1], b[0, 2])\n", "print(b[1, 0], b[1, 1], b[1, 2])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O NumPy traz algumas funções para facilitar a criação de arrays." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`np.zeros` cria um array com todos os elementos igual a zero." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[0. 0.]\n", " [0. 0.]]\n" ] } ], "source": [ "a = np.zeros((2, 2)) # (2, 2) é o tamanho do array\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`np.ones` cria um array com todos os elementos igual a um." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[1. 1.]\n", " [1. 1.]]\n" ] } ], "source": [ "b = np.ones((2, 2)) # (2, 2) é o tamanho do array\n", "print(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`np.full` cria um array com todos os elementos iguais a uma constante passada como parâmetro." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[7 7]\n", " [7 7]]\n" ] } ], "source": [ "c = np.full((2, 2), 7) # (2, 2) é o tamanho do array e 7 é a constante\n", "print(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`np.arange` cria um array com um intervalo de números." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0 1 2 3 4 5 6 7 8 9]\n", "[1 2 3 4 5 6 7 8]\n", "[1 3 5 7]\n" ] } ], "source": [ "d1 = np.arange(10) # intervalo de 0 até antes de 10\n", "print(d1)\n", "\n", "d2 = np.arange(1, 9) # intervalo de 1 até antes de 9\n", "print(d2)\n", "\n", "d3 = np.arange(1, 9, 2) # intervalo de 1 até antes de 9 com um passo de tamanho 2\n", "print(d3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`np.eye` Cria uma matriz identidade." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[1. 0.]\n", " [0. 1.]]\n" ] } ], "source": [ "e = np.eye(2) # 2 é o tamanho da matriz identidade\n", "print(e)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`np.random.random` Cria um array com valores aleatórios." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[0.11682408 0.89582127]\n", " [0.8772504 0.33403101]]\n" ] } ], "source": [ "f = np.random.random((2, 2)) # (2, 2) é o tamanho do array\n", "print(f)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tipos de dados\n", "\n", "Ao criar um array, o NumPy tenta inferir o tipo de dado dos elementos." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "int64\n", "float64\n" ] } ], "source": [ "a = np.array([1, 2, 3])\n", "print(a.dtype)\n", "\n", "b = np.array([1.0, 2.0, 3.0])\n", "print(b.dtype)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Entretanto, é possível explicitar o tipo que deve ser usado." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "float64\n" ] } ], "source": [ "a = np.array([1, 2, 3], dtype=float)\n", "print(a.dtype)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O NumPy suporta diversos tipos de dados que podem ser usados para armazenar de forma eficiente os diferentes valores suportados pela linguagem. Para mais detalhes: https://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Indexação\n", "\n", "Além da indexação vista anteriormente, o NumPy fornece outras maneiras de acessar os elementos de um array." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Slicing\n", "\n", "Assim como as listas do Python, os arrays do NumPy também podem \"fatiados\".\n", "A sintaxe do slice é: `meu_array[início:fim]`. Onde `início` é a posição de início e `fim` é o limite final do slice." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([2, 3, 4])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.array([1, 2, 3, 4, 5])\n", "a[1:4] # começa na posição 1 e termina antes da posição 4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Omitindo o `início` o slice é feito a partir do primeiro elemento. Omitindo o `fim` o slice é feito até o último elemento." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1 2 3 4]\n", "[3 4 5]\n" ] } ], "source": [ "print(a[:4])\n", "print(a[2:])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Arrays multidimensionais também suportam slicing." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 1 2 3 4]\n", " [ 5 6 7 8]\n", " [ 9 10 11 12]]\n" ] } ], "source": [ "b = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])\n", "print(b)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[2, 3],\n", " [6, 7]])" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b[0:2, 1:3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A figura abaixo ilustra o resultado do slicing anterior. Na primeira dimensão, foi especificado o slice `0:2`, que é representado pelo retângulo verde na figura. Esse slice é composto da primeira e da segunda linha. Na segunda dimensão, foi especificado o slice `1:3`, representado pelo retângulo vermelho. Esse slice é composto da segunda e da terceira coluna. O resultado do slicing é a interseção dos retângulos verde e vermelho." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![](mdslice.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Podemos combinar slicing e atribuição." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 0 1 2 3 4 10 10 10 10 10]\n", "[ 0 1 20 30 40 5 6 7 8 9]\n" ] } ], "source": [ "a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])\n", "a[5:] = 10\n", "print(a)\n", "\n", "b = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])\n", "b[2:5] = np.array([20, 30, 40]) # esse array precisa ser do mesmo tamanho do slice\n", "print(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O resultado de um slice é uma espécie de janela para o array original. Assim, modificando o slice você modificará o array original." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[9 3]\n", "[1 9 3 4 5]\n" ] } ], "source": [ "a = np.array([1, 2, 3, 4, 5])\n", "a_slice = a[1:3]\n", "\n", "a_slice[0] = 9\n", "print(a_slice)\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Indexação Avançada\n", "\n", "A indexação avançada é utilizada para criar novos arrays a partir de um array original através de máscaras definidas por números inteiros ou valores booleanos." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Máscaras Booleanas" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Para máscaras booleanas, definimos um array com a mesma quantidade de elementos do array original, onde True indica que o elemento naquela posição vai fazer parte do novo array e False indica que o elemento naquela posição não vai fazer parte do array." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5])" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])\n", "mask = [True, True, True, True, True, True, False, False, False, False]\n", "\n", "a[mask]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Podemos criar máscaras booleanas aplicando operadores lógicos aos arrays." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ True, True, True, True, True, True, False, False, False,\n", " False])" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a <= 5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Com isso, conseguimos usar a máscara booleana de forma direta." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5])" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[a <= 5]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Usando máscaras booleanas, podemos filtrar o array de acordo com os seus elementos. Por exemplo, para criar um array apenas com números pares, temos:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 2, 4, 6, 8])" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[a%2 == 0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As máscaras booleanas também podem auxiliar na atribuição de novos valores. No exemplo abaixo, vamos substituir todas as entradas nulas por zero." ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[20 50 0 35 90 0 110]\n" ] } ], "source": [ "b = np.array([20, 50, None, 35, 90, None, 110])\n", "b[b == None] = 0\n", "\n", "print(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As máscaras precisam ter as mesmas dimensões do array original." ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[False False]\n", " [ True True]\n", " [ True True]]\n" ] } ], "source": [ "a = np.array([[1, 2], [3, 4], [5, 6]])\n", "mask = a > 2\n", "print(mask)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Entretanto, a indexação usando máscaras multidimensionais retornam arrays unidimensionais." ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([3, 4, 5, 6])" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[mask]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Indexação com arrays de inteiros" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Com a indexação com arrays de inteiros, novos arrays são criados escolhendo os elementos do array original de acordo com suas posições." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([10, 50, 90])" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.array([0, 10, 20, 30, 40, 50, 60, 70 , 80, 90])\n", "a[[1, 5, 9]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Na indexação, os índices não precisam aparecer em ordem." ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([50, 10, 90])" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[[5, 1, 9]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Os índices também podem ser repetidos." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([50, 10, 50, 90, 90, 50, 50])" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[[5, 1, 5, 9, 9, 5, 5]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Assim como nas máscaras booleanas, podemos usar o array de inteiros para atribuições de novos valores." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 100, 20, 30, 40, 100, 60, 70, 80, 100])" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[[5, 1, 9]] = 100\n", "a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Para arrays multidimensionais, precisamos passar arrays multidimensionais na indexação. No exemplo abaixo, são selecionados os elementos a[0,0] , a[1,1] e a[2,0]." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1, 4, 5])" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.array([[1 ,2], [3, 4], [5, 6]])\n", "a[[0, 1, 2], [0, 1, 0]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Operações elemento por elemento" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Operações matemáticas básicas são realizadas elemento por elemento nos arrays." ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[2 3 4 5 6]\n", "[ 2 4 6 8 10]\n" ] } ], "source": [ "a = np.array([1, 2, 3, 4, 5])\n", "\n", "print(a + 1) # 1 é somado a cada elemento do array\n", "print(2 * a) # 2 é multiplicado a cada elemento do array" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Também conseguimos fazer operações matemáticas onde os dois operandos são arrays." ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 6 8]\n", " [10 12]]\n", "[[ 5 12]\n", " [21 32]]\n" ] } ], "source": [ "a = np.array([[1, 2], [3, 4]])\n", "b = np.array([[5, 6], [7, 8]])\n", "\n", "print(a+b) # cada elemento do array a é somado com o elemento do array b da posição correspondente\n", "print(a*b) # cada elemento do array a é mutiplicado pelo o elemento do array b da posição correspondente" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "No NumPy, usar o operador de multiplicação entre arrays não significa que estamos fazendo multiplicação de matrizes. Para multiplicar duas matrizes usamos a função `np.dot`." ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 5 12]\n", " [21 32]]\n", "[[19 22]\n", " [43 50]]\n" ] } ], "source": [ "print(a*b)\n", "print(np.dot(a, b))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Além de operações aritméticas, também é possível fazer operações lógicas entre arrays." ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([False, True, False, True])" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.array([1, 2, 3, 4])\n", "b = np.array([4, 2, 2, 4])\n", "a == b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Usando o operador `==` foi realizada uma comparação elemento por elemento e o resultado foi mostrado elemento por elemento. Para comparar se todos os elementos de dois arrays são iguais usamos a função `np.array_equal`." ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n", "True\n" ] } ], "source": [ "c = np.array([1, 2, 3, 4])\n", "\n", "print(np.array_equal(a, b))\n", "print(np.array_equal(a, c))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Para as operações OR e AND, temos:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1 1 1 0]\n", "[1 0 0 0]\n" ] } ], "source": [ "a = np.array([1, 1, 0, 0])\n", "b = np.array([1, 0, 1, 0])\n", "\n", "print(a | b) # OR\n", "print(a & b) # AND" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Agregações" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Funções de agregação são úteis para sumarizar informações contidas nos arrays." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`np.sum` soma todos os valores de um array." ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.array([1, 2, 3, 4])\n", "np.sum(a)" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "21" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b = np.array([[1, 2, 3], [4, 5, 6]])\n", "np.sum(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Utilizando o parâmetro `axis` especificamos a agregação numa determinada dimensão." ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([5, 7, 9])" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.sum(b, axis=0) # 0 é a primeira dimensão, ou seja, as linhas." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note que somar os valores na dimensão das linhas não significa somar as linhas, mas somar os valores na direção das linhas. Veja a figura abaixo." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![](axis.png)" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 6, 15])" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.sum(b, axis=1) # 1 é a segunda dimensão, ou seja, as colunas" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`np.min` encontra o valor mínimo de um array e `np.max` encontra o valor máximo." ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "1\n", "4\n", "6\n" ] } ], "source": [ "print(np.min(a))\n", "print(np.min(b))\n", "\n", "print(np.max(a))\n", "print(np.max(b))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Utilizando o parâmetro `axis` encontramos o valor máximo ou mínimo numa determinada dimensão." ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1 2 3]\n", "[1 4]\n", "[4 5 6]\n", "[3 6]\n" ] } ], "source": [ "print(np.min(b, axis=0)) # encontra o valor mínimo seguindo a dimensão das linhas\n", "print(np.min(b, axis=1)) # encontra o valor mínimo seguindo a dimensão das colunas\n", "\n", "print(np.max(b, axis=0)) # encontra o valor máximo seguindo a dimensão das linhas\n", "print(np.max(b, axis=1)) # encontra o valor máximo seguindo a dimensão das colunas" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`np.mean` calcula a média dos elementos de um array, `np.median` calcula a mediana e `np.std` calcula o desvio padrão." ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2.5\n", "3.5\n", "2.5\n", "3.5\n", "1.118033988749895\n", "1.707825127659933\n" ] } ], "source": [ "print(np.mean(a))\n", "print(np.mean(b))\n", "\n", "print(np.median(a))\n", "print(np.median(b))\n", "\n", "print(np.std(a))\n", "print(np.std(b))" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[2.5 3.5 4.5]\n", "[2. 5.]\n", "[2.5 3.5 4.5]\n", "[2. 5.]\n", "[1.5 1.5 1.5]\n", "[0.81649658 0.81649658]\n" ] } ], "source": [ "print(np.mean(b, axis=0))\n", "print(np.mean(b, axis=1))\n", "\n", "print(np.median(b, axis=0))\n", "print(np.median(b, axis=1))\n", "\n", "print(np.std(b, axis=0))\n", "print(np.std(b, axis=1))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`np.any` avalia se algum elemento satisfaz uma expressão booleana, `np.all` avalia se todos os elementos satisfazem uma expressão booleana." ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "False\n", "True\n" ] } ], "source": [ "c = np.array([1, 2, 3, 4])\n", "d = np.array([2, 4, 6, 8])\n", "\n", "print(np.any(c == 2)) # True, pois um dos elementos de c é igual a 2\n", "print(np.all(c == 2)) # False, pois existem elementos de c que não são iguais a 2\n", "print(np.all(c < 5)) # True, pois todos os elementos de c são menores que 5" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "False\n", "True\n" ] } ], "source": [ "print(np.any(c % 2 == 0)) # True, pois o elemento 2 e o elemento 4 são divisíveis por 2\n", "print(np.all(c % 2 == 0)) # False, pois o elemento 1 e o element 3 não são divisíveis por 2\n", "print(np.any(d % 2 == 0)) # True, pois todos os elementos de d são divisíveis por 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Broadcast" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Para arrays de mesmo tamanho, as operações são realizadas elemento por elemento. Entretanto, através do broadcast, o NumPy permite que essas operações sejam feitas usando arrays com diferentes dimensões." ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[11, 22, 33],\n", " [14, 25, 36]])" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.array([[1, 2, 3],\n", " [4, 5, 6]])\n", "\n", "b = np.array([10, 20, 30])\n", "\n", "a+b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Percebam que o NumPy somou a linha `[1, 2, 3]` com o array `[10, 20, 30]` e somou a linha `[4, 5, 6]` com o mesmo array `[10, 20, 30]`. Através do broadcast, o NumPy \"estica\" o array com menos dimensões repetindo os seus dados. A soma anterior é a mesma que:" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[11, 22, 33],\n", " [14, 25, 36]])" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.array([[1, 2, 3],\n", " [4, 5, 6]])\n", "\n", "b = np.array([[10, 20, 30],\n", " [10, 20, 30]])\n", "\n", "a+b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O broadcast segue três regras para determinar a interação entre os arrays:\n", "\n", "1. Se dois arrays possuirem dimensões diferentes, o formato do array com menos dimensões é acrescido de 1 do lado esquerdo.\n", "\n", "2. Se os tamanhos dos arrays não forem iguais em alguma dimensão, o array com tamanho igual a 1 numa determinada dimensão é esticado, repetindo seus elementos, para ficar igual ao outro tamanho.\n", "\n", "3. Se os tamanhos dos array não forem iguais e nenhum dos dois for igual a 1, então é retornado um erro." ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(2, 3)\n", "(3,)\n" ] } ], "source": [ "a = np.array([[1, 2, 3],\n", " [4, 5, 6]])\n", "\n", "b = np.array([10, 20, 30])\n", "\n", "print(a.shape)\n", "print(b.shape)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nesse caso, `b` tem menos dimensões que `a`. Assim, de acordo com a regra número 1, seu formato vai ter 1 adicionado do lado esquerdo, resultando em `(1, 3)`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Agora, o formato de `a` é `(2, 3)` e o de `b` é `(1, 3)`. Seguindo a regra 2, `b` vai ser esticado para ficar com tamanho `(2, 3)`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Utilizando as regras do broadcast, percebemos que é possível esticar dois arrays ao mesmo tempo." ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[11, 12, 13],\n", " [21, 22, 23],\n", " [31, 32, 33]])" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.array([1, 2, 3])\n", "b = np.array([[10],\n", " [20],\n", " [30]])\n", "\n", "a+b" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(3,)\n", "(3, 1)\n" ] } ], "source": [ "print(a.shape)\n", "print(b.shape)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nesse caso, `a` tem menos dimensões que `b`. Assim, seu formato vai ter 1 adicionado do lado esquerdo, resultando em `(1, 3)`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Agora, `a` tem o formato `(1, 3)` e `b` tem o formato `(3, 1)`. Seguindo a regra 2, `a` vai ser esticado para ficar com tamanho `(3, 3)` e `b` vai ser esticado para ficar com o tamanho `(3, 3)`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Alterando dimensões" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O NumPy permite que um array tenha o seu formato alterado para distribuir seus valores usando diferentes dimensões." ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1, 2],\n", " [3, 4]])" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.array([1, 2, 3, 4])\n", "\n", "a.reshape((2, 2)) # transforma o array a num array 2x2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note que a quantidade de elementos do array inicial precisa ser a mesma do novo array." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Podemos usar o `reshape` para transformar um array multidimensional num array de uma dimensão." ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1, 2, 3, 4, 5, 6])" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b = np.array([[1, 2, 3],\n", " [4, 5, 6]])\n", "\n", "b.reshape((6,))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Também podemos converter um array de uma dimensão em uma matriz coluna ou matriz linha." ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[1 2 3 4]]\n", "[[1]\n", " [2]\n", " [3]\n", " [4]]\n" ] } ], "source": [ "print(a.reshape((1, 4))) # matriz linha\n", "print(a.reshape((4, 1))) # matriz coluna" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Trabalhando com matrizes, uma operação comum é obtenção de uma nova matriz através da troca de suas dimensões, também conhecida como a matriz transposta." ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1, 4],\n", " [2, 5],\n", " [3, 6]])" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b.T" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ordenação" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Para ordenar um array usamos a função `np.sort()` que implementa o algoritmo quicksort." ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1, 2, 3, 4, 5])" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.array([4, 1, 3, 5, 2])\n", "np.sort(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A função anterior retorna o array ordenado. Se você desejar ordenar o próprio array, basta usar o método `sort()`." ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[4 1 3 5 2]\n", "[1 2 3 4 5]\n" ] } ], "source": [ "print(a)\n", "a.sort()\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ao invés de ordenar o array, é possível obter um array com os índices dos elementos ordenados utilizando a função `np.argsort()`." ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1, 4, 2, 0, 3])" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.array([4, 1, 3, 5, 2])\n", "np.argsort(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O resultado anterior significa que o menor elemento está na posição 1, o segundo menor na posição 4, o terceiro menor na posição 2, o quarto menor na posição 0 e o quinto menor (ou o maior) na posição 3." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Utilizando a indexação avançada, podemos usar o resultado do `np.argsort()` para obter o array ordenado." ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1, 2, 3, 4, 5])" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.array([4, 1, 3, 5, 2])\n", "sort_pos = np.argsort(a)\n", "\n", "a[sort_pos]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Por fim, o parâmetro `axis` está disponível para as funções de ordenação. Com ele, especificamos que a ordenação deve ser feita através de uma determinada dimensão." ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[2, 1, 2, 1, 1],\n", " [3, 2, 3, 3, 2],\n", " [4, 5, 5, 5, 4]])" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b = np.array([[4, 1, 3, 5, 2],\n", " [2, 5, 2, 3, 1],\n", " [3, 2, 5, 1, 4]])\n", "\n", "np.sort(b, axis=0) # ordena seguindo a dimensão das linhas" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1, 2, 3, 4, 5],\n", " [1, 2, 2, 3, 5],\n", " [1, 2, 3, 4, 5]])" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.sort(b, axis=1) # ordena seguindo a dimensão das colunas" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1, 2, 3, 4, 5],\n", " [1, 2, 2, 3, 5],\n", " [1, 2, 3, 4, 5]])" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.sort(b) # omitindo axis, a última dimensão é usada, nesse caso, as colunas" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5])" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.sort(b, axis=None) # usando None, o array é transformado em unidimensional e depois ordenado" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O conteúdo deste notebook foi inspirado no material dos seguintes links:\n", "\n", "- https://numpy.org/doc/1.17/\n", "- http://cs231n.github.io/python-numpy-tutorial/\n", "- http://scipy-lectures.org/intro/numpy/\n", "- https://jakevdp.github.io/PythonDataScienceHandbook" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3.10.4 64-bit ('3.10.4')", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.4" }, "vscode": { "interpreter": { "hash": "920717a7cc80731a9b73e79f915c61e3bfaff3c2aee97a8455928bf5b256b3eb" } } }, "nbformat": 4, "nbformat_minor": 2 }