Enviar um café pro programador

Mostrando postagens com marcador Dados. Mostrar todas as postagens
Mostrando postagens com marcador Dados. Mostrar todas as postagens

Reshape e Resize: Como mudar o tamanho e formato de dados em Python

 Neste tutorial, de nosso curso de Ciência de Dados com Python, vamos aprender como usar as funções de reshaping e resizing, para alterar o formato e tamanho dos arrays.

É muito comum, quando trabalhamos com dados em programação, termos a necessidade de alterar a maneira como as informações são armazenadas e exibidas, para facilitar nossa tarefa.

Por exemplo, vamos supor que você um array unidimensional com as notas de todos os alunos de uma turma, ou seja, tudo numa linha. Ora, essa é uma péssima maneira de armazenar esses dados. Seria melhor uma tabela (matriz), onde uma linha se refere a somente um aluno, e as colunas são as notas de cada matéria, concorda?

reshape() - Mudando o formato de arrays

Nas funções de reshape, não vamos alterar o número de elementos total, vamos apenas reorganizar, ou seja, mudar o formato como as dados são exibidos, ok?

np.reshape( info, formato(linhas, colunas) )

Vamos usar a função reshape, da biblioteca NumPy, para alterar o formato de um array. Para isso, vamos fornecer dois argumentos para a função: o array com as informações e o formato na qual queremos exibir, onde o formato deve ser da seguinte maneira: (linhas, colunas)

Vamos supor que temos o array arr1 que tem uma linha e 4 colunas, e queremos criar o array arr2 com duas linhas e duas colunas. Ou seja, vamos mudar o array de 1x4 para 4x4:

import numpy as np arr1 = np.array([1,2,3,4]) arr2 = np.reshape(arr1, (2,2)) print("Array original 1x4: ", arr1) print("Array reshape 2x2 : \n", arr2)

Mais uma vez é importante salientar: não alteramos o número de elementos, nem seus valores, apenas vamos alterar seu formato (shape).

Agora vamos fazer o contrário, vamos pegar um array arr1 que é uma matriz 3x3 e vamos transformar um array unidimensional, de 9 elementos:

import numpy as np arr1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) arr2 = arr1.reshape(1,9) print("Array original 3x3: \n", arr1) print("Array reshape 1x9 : \n", arr2)

Note que chamamos a função reshape diretamente do array arr1, bastando então fornecer o formato que queremos salvar em arr2, pois já fica subtendido que vamos usar os dados de arr1.


Transformando tudo em um array unidimensional: ravel()

Veja que no último caso foi preciso explicitar as dimensões do array unidimensional. Porém, as vezes não sabemos ou não queremos nos incomodar com o tanto de elementos, apenas queremos transformar a matriz de dados em um array unidimensional. Para fazer isto, basta usar a função ravel():

import numpy as np arr1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) arr2 = np.array([ [9,8], [7,6], [5,4], [3,2]]) print("ravel() de arr1: ", arr1.ravel()) print("ravel() de arr2: ", arr2.ravel())

Lembrando que, tanto a reshape() como a ravel() não vão alterar o formato dos arrays originais.


Resize - mudando o tamanho de arrays

Uma outra operação bem comum em data science, é a de alterar o tamanho de arrays, como por exemplo, unir duas matriz, concatenar arrays ou simplesmente adicionar ou retirar elementos desses arrays.

  • append() : acrescentando elementos ao final

A maneira mais simples de se mudar o tamanho de um array, é adicionando um elemento ao final dele. Para isso, vamos usar a função append(), que cria um novo array, com o original acrescido do que você adicionou.

Por exemplo:

import numpy as np arr1 = np.array([1, 2, 3]) arr2 = np.array([4, 5, 6]) arr3 = np.append(arr1, arr2) arr4 = np.append(arr3, 7) print(arr4)

Para criar o arr3, unimos o arr2 ao final do arr1. Assim, temos : arr3 = [1,2,3,4,5,6]
Já para criar o arr4, simplesmente adicionamos o valor 7 a ele: arr4 = [1,2,3,4,5,6,7]

Se não especificarmos o eixo (axis), essa função primeiro deixar os arrays como unidimensionais e depois faz a junção. Mas, podemos, por exemplo, adicionar elementos ao final tanto no eixo vertical (axis=0), ou seja abaixo, como ao final horizontalmente (axis=1).

import numpy as np

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

