Aula 08: Numpy, Scipy, Matplotlib e Pandas
Aula 08: Numpy/Scipy/Pandas/Matplotlib¶
Python se tornou uma linguagem de programação amplamente usada em meios científicos. Em algumas áreas se tornou a lingua franca. Porque e como isso ocorreu.
Tradicionalmente, a linguagem usada em computação científica é o FORTRAN, mais especificamente o FORTRAN 77. Também é usado o C/C++ e até hoje essa é a base de quase todas as ferramentas que se utiliza em computação científica. Essas são linguagens compiladas sem interatividade (não estritamente verdade) e o fluxo de trabalho era (ou é...) o seguinte:
- Escreva um programa
- Compile o programa
- Escreva um arquivo com os dados de entrada
- Execute o programa com os dados de saída
- O programa escreve seus resultados em um arquivo de saída
- Use um outro programa para fazer gráficos e analisar os dados
- Volte para 1 até dar certo
Estamos na última aula do curso de python e nunca fizemos nada parecido. Com python e seus ambientes interativos (tanto o terminal quanto o jupyter) fazem esta tarefa ser muito mais fácil, rápido e integrado.
Mas aí temos alguns problemas:
- Python, sozinho, não tem nenhuma das ferramentas necessárias:
- Matrizes
- Álgebra linear
- Equações diferenciais
- Plotar gráficos
- etc, etc, etc
- Python é lento
Este era o estado das coisas em 2000 (ou um pouco antes).
Qualquer aplicação científica ou de ciência de dados precisa tratar de matrizes e álgebra linear. Isso é tão importante que existem bibliotecas básicas para isso com implementações padrão:
TODO mundo usa as bibliotecas acima. Se não usa deveria usar.
MATLAB e outros¶
Um pessoal, por volta de 1980 criou um software que fazia uma interface interativa para essas bibliotecas. Esse software é o MATLAB - MATrix LABoratory.
Mas o MATLAB, apesar de todo o sucesso, tem alguns problemas
- É caro
- É muito caro
- Também é lento (para algumas coisas)
- A linguagem de programação parece uma gambiarra
- Existem limitações (legais) ao que se pode fazer
Outras ferramentas semelhantes surgiram que competem com MATLAB ou focam em outras áreas
- Mathematica
- IDL
- S-PLUS
- e outras, muitas outras...
Python como uma linguagem para aplicações matemáticas¶
No final dos anos 90, python estava se tornando uma linguagem de script popular por ser uma linguagem simples, amigável e fácil de aprender. Algumas pessoas acharam interessante usar python para aplicações matemáticas e numéricas. Com isso, começaram a criar extensões que permitissem isso. Após alguns anos e alguns traumas (numeric vs numarray vs numpy) chegou-se a algumas ferramentas básicas que permitiu todo o desenvolvimento posterior:
- Numpy: operação com arrays uniformes multidimensionais
- Scipy: algoritmos numéricos básicos
- Matplotlib: gráficos com qualidade
- Pandas: manipulação de dados e tabelas
Porque python se tornou tão popular nessa área? Porque resolve problemas! Na minha opinião, python se tornou popular pelos seguintes motivos
- Software livre: você usa como quiser e onde quiser e não precisa pagar preços exorbitantes
- Base sólida (numpy+scipy+matplotlib+pandas)
- Linguagem de programação de verdade (não uma gambiarra)
- Linguagem de programação agradável
- Extensível: dá para você interfacear com C/C++/Fortran sem grandes dificuldades
- Interage bem com a Internet - importante para a ciência de dados
Numpy¶
Numpy é uma biblioteca Python para trabalhar com matrizes multidimensionais.
Instalação¶
Se você está usando a distribuição de Python Anaconda, numpy já vem. Abra um terminal, inicie o Python e execute o seguinte comando:
import numpy
Se não deu erro, quer dizer o Numpy está instalado.
Caso contrário, execute o comando a seguir num terminal (não do Python, o prompt ou powershell)
python -m pip install numpy
Isso vai baixar o numpy e instalar.
Executando o numpy¶
Para usar o numpy, você primeiro precisa carregar a biblioteca. Para isso existem algumas opções:
import numpy
import numpy as np
from numpy import *
A primeira opção tem um problema: tem que digitar numpy.
na frente de tudo. A última opção você acessa diretamente a funcionalidade mas vai poluir o teu namespace. Eu prefiro a opção do meio e é o que vou utilizar.
import numpy as np
O tipo básico do numpy é o ndarray
?np.ndarray
O ndarray
é usado para representar uma matriz multidimensional homogênea com ítens de tamanho fixo.
Criando objetos ndarray
¶
Dificilmente vamos usar o ndarray
diretamente.
A função array
cria um ndarray
a partir de listas tuplas e coisas parecidas:
x = np.array(range(30))
type(x)
x[0]
x[10:15]
x.size
# Dá para fatiar!
y = x[3:15:3]
y
# y faz referência à mesma memória que x
y[0] = 123
y[0], x[3]
x.strides
y.strides
x.dtype
Usando a mesma sintaxe, é possível criar matrizes:
mat = np.array([[1,2,3], [4,5,6]]) # Lista de listas
mat
mat[0,0]
mat[1,0]
mat[0,:]
mat[:,0]
mat.size
mat.ndim
mat.shape
mat.dtype
# Array 3D
arr = np.array([[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]])
arr
arr.ndim
arr.size
arr.shape
arr
# Indexando
arr[0,0,0]
arr[1,0,0]
arr[0,1,0]
arr[0]
arr[0,0]
arr.strides
Melhor jeito para criar os ndarray
s¶
np.zeros( (3,4) )
np.zeros( (2,3,4), dtype='int64')
np.ones((2,3,4))
np.ones((2,3,4), dtype='int64')
Arrays igualmente espaçados¶
np.arange(0, 1, 0.01)
np.linspace(0,1,num=11)
np.logspace(1,10, num=11)
np.geomspace(1,100,num=4)
x = np.array(range(1,13))
x
y = x.reshape(3,4)
y
y.sum()
y.sum(0)
y.sum(1)
z = np.array(range(1,25)).reshape(2,3,4)
z
z.sum()
z.sum(0)
z.sum(1)
z.sum(2)
z.sum((0,1))
z.sum((0,2))
z.sum((1,2))
Média e desvio padrão¶
z.mean()
z.mean(0)
z.mean(1)
z.std()
z.std(0)
Máximos e mínimos¶
z.max()
z.max(0)
z.min(1)
Números aleatórios¶
import numpy.random as rnd
x = rnd.randn(1000)
x.mean()
x.std()
import matplotlib.pyplot as plt
plt.plot(x)
plt.plot(x, "o")
plt.hist(x)
y = rnd.gumbel(size=1000)
plt.hist(y)
Operações vetorizadas e broadcasting¶
x = np.linspace(0,1,num=51)
y = np.sin(2*np.pi*x)
plt.plot(x,y)
plt.plot(x, x**2*np.cos(6*x) + np.exp(x))
x + 1
x * 2
x = rnd.randn(10)
x
positivo = x > 0
positivo
x[positivo]
x[~positivo]
y = rnd.randn(5,8)
y[y > 0]
Já tínhamos visto fatiamento¶
x = np.array(range(50))
x[ [10,15,20]]
Álgebra linear¶
A0 = rnd.randn(5,5)
A0
# Matriz diagonal com diagonal = 10
A1 = np.diag(10*np.ones(5))
A1
A = A0 + A1
b = np.ones(5)
import numpy.linalg as linalg
# Resolvendo o sistema linear A*x = b
x = linalg.solve(A, b)
x
np.dot(A,x)
A.dot(x)
# Matriz transposta
A.T
# Inversa da matriz
iA = linalg.inv(A)
np.dot(iA,A)
# Determinante da matriz
linalg.det(A)
1 / linalg.det(iA)
# Vamos criar uma matriz simétrica
B = A + A.T
B
linalg.cholesky(B)
Álgebra linear¶
Bem mais completo que o numpy
!
import scipy.linalg as lin
# Problema de autovalor
λ, ϕ = lin.eig(B)
Λ = np.diag(λ)
i = 3
np.abs(B.dot(ϕ[:,i]) - λ[i] * ϕ[:,i]).max()
# Decomposição LU
P,L,U = lin.lu(A)
P
L
U
lu, piv = lin.lu_factor(A)
lu
lin.lu_solve( (lu,piv), b)
Integração numérica (funções)¶
import scipy.integrate as integr
Quero calcular a seguinte integral:
$$ \int_0^1 \cos(x) \: dx = \sin(1) $$I1 = integr.romberg(np.cos, 0, 1)
I1
Ie = np.sin(1)
Ie
erro = I1 - Ie
erro
# Funçãosinha bem chata para integrar na mão...
def minhafun(x):
return np.cos(x**2)
integr.romberg(minhafun, 0, 1)
Exemplo Camada limite¶
A camada limite foi medida no túnel de vento. Vamos analisar estes dados. Os dados estão armazenados em um arquivo no format HDF5, um formato binário adequado para armazenar arrays de grandes dimensões
Ler os dados de um arquivo HDF5¶
# Carregar a biblioteca python para ler arquivos HDF5:
import h5py
# Abrir o arquivo:
f = h5py.File("camada-limite.h5", "r")
# Vamos ver o que tem dentro deste arquivo
f.keys()
U = f['U'][:]
z = f['z'][:]
U.shape
z.shape
# Vamos ler a taxa de amostragem a partir dos atributos de U
fs = f['U'].attrs['rate'][0]
Plotar os perfis de velocidade¶
Vamos plotar o perfil de velocidades e intensidade de turbulência:
Um = U.mean(1)
sU = U.std(1)
I = sU / Um * 100
plt.figure(figsize=(12,6))
plt.subplot(1,2,1)
plt.plot(Um, z, "o")
plt.xlabel("Velocidade (m/s)")
plt.ylabel("Altura (m)")
plt.subplot(1,2,2)
plt.plot(I, z, "o")
plt.xlabel("Intensidade de turb. (%)")
plt.ylabel("Altura (m)")
fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True, figsize=(12,8))
ax1.plot(Um, z, "o")
ax1.grid()
ax1.set_xlabel("Velocidade (m/s)")
ax1.set_ylabel("Altura (m)")
ax1.set_title("Perfil de velocidade")
ax2.plot(I, z, "o")
ax2.grid()
ax2.set_xlabel("Intensidade de turb. (%)")
ax2.set_title("Turbulência")
#plt.ylabel("Altura (m)")
Espectro de turbulência¶
iref = 14
zref = z[iref]
u = U[iref]
N = len(u)
dt = 1/fs
t = np.arange(N) * dt
ū = u.mean()
σ = u.std()
plt.figure(figsize=(12,6))
plt.plot(t, u, label="$U(t)$", color='k')
plt.axhline(y=ū, linewidth=3, color='g', label="$\\bar{U}$")
plt.axhline(y = ū+2*σ, color='r', linestyle='--', linewidth=2, label='$\\bar{U} + 2\\sigma$')
plt.axhline(y = ū-2*σ, color='b', linestyle='--', linewidth=2, label='$\\bar{U} - 2\\sigma$')
plt.legend(loc='upper right')
plt.xlabel("Tempo (s)")
plt.ylabel("Velocidade (m/s)")
plt.figure(figsize=(12,6))
plt.xlim( (18,20))
plt.plot(t, u, label="$U(t)$", color='k')
plt.axhline(y=ū, linewidth=3, color='g', label="$\\bar{U}$")
plt.axhline(y = ū+2*σ, color='r', linestyle='--', linewidth=2, label='$\\bar{U} + 2\\sigma$')
plt.axhline(y = ū-2*σ, color='b', linestyle='--', linewidth=2, label='$\\bar{U} - 2\\sigma$')
plt.legend(loc='upper right')
plt.xlabel("Tempo (s)")
plt.ylabel("Velocidade (m/s)")
Análise espectral da velocidade¶
import scipy.signal as signal
f, S = signal.welch(u, fs, scaling='spectrum', nperseg=1000)
f1 = f[1:]
S1 = S[1:]
plt.figure(figsize=(12,6))
plt.grid()
plt.loglog(f1, S1, label="Medido")
plt.xlabel("Frequência (Hz)")
plt.ylabel("PSD")
ff = 10.0
ss = 1.0
a = ss / (ff**(-5/3))
plt.plot(f1, a*f1**(-5/3), "r--", label="Espectro de Kolmogorov $f^{-5/3}$")
plt.legend()
Exemplo: Equações de Lorenz¶
https://jupyter.org/try-jupyter/retro/notebooks/?path=notebooks/Lorenz.ipynb
$$ \begin{aligned} \dot{x} & = \sigma(y-x) \\ \dot{y} & = \rho x - y - xz \\ \dot{z} & = -\beta z + xy \end{aligned} $$import numpy as np
from matplotlib import pyplot as plt
from scipy import integrate
np.random.seed(1)
x0 = -15 + 30 * np.random.random((N, 3))
def lorenz_deriv(x_y_z, t0, sigma=10.0, beta=8./3., rho=28.0):
"""Compute the time-derivative of a Lorenz system."""
x, y, z = x_y_z
return [sigma * (y - x), x * (rho - z) - y, x * y - beta * z]
max_time = 100.0
t = np.linspace(0, max_time, int(250*max_time))
x1 = integrate.odeint(lorenz_deriv, [0.5, 0.4, 0.6], t)
x2 = integrate.odeint(lorenz_deriv, [0.50000001, 0.4, 0.6], t)
plt.figure(figsize=(18,10))
plt.plot(t, x1[:,2])
plt.plot(t, x2[:,2])
Pandas¶
Biblioteca para análise de dados. Dados em forma de tabelas. Pode-se pensar nisso como se fosse uma planilha.
Referência: Análise de dados com Python e Pandas de Daniel Y. Chen
import pandas as pd
df = pd.read_csv('gapminder.tsv', sep='\t')
df
type(df)
df.shape
df.columns
df.dtypes
df.info()
df.head()
df.tail()
country_df = df['country']
country_df
type(country_df)
# Pegar linhas de acordo com o rótulo
df.loc[0]
df.loc[10:20]
# Pegar linhas de acordo com o índice
df.iloc[0]
df.iloc[10:20]
df.loc[-1]
df.iloc[-1]
Agrupando e agregando dados¶
Perguntas.
- Para cada ano qual era a expectativa de vida média
- Podemos ver isso por continente?
- Quantos países estão listados por continente?
df.groupby('year')['lifeExp'].mean()
Vamos detalhar isso.
grouped_by_year_df = df.groupby('year')
type(grouped_by_year_df)
grouped_by_year_lifeExp = grouped_by_year_df['lifeExp']
type(grouped_by_year_lifeExp)
b = df['year'] == 1960
b
df60 = df[b]
df60['lifeExp']
df60['lifeExp'].mean()
Vamos fazer por continente
multi_group_var = df.groupby(['year', 'continent'])[['lifeExp', 'gdpPercap']].mean()
multi_group_var
Comentários
Comments powered by Disqus