arr2 = np.array([[5, 6],
[7, 8]])

arr3 = np.append(arr1, arr2, axis=0)
arr4 = np.append(arr1, arr2, axis=1)

print("axis=0: \n", arr3)
print("axis=1: \n", arr4)

O resultado é:

axis=0: 
 [1 2]
 [3 4]
 [5 6]
 [7 8]

axis=1: 
 [1 2 5 6]
 [3 4 7 8]

  • concatenate() : juntando quaisquer arrays

Os dois exemplos anteriores de append só funcionaram porque as duas matrizes eram arrays de mesmas dimensões. Experimente usar o append de um array 2x1 em uma matriz 2x2.

Intuitivamente, esperaríamos que o array fosse anexado ao final da matriz. Porém, teste. Teste e veja que não funciona.

Uma maneira de resolver isso, é usar a função concatenate(), que recebe uma lista com os arrays a serem concatenados e se desejar, você pode especificar como vai ocorrer o concatenamento. 

No exemplo abaixo, arr1 é uma matriz 2x2, arr2 é um vetor de linha 1x2 e arr3 é um vetor de coluna 2x1. Criamos arr4 concatenando a linha embaixo da matriz e arr5 é criado concatenando arr3 à direita da matriz, veja:

import numpy as np arr1 = np.array([[1, 2], [3, 4]]) arr2 = np.array([ [5, 6] ]) arr3 = np.array([ [5], [6]]) arr4 = np.concatenate((arr1, arr2), axis=0) arr5 = np.concatenate((arr1, arr3), axis=1) print("axis=0: \n", arr4) print("axis=1: \n", arr5)

Onde a saída será:

axis=0: 
 [[1 2]
  [3 4]
  [5 6]]

axis=1: 
 [[1 2 5]
  [3 4 6]]

Veja que os três arrays declarados são de dimensões diferentes.

  • resize() : criando arrays de quaisquer tamanhos

Por fim, é bem comum termos a necessidade de alterar as dimensões diretamente em um array, seja através da união de outros arrays ou simplesmente expandindo o próprio array.

Através da resize() podemos sempre alterar o tamanho e dimensão do array, e mesmo que isso signifique acrescentar novos elementos, sem termos que especificar novos valores ou fornecer sequer um outro array para fazer ele mudar de tamanho.

Por exemplo, vamos mudar um matriz 2x2 para uma 3x3:

import numpy as np arr = np.array([[1, 2], [3, 4]]) arr2 = np.resize(arr, (3,3)) print(arr2)

E o resultado é:

[[1 2 3]
 [4 1 2]
 [3 4 1]]

Ou seja, o NumPy cria uma cópia do array original, coloca no novo array e repete os valores do array original, até preencher as novas posições da matriz 3x3.

Já se chamarmos a função resize() diretamente do array, sem criar uma nova matriz, ele vai alterar a matriz original, preenchendo ela com valores 0:

import numpy as np arr = np.array([[1, 2], [3, 4]]) arr.resize((3,3)) print(arr)

Saída:

[[1 2 3]
 [4 0 0]
 [0 0 0]]


Histograma em Python - Como gerar e plotar gráficos

 Neste tutorial, vamos aprender como gerar um gráfico do tipo histograma, através da linguagem de programação Python.

O que é um Histograma

Histograma é um tipo de gráfico, com barras verticais, onde cada uma represente uma classe de valores, e a altura representa a frequência que essa classe aparece no seu conjunto de dados. Numa linguagem mais técnica, representa uma distribuição de frequências.

Por exemplo, um consultório médico criou um histograma, para melhor entender a distribuição de idades dos pacientes:

Como plotar gráficos do tipo Histograma

No eixo x, temos as idades dos pacientes. Cada barra dessas representa uma idade ou intervalo de idades. Já o eixo y representa quantas vezes cada intervalo desses apareceu.

Pelo gráfico, podemos ver que cada barra dessas tem um intervalo próximo de 5 anos. A maior parte dos pacientes, tem por volta dos 20-25 anos e 25-30, pois cada barra que representa esses intervalos apareceu (frequência) mais de 50 vezes. Ou seja, tem mais de 100 pacientes com idade entre 20 e 30 anos.

Pacientes com mais de 90 anos? Bem poucos.
Pacientes com 0-5 anos de idade? Quase 20.

O gráfico do tipo histograma é muito útil quando você tem uma grande quantidade de dados e quer, rápida e facilmente, identificar como está a distribuição de determinados valores desses dados. Por ser uma maneira visual de representar e classificar dados, é muito usada para exibir resultados, seja em trabalhos científicos como em reuniões, por exemplo.

Tipos de Histograma em Python

Como podem imaginar, existe uma infinidade de tipos de gráficos histograma, e cada um deles nos diz informações muito importante sobre os dados que estamos analisando.

E, obviamente, o Python pode nos ajudar muito, mas muito mesmo, nessa tarefa de plotar e analisar.

Experimento do Pêndulo Simples

No laboratório de Física da Universidade Federal do Ceará (UFC), realizei o famoso experimento do pêndulo simples:

Pêndulo simples em Python

Cuja fórmula do período é dada por:

Física com Python

Onde L é o comprimento da corda do pêndulo, e g o valor da gravidade no local, que é 9,78 m/s² dentro do Campus do Pici, local onde foi realizado a medição.

Logo, o valor teórico do período é: T = 2,009141114 s = 2,01s
Vamos usar o mesmo número de algarismos significativos do cronômetro usado, dois.

Os valores que calculei podem ser obtidos em:
https://github.com/jarlissonmoreira/PythonProgressivo/blob/main/Histograma/data.txt

Note que os valores obtidos experimentalmente estão bem próximos do valor teórico. Vamos colocar esses valores em um histograma e ver isso em um gráfico, para confirmar que a maioria das medições estão ali por volta desse valor 2.01s

O meu arquivo tem 135 linhas, divididas em 10 colunas. Mas o script que será apresentado é bem abrangente, você pode colocar seus dados em quaisquer números de linhas e colunas, que ele vai funcionar.

Vamos aprender como usar o script para plotar um histograma.


Como plotar um Histograma em Python

Vamos usar a biblioteca matplotlib e a função hist() dela, para plotar nosso histograma.
Mas, antes, precisamos tratar nossos dados, antes de passar os valores para essa função.

De onde o script vai puxar esses dados? Onde e como você vai armazenar eles? Eles tem vírgula ou ponto, como decimal? Se for vírgula, precisa trocar por ponto. Como estão formatados? Tudo junto? Numa matriz? Em txt ou csv?

Usar as funções é fácil, o que devemos ter cuidado é na hora de tratar os dados.

No script fornecido abaixo, você pode passar os dados de várias maneiras. Eu, por exemplo, coloquei todos os dados no arquivo txt acima mencionado e em seguida usei o endereço desse arquivo "data.txt" (pois o data.txt está na mesma pasta do script histograma.py) para o parâmetro path da minha função plot_histograma().

Se preferir, pode passar diretamente os dados através do parâmetro data (como não usei, coloquei o valor None nele), fornecendo uma string de valores. Obviamente, só é viável se tiver poucos dados.

Por fim, precisamos configurar o bins, que são os intervalos das barras, no eixo x. Eu passei o valor 'auto', para a função hist() fazer o melhor ajuste possível, mas você pode definir manualmente os intervalos que desejar.

Vamos plotar três gráficos. O primeiro, é o histograma da matriz original, com todos os dados, bastando fazer:

  • ax1.hist(array, bins)

Onde array são os dados e bins os intervalos.

No segundo gráfico, vamos calcular as médias de cada linha da matriz. Nossa matriz tem 135 linhas com 10 elementos em cada. Logo, nosso segundo gráfico vai ter 135 elementos. Isso é muito usado em Física Experimental, a média das médias, pois fornecem valores mais confiáveis e próximos do teórico, pois 'amenizam' os resultados muito discrepantes.

Por fim, ploetei os dois gráficos juntos, um na frente do outro, para vermos a diferença.

O resultado ficou:

Script para fazer histograma em Python

Nosso script, usado para gerar esses plots de histogramas, é:

import numpy as np
from matplotlib import pyplot


def plot_histograma(path: str = None, data: str = None, bins: float | str = None) -> None:
    #path: caminho do arquivo .txt com os dados "caminho/do/data.txt"
    #bins: se nao fornecido retorna o histograma dos valores individuais,
    #ele pode ser tamanho (float), ou uma string com valores: 'auto', 'fd', 'doane', 'scott', 'stone', 'rice', 'sturges', or 'sqrt'
    #return: printa na tela o histograma
    
    if path is not None:
        with open(path, "r") as file:
            content = file.read().replace(',', '.')
            values: list[float] = [float(i) for i in content.split()]
    else:
        content = data.replace(',', '.')
        values: list[float] = [float(i) for i in content.split(';')]
   
    array = np.array(values)
    
    if bins is None:
        bins=sorted(values)
       
    if type(bins) is str:
        bins=bins
       
    if type(bins) is float:
        bins = np.arange(array.min(), array.max() + bins, bins)
    
    #Transforma o array/lista de valores em uma matriz com 10 colunas
    col = 10
    lin = int(len(array)/col)
    array2 = array.reshape(lin,col)
    
    #Cria um array, onde cada elemento é uma média de 10 valores,
    #de cada linha da matriz anterior
    median=np.mean(array2, axis=1)
    
    #Novo código para imprimir os três gráficos, com mesmo eixo x
    fig, (ax1, ax2, ax3) = pyplot.subplots(3, 1, sharex=True)

    #Primeiro gráfico, de 1350 medições
    ax1.hist(array, bins)
    ax1.xaxis.set_tick_params(labelbottom=True)
    leg1 = str(lin*col)
    ax1.set_xlabel(leg1+' medições')

    #Segundo gráfico, das 135 médias
    ax2.hist(median,bins)
    ax2.xaxis.set_tick_params(labelbottom=True)
    leg2 = str(len(median))
    ax2.set_xlabel(leg2+' médias')
    
    #Sobrepondo os dois, para efeitos de comparação
    ax3.hist(array, bins, alpha=0.5, label=leg1)
    ax3.hist(median, bins, alpha=0.5, label=leg2)
    ax3.set_xlabel('Gráficos sobrepostos')
    ax3.legend(loc='upper right')
    
    pyplot.tight_layout()
    pyplot.show()

path="data.txt"
data=None
bins='auto'
plot_histograma(path,data,bins)

Recebendo dados do usuário: Entry widget

Neste tutorial de programação gráfica GUI em Python, vamos aprender o que é e como usar o widget Entry.

Recebendo informações do usuário

Até o momento, nossa única interação código-usuário foi através do clique do usuário em botões, seja em nossos buttons como em caixas de diálogo.

Porém, a forma mais comum de interação entre um programa e o usuário, é através daquelas áreas retangulares, onde escrevemos algum texto.

Por exemplo, para preencher o campo de nome, telefone, CEP, data de nascimento etc.



Geralmente, o normal é termos algo do tipo:

  • Um label com algum texto
  • Um campo de entrada, para escrevermos algo
  • Um botão, para fazer algo com o dado que escrevemos

Vejamos um print de uma aplicação real:

Como receber entrada do usuário

Como usar entradas: Entry widget

Vamos aprender como fazer o programinha do print anterior.

Na primeira janela, temos dois frames:
frame de cima: tem um label e um widget do tipo Entry
frame de baixo: dois botões

Após criar os objetos do tipo label e os frames, vamos criar nosso widget Entry.

  1. Ele recebe dois parâmetros:
  2. O container que ele vai estar (frame ou janela)
  3. width: número de caracteres que vai ser possível digitar no campo de texto

Vamos usar width=30
Em seguida, empacotamos o label e entry no frame de cima, lado a lado (side='left').
Nosso entry vai se chamar entrada e ele tem um método especial, o get(), que retorna uma string com o que foi digitado na caixa.

Em seguida, criamos dois botões.
O primeiro chama o método exibe(), onde esse método exibe uma string.
Por fim, um botão de quit.

Agora vamos empacotar esse botões no frame de baixo.
Depois empacotamos os dois frames na janela principal...e rodamos o programa!

Veja como fica o código completo:

from tkinter import *
from tkinter import messagebox

class MinhaGUI:
 def __init__(self):
  # Criamos a janela principal
  self.janela_principal = Tk()
  
  # Criando os frames
  self.frame_cima  = Frame(self.janela_principal) 
  self.frame_baixo = Frame(self.janela_principal) 
  
  # Criando label e botões do frame de cima
  self.label = Label(self.frame_cima, text='Digite seu nome:')
  
  # Criando o widget de entrada
  self.entrada = Entry(self.frame_cima, width=30)
  
  # Empacotando label e entrada no frame de cima
  self.label.pack(side='left')
  self.entrada.pack(side='left')
  
  # Criando os botões, no frame de baixo
  self.botao = Button(self.frame_baixo, text='Exibir', command=self.exibe)
  self.botao_sair = Button(self.frame_baixo, text='Sair', command=self.janela_principal.quit)
  
  # Empacotando os botões no frame de baixo
  self.botao.pack(side='left')
  self.botao_sair.pack(side='left')
  
  # Empacotando os botões janela principal
  self.botao.pack()
  self.botao_sair.pack()
  
  # Empacotando os frames na janela principal
  self.frame_cima.pack()
  self.frame_baixo.pack()
  
  # Rodando
  mainloop()

  
 def exibe(self):
  messagebox.showinfo('Python Progressivo','Seu nome é: '+ self.entrada.get())


gui = MinhaGUI()

Ou seja, o pulo do gato dos widgets Entry é o método get() que todo objeto desse tipo tem.
Esse método retorna SEMPRE uma string, com o que foi digitado.

Quer pegar um número? Ok, mas primeiro converte de string pra inteiro ou float, só depois usa o número. Mas é sempre uma string, ok?

Jogando Dados com Python - Estatística e Probabilidade

Neste tutorial de Python, vamos envolver programação e Matemática, especificamente estatística e probabilidade, e vamos comprovar na prática que elas existem e funcionam!

Leia também:

Jogando os Dados com o Python


Para gerar nossos números aleatórios de 1 até 6, vamos definir a função gera() que não tem nenhum parâmetro e vai, obviamente, retornar número inteiro de 1 até 6.

Para isso, vamos usar a função randint da biblioteca random.
Se não leu nosso tutorial, veja: Como gerar números aleatórios em Python

Essa função recebe os argumentos 1 e 6, parar gerar inteiros de 1 até 6. E para usar ela, temos que importar o módulo random.
Ela fica:

import random

def gera():
    return random.randint(1,6)

Agora, vamos criar a função repete(n), que vai repetir n lançamentos de dados, onde n o usuário vai escolher quantas vezes vai jogar os dados.

Vamos armazenar os resultados 1, na variável test1.
Vamos armazenar os resultados 2, na variável test2.
...
Vamos armazenar os resultados 6, na variável test6.

Então inicializamos essa variável com todas elas igual a 0.

Agora vamos fazer um laço for pra rodar n vezes o lançamento de dados.
Cada vez que lança o dado (simplesmente chamando a função gera() - uma maravilha função né?), armazenamos na variável test.

Em seguida, vamos fazer várias comparações com IF, ELIF e ELSE, para saber se o valor do dado é 1, 2, 3, 4, 5 ou 6. E quando achar o valor certo, incrementar em 1 o valor da variável test1, ou test2 ou ... test6.

Ou seja, ao final do laço for, as variáveis test1, test2, ..., test6 terão quando vezes foi sorteado o número 1, 2, 3, 4, 5 e 6 respectivamente.

Então simplesmente damos seis prints, para exibir quantas vezes cada número saiu, bem como mostramos a porcentagem de frequência de cada valor,





Veja o código:

import random

def gera():
    return random.randint(1,6)

def repete(n):
    test1=test2=test3=      \
    test4=test5=test6 = 0
    for val in range(n):
        test = gera()

        if(test==1):
            test1 += 1
        elif(test==2):
            test2 += 1
        elif(test==3):
            test3 += 1
        elif(test==4):
            test4 += 1
        elif(test==5):
            test5 += 1
        else:
            test6 += 1
            

    print("Numero 1 saiu ", test1," vezes = ",(test1/n)*100, " %")
    print("Numero 2 saiu ", test2," vezes = ",(test2/n)*100, " %")
    print("Numero 3 saiu ", test3," vezes = ",(test3/n)*100, " %")
    print("Numero 4 saiu ", test4," vezes = ",(test4/n)*100, " %")
    print("Numero 5 saiu ", test5," vezes = ",(test5/n)*100, " %")
    print("Numero 6 saiu ", test6," vezes = ",(test6/n)*100, " %")

        
def menu():
    n = int(input('Quantos lançamentos de dado? '))
    repete(n)
    
while True:
    menu()

PS 1: Quanto maior for o n, mais a porcentagem se aproxima de 16,67% pois vai tendendo à probabilidade, que é de 1/6 .

PS 2: Mais na frente, quantos estudarmos sequências, você aprenderá maneiras mais simples de se trabalhar com várias variáveis de uma vez só.