Você está na página 1de 57

Machine Translated by Google

Figura 5-120. A imagem de entrada

Uma forma de visualizar esse conjunto de pixels é como uma nuvem de pontos em um espaço de cores
tridimensional. Vamos remodelar os dados para [n_samples x n_features] e redimensionar as cores
para que fiquem entre 0 e 1:

In[20]: data = china / 255,0 # use escala 0...1


dados = dados.reshape(427 * 640, 3)
dados.forma

Fora[20]: (273280, 3)

Podemos visualizar esses pixels neste espaço de cores, usando um subconjunto de 10.000 pixels para
eficiência (Figura 5-121):

In[21]: def plot_pixels(dados, título, cores=Nenhum, N=10000): se cores


for Nenhum: cores =
dados

# escolha um subconjunto aleatório


rng = np.random.RandomState(0) i
= rng.permutation(data.shape[0])[:N] cores =
cores[i]
R, G, B = dados[i].T

fig, ax = plt.subplots(1, 2, figsize=(16, 6)) ax[0].scatter(R,


G, color=colors, marker='.') ax[0].set(xlabel= 'Vermelho',
ylabel='Verde', xlim=(0, 1), ylim=(0, 1))

machado[1].scatter(R, B, color=cores, marcador='.')


ax[1].set(xlabel='Vermelho', ylabel='Azul', xlim=(0, 1), ylim= (0, 1))

fig.suptitle(título, tamanho=20);

In[22]: plot_pixels(data, title='Espaço de cores de entrada: 16 milhões de cores possíveis')

474 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

Figura 5-121. A distribuição dos pixels no espaço de cores RGB

Agora vamos reduzir esses 16 milhões de cores para apenas 16 cores, usando um agrupamento k-
means no espaço de pixels. Como estamos lidando com um conjunto de dados muito grande,
usaremos o minilote k-means, que opera em subconjuntos de dados para calcular o resultado muito
mais rapidamente do que o algoritmo k-means padrão (Figura 5-122) :

In[23]: de sklearn.cluster importar MiniBatchKMeans


kmeans = MiniBatchKMeans(16)
kmeans.fit(dados)
new_colors = kmeans.cluster_centers_[kmeans.predict(dados)]

plot_pixels(dados, cores=novas_cores,
title="Espaço de cores reduzido: 16 cores")

Figura 5-122. 16 clusters no espaço de cores RGB

Em profundidade: agrupamento k-Means | 475


Machine Translated by Google

O resultado é uma recoloração dos pixels originais, onde cada pixel recebe a cor do centro do cluster
mais próximo. Plotar essas novas cores no espaço da imagem, em vez do espaço de pixels, nos
mostra o efeito disso (Figura 5-123):

Em[24]:
china_recolored = new_colors.reshape(china.shape)

fig, ax = plt.subplots(1, 2, figsize=(16, 6),


subplot_kw=dict(xticks=[], yticks=[]))
fig.subplots_adjust(wspace=0.05)
ax[0].imshow(china)
ax[0].set_title(' Imagem original', tamanho=16)
ax[1].imshow(china_recolored)
ax[1].set_title(' Imagem de 16 cores ', tamanho = 16);

Figura 5-123. Uma comparação entre a imagem colorida (esquerda) e a imagem de 16 cores (direita)

Alguns detalhes certamente são perdidos no painel mais à direita, mas a imagem geral ainda é
facilmente reconhecível. Esta imagem à direita atinge um fator de compressão de cerca de 1 milhão!
Embora esta seja uma aplicação interessante do k-means, certamente existem maneiras melhores de
compactar informações em imagens. Mas o exemplo mostra o poder de pensar fora da caixa com
métodos não supervisionados como k-means.

Em profundidade: modelos de mistura gaussiana

O modelo de agrupamento k-means explorado na seção anterior é simples e relativamente fácil de


entender, mas sua simplicidade leva a desafios práticos em sua aplicação. Em particular, a natureza
não probabilística das médias k e seu uso da simples distância do centro do cluster para atribuir
membros ao cluster leva a um desempenho insatisfatório em muitas situações do mundo real. Nesta
seção daremos uma olhada nos modelos de mistura gaussiana, que podem ser vistos como uma
extensão das ideias por trás das médias k, mas também podem ser uma ferramenta poderosa para
estimativa além do simples agrupamento. Começamos com as importações padrão:

476 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

In[1]: %matplotlib importação


inline matplotlib.pyplot as plt import
seaborn as sns; sns.set() importa
numpy como np

Motivando o GMM: Pontos fracos do k-means

Vamos dar uma olhada em alguns dos pontos fracos do k-means e pensar em como
podemos melhorar o modelo de cluster. Como vimos na seção anterior, dados simples e
bem separados, k-means encontra resultados de agrupamento adequados.

Por exemplo, se tivermos blocos simples de dados, o algoritmo k-means pode rotular rapidamente
esses clusters de uma forma que corresponda ao que poderíamos fazer a olho nu (Figura 5-124):

In[2]: # Gere alguns dados de


sklearn.datasets.samples_generator import make_blobs X, y_true
= make_blobs(n_samples=400, centers=4, cluster_std=0.60,
random_state=0)
X = X[:, ::-1] # inverte os eixos para melhor plotagem

In[3]: # Plote os dados com rótulos k-means de


sklearn.cluster import KMeans kmeans
= KMeans(4, random_state=0) rótulos =
kmeans.fit(X).predict(X) plt.scatter(X[: ,
0], X[:, 1], c=rótulos, s=40, cmap='viridis');

Figura 5-124. rótulos k-means para dados simples

De um ponto de vista intuitivo, poderíamos esperar que a atribuição de agrupamento para alguns
pontos seja mais certa do que para outros; por exemplo, parece haver uma sobreposição muito
ligeira entre os dois clusters intermediários, de tal forma que podemos não ter total confiança na
atribuição de pontos do cluster entre eles. Infelizmente, o modelo k-means não tem medida intrínseca
de probabilidade ou incerteza de atribuições de cluster

Em profundidade: modelos de mistura gaussiana | 477


Machine Translated by Google

(embora possa ser possível utilizar uma abordagem bootstrap para estimar esta incerteza).
Para isso, devemos pensar em generalizar o modelo.

Uma maneira de pensar sobre o modelo k-means é colocar um círculo (ou, em dimensões
superiores, uma hiperesfera) no centro de cada cluster, com um raio definido pelo ponto
mais distante do cluster. Este raio atua como um ponto de corte para atribuição de cluster
dentro do conjunto de treinamento: qualquer ponto fora deste círculo não é considerado
membro do cluster. Podemos visualizar este modelo de cluster com a seguinte função
(Figura 5-125):
Em
[4]: de sklearn.cluster importar KMeans
de scipy.spatial.distance importar cdist

def plot_kmeans(kmeans, X, n_clusters=4, rseed=0, ax=Nenhum):


rótulos = kmeans.fit_predict(X)

# plote os dados de
entrada ax = ax ou
plt.gca()
ax.axis('equal') ax.scatter(X[:, 0], X[:, 1], c=labels, s=40, cmap= 'viridis', ordem z = 2)

# traçar a representação do modelo k-means centers =


kmeans.cluster_centers_ radii =
[cdist(X[labels == i], [center]).max() for i, center in
enumerate(centers)]
para c, r em zip (centros, raios):
ax.add_patch(plt.Circle(c, r, fc='#CCCCCC', lw=3, alfa=0,5, zorder=1))

Em [5]: kmeans = KMeans(n_clusters=4, random_state=0)


plot_kmeans(kmeans, X)

Figura 5-125. Os clusters circulares implícitos no modelo k-means

478 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

Uma observação importante para k-means é que esses modelos de cluster devem ser circulares: k-means
não possui uma maneira integrada de contabilizar clusters oblongos ou elípticos. Assim, por exemplo, se
pegarmos os mesmos dados e transformá-los, as atribuições do cluster acabam ficando confusas (Figura
5-126):

Em[6]: rng = np.random.RandomState(13)


X_esticado = np.dot(X, rng.randn(2, 2))

kmeans = KMeans(n_clusters=4, random_state=0)


plot_kmeans(kmeans, X_stretched)

Figura 5-126. Baixo desempenho de k-means para clusters não circulares

A olho nu, reconhecemos que estes aglomerados transformados são não circulares e, portanto, aglomerados
circulares seriam um ajuste inadequado. No entanto, k-means não é flexível o suficiente para dar conta
disso e tenta forçar o ajuste dos dados em quatro clusters circulares. Isto resulta numa mistura de
atribuições de cluster onde os círculos resultantes se sobrepõem: veja especialmente o canto inferior direito
deste gráfico. Poderíamos imaginar abordar esta situação específica pré-processando os dados com PCA
(ver “Em profundidade: análise de componentes principais” na página 433), mas na prática não há garantia
de que tal operação global circularizará os dados individuais.

Essas duas desvantagens do k-means – sua falta de flexibilidade no formato do cluster e falta de atribuição
probabilística de cluster – significam que para muitos conjuntos de dados (especialmente conjuntos de
dados de baixa dimensão) ele pode não funcionar tão bem quanto você poderia esperar.

Você pode imaginar abordar essas fraquezas generalizando o modelo k-means: por exemplo, você poderia
medir a incerteza na atribuição de clusters comparando as distâncias de cada ponto a todos os centros dos
clusters, em vez de focar apenas nos mais próximos.
Você também pode imaginar permitir que os limites do cluster sejam elipses em vez de círculos.

Em profundidade: modelos de mistura gaussiana | 479


Machine Translated by Google

cles, de modo a dar conta de clusters não circulares. Acontece que estes são dois componentes essenciais
componentes de um tipo diferente de modelo de agrupamento, modelos de mistura gaussiana.

Generalizando E – M: Modelos de Mistura Gaussiana


Um modelo de mistura gaussiana (GMM) tenta encontrar uma mistura de multidimensionais
Distribuições de probabilidade gaussianas que melhor modelam qualquer conjunto de dados de entrada. No mais simples
caso, GMMs podem ser usados para encontrar clusters da mesma maneira que k-means
(Figura 5-127):

In[7]: de sklearn.mixture importar GMM


gmm = GMM(n_componentes=4).fit(X)
rótulos = gmm.predict(X)
plt.scatter(X[:, 0], X[:, 1], c=rótulos, s=40, cmap='viridis');

Figura 5-127. Rótulos do modelo de mistura gaussiana para os dados

Mas como o GMM contém um modelo probabilístico subjacente, também é possível


para encontrar atribuições de cluster probabilísticas - no Scikit-Learn fazemos isso usando o pré
Método dict_proba . Isso retorna uma matriz de tamanho [n_samples, n_clusters] que
mede a probabilidade de qualquer ponto pertencer a um determinado cluster:

Em[8]: problemas = gmm.predict_proba(X)


imprimir(probs[:5].round(3))

[[ 0. 0. 0,475 0,525]
[ 0. 1. 0. 0. ]
[ 0. 1. 0. 0. ]
[ 0. 0. 0. 1. ]
[ 0. 1. 0. 0. ]]

Podemos visualizar esta incerteza, por exemplo, fazendo com que o tamanho de cada ponto pro-
proporcional à certeza de sua previsão; olhando para a Figura 5-128, podemos ver que

480 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

são precisamente os pontos nas fronteiras entre os clusters que refletem esta incerteza na atribuição dos clusters:

In[9]: size = 50 * probs.max(1) ** 2 # square enfatiza diferenças


plt.scatter(X[:, 0], X[:, 1], c=rótulos, cmap='viridis', s=tamanho);

Figura 5-128. Rótulos probabilísticos do GMM: as probabilidades são mostradas pelo tamanho dos pontos

Nos bastidores, um modelo de mistura gaussiana é muito semelhante ao k-means: ele usa uma abordagem de
maximização de expectativa que qualitativamente faz o seguinte:

1. Escolha estimativas iniciais para a localização e forma 2. Repita

até convergir:

a. E-step: para cada ponto, encontre pesos que codifiquem a probabilidade de pertencimento a
cada cluster

b. Etapa M: para cada cluster, atualize sua localização, normalização e forma com base
em todos os pontos de dados, fazendo uso dos pesos

O resultado disso é que cada cluster está associado não a uma esfera de arestas rígidas, mas a um modelo
gaussiano suave. Assim como na abordagem de maximização de expectativa k-médias, esse algoritmo pode às
vezes perder a solução globalmente ótima e, portanto, na prática, são usadas múltiplas inicializações aleatórias.

Vamos criar uma função que nos ajudará a visualizar as localizações e formas dos clusters do GMM desenhando
elipses com base na saída do gmm :

Em [10]:
de matplotlib.patches importar Ellipse

def draw_ellipse(posição, covariância, ax=Nenhum, **kwargs):


"""Desenhe uma elipse com uma determinada posição e covariância"""

Em profundidade: modelos de mistura gaussiana | 481


Machine Translated by Google

machado = machado ou plt.gca()

# Converta a covariância em eixos principais


se covariance.shape == (2, 2): U, s,
Vt = np.linalg.svd(covariance) angle =
np.degrees(np.arctan2(U[1, 0], U [0, 0])) largura, altura = 2
* np.sqrt(s) senão:

ângulo = 0
largura, altura = 2 * np.sqrt(covariância)

# Desenhe a elipse
para nsig em range(1, 4):
ax.add_patch(Ellipse(position, nsig * width, nsig * height, angle, **kwargs))

def plot_gmm(gmm, X, label=True, ax=None): ax =


ax ou plt.gca() rótulos =
gmm.fit(X).predict(X) if label:

ax.scatter(X[:, 0 ], X[:, 1], c=rótulos, s=40, cmap='viridis', zorder=2) senão: ax.scatter(X[:,


0],
X[:, 1], s=40 , zordem=2) ax.axis('igual')

w_factor = 0,2 / gmm.weights_.max() para


pos, covar, w em zip(gmm.means_, gmm.covars_, gmm.weights_):
draw_ellipse(pos, covar, alpha=w * w_factor)

Com isso implementado, podemos dar uma olhada no que o GMM de quatro componentes nos fornece
para nossos dados iniciais (Figura 5-129):

Em[11]: gmm = GMM(n_components=4, random_state=42)


plot_gmm(gmm, X)

482 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

Figura 5-129. Representação do GMM de quatro componentes na presença de clusters circulares

Da mesma forma, podemos usar a abordagem GMM para ajustar nosso conjunto de dados ampliado;
permitindo uma covariância completa, o modelo se ajustará até mesmo a clusters muito oblongos e esticados
(Figura 5-130):

Em[12]: gmm = GMM(n_components=4, covariance_type='full', random_state=42)


plot_gmm(gmm, X_esticado)

Figura 5-130. Representação do GMM de quatro componentes na presença de clusters não circulares

Isto deixa claro que os GMMs abordam as duas principais questões práticas com k-means encontradas
anteriormente.

Em profundidade: modelos de mistura gaussiana | 483


Machine Translated by Google

Escolhendo o tipo de

covariância Se você observar os detalhes dos ajustes anteriores, verá que a opção covariance_type
foi definida de forma diferente em cada um. Este hiperparâmetro controla os graus de liberdade na
forma de cada cluster; é essencial definir isso cuidadosamente para qualquer problema. O padrão é
covariance_type="diag", o que significa que o tamanho do cluster ao longo de cada dimensão pode ser
definido de forma independente, com a elipse resultante restrita para se alinhar aos eixos. Um modelo
um pouco mais simples e rápido é cova riance_type="spherical", que restringe a forma do cluster de
forma que todas as dimensões sejam iguais. O agrupamento resultante terá características semelhantes
às do k-means, embora não seja totalmente equivalente. Um modelo mais complicado e
computacionalmente caro (especialmente à medida que o número de dimensões aumenta) é usar
covariance_type="full", que permite que cada cluster seja modelado como uma elipse com orientação
arbitrária.

Podemos ver uma representação visual dessas três opções para um único cluster na Figura 5-131:

Figura 5-131. Visualização dos tipos de covariância do GMM

GMM como estimativa de densidade

Embora o GMM seja frequentemente classificado como um algoritmo de agrupamento, fundamentalmente


é um algoritmo para estimativa de densidade. Ou seja, o resultado de um GMM ajustado a alguns
dados não é tecnicamente um modelo de agrupamento, mas um modelo probabilístico generativo que
descreve a distribuição dos dados.

Como exemplo, considere alguns dados gerados a partir da função make_moons do Scikit-Learn
(visualizada na Figura 5-132), que vimos em “Em profundidade: agrupamento k-Means” na página 462:

In[13]: de sklearn.datasets importar make_moons


Xmoon, ymoon = make_moons(200, noise=0,05, random_state=0)
plt.scatter(Xmoon[:, 0], Xmoon[:, 1]);

484 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

Figura 5-132. GMM aplicado a clusters com limites não lineares

Se tentarmos ajustar isso a um GMM de dois componentes visto como um modelo de agrupamento, os resultados
não serão particularmente úteis (Figura 5-133):

Em [14]: gmm2 = GMM(n_components=2, covariance_type='full', random_state=0)


plot_gmm(gmm2, Xmoon)

Figura 5-133. GMM de dois componentes adequado para clusters não lineares

Mas se usarmos muito mais componentes e ignorarmos os rótulos dos clusters, encontraremos um ajuste que está
muito mais próximo dos dados de entrada (Figura 5-134):

Em[15]: gmm16 = GMM(n_components=16, covariance_type='full', random_state=0)


plot_gmm(gmm16, Xmoon, rótulo=Falso)

Em profundidade: modelos de mistura gaussiana | 485


Machine Translated by Google

Figura 5-134. Usando muitos clusters GMM para modelar a distribuição de pontos

Aqui a mistura de 16 gaussianas não serve para encontrar grupos separados de dados, mas sim
para modelar a distribuição global dos dados de entrada. Este é um modelo generativo de
distribuição, o que significa que o GMM nos dá a receita para gerar novos dados aleatórios
distribuídos de forma semelhante à nossa entrada. Por exemplo, aqui estão 400 novos pontos
extraídos deste ajuste do GMM de 16 componentes aos nossos dados originais (Figura 5-135):

Em[16]: Xnew = gmm16.sample(400, random_state=42)


plt.scatter(Xnew[:, 0], Xnew[:, 1]);

Figura 5-135. Novos dados extraídos do GMM de 16 componentes

O GMM é conveniente como um meio flexível de modelar uma distribuição multidimensional


arbitrária de dados.

486 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

Quantos componentes?
O fato de o GMM ser um modelo generativo nos dá um meio natural de determinar o número
ideal de componentes para um determinado conjunto de dados. Um modelo generativo é
inerentemente uma distribuição de probabilidade para o conjunto de dados e, portanto, podemos
simplesmente avaliar a probabilidade dos dados no modelo, usando validação cruzada para
evitar ajuste excessivo. Outra forma de corrigir o overfitting é ajustar as probabilidades do
modelo usando algum critério analítico, como o critério de informação de Akaike (AIC) ou o
critério de informação bayesiano (BIC). O estimador GMM do Scikit-Learn, na verdade, inclui
métodos integrados que calculam ambos e, portanto, é muito fácil operar com essa abordagem.

Vejamos o AIC e o BIC como uma função do número de componentes do GMM para nosso
conjunto de dados lunares (Figura 5-136):

Em[17]: n_componentes = np.arange(1, 21)


modelos = [GMM(n, covariance_type='full', random_state=0).fit(Xmoon)
para n em n_componentes]

plt.plot(n_components, [m.bic(Xmoon) para m em modelos], label='BIC')


plt.plot(n_components, [m.aic(Xmoon) para m em modelos], label='AIC')
plt.legend(loc='melhor')
plt.xlabel('n_components');

Figura 5-136. Visualização de AIC e BIC para escolha da quantidade de componentes


do GMM

O número ideal de clusters é o valor que minimiza o AIC ou o BIC, dependendo da aproximação
que desejamos usar. A AIC diz-nos que a nossa escolha de 16 componentes foi provavelmente
demasiada: cerca de 8 a 12 componentes teriam sido um

Em profundidade: modelos de mistura gaussiana | 487


Machine Translated by Google

melhor escolha. Como é típico neste tipo de problema, o BIC recomenda um modelo mais simples.

Observe o ponto importante: esta escolha do número de componentes mede quão bem o GMM funciona como
estimador de densidade, e não quão bem funciona como algoritmo de agrupamento. Eu encorajo você a pensar
no GMM principalmente como um estimador de densidade e usá-lo para agrupamento somente quando
necessário em conjuntos de dados simples.

Exemplo: GMM para geração de novos dados Acabamos de

ver um exemplo simples de utilização do GMM como modelo generativo de dados para criar novas amostras a
partir da distribuição definida pelos dados de entrada. Aqui seguiremos essa ideia e geraremos novos dígitos
manuscritos a partir do corpus de dígitos padrão que usamos antes.

Para começar, vamos carregar os dados de dígitos usando as ferramentas de dados do Scikit-Learn:

In[18]: de sklearn.datasets import load_digits digits =


load_digits() digits.data.shape

Fora[18]: (1797, 64)

A seguir, vamos representar graficamente os primeiros 100 deles para lembrar exatamente o que estamos vendo
(Figura 5-137):

Em[19]: def plot_digits(dados):


fig, ax = plt.subplots(10, 10, figsize=(8, 8),
subplot_kw=dict(xticks=[], yticks=[]))
fig.subplots_adjust(hspace=0,05, wspace=0,05) para i,
eixo em enumerar (ax.flat): im =
axi.imshow(data[i].reshape(8, 8), cmap='binary') im.set_clim(0,
16) plot_digits(digits.data)

Temos quase 1.800 dígitos em 64 dimensões e podemos construir um GMM sobre eles para gerar mais. GMMs
podem ter dificuldade em convergir em um espaço dimensional tão alto, então começaremos com um algoritmo
de redução de dimensionalidade invertível nos dados. Aqui usaremos um PCA simples, solicitando que preserve
99% da variação nos dados projetados:

Em [20]: de sklearn.decomposition importar PCA


pca = PCA (0,99, whiten = True)
data = pca.fit_transform (digits.data) data.shape

Fora[20]: (1797, 41)

488 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

Figura 5-137. Entrada de dígitos manuscritos

O resultado são 41 dimensões, uma redução de quase 1/3 e quase nenhuma perda de informação.
Dados esses dados projetados, vamos usar o AIC para obter uma medida do número de componentes
do GMM que devemos usar (Figura 5-138):

In[21]: n_components = np.arange(50, 210, 10) models


= [GMM(n, covariance_type='full', random_state=0) para n em
n_components] aics =
[model.fit(data).aic (dados) para modelo em modelos]
plt.plot(n_components, aics);
Parece que cerca de 110 componentes minimizam o AIC; usaremos este modelo.
Vamos ajustar isso rapidamente aos dados e confirmar se eles convergiram:

Em[22]: gmm = GMM(110, covariance_type='full', random_state=0)


gmm.fit(dados)
print(gmm.converged_)
Verdadeiro

Agora podemos extrair amostras de 100 novos pontos dentro deste espaço projetado de 41
dimensões, usando o GMM como modelo generativo:

Em [23]: data_new = gmm.sample(100, random_state=0)


data_new.shape

Fora[23]: (100, 41)

Em profundidade: modelos de mistura gaussiana | 489


Machine Translated by Google

Figura 5-138. Curva AIC para escolher o número apropriado de componentes do GMM

Finalmente, podemos usar a transformada inversa do objeto PCA para construir os novos
dígitos (Figura 5-139):
Em [24]: dígitos_new = pca.inverse_transform(data_new)
plot_digits(digits_new)

Figura 5-139. “Novos” dígitos retirados aleatoriamente do modelo subjacente do GMM


estimador

490 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

A maior parte dos resultados parecem dígitos plausíveis do conjunto de dados!

Considere o que fizemos aqui: dada uma amostragem de dígitos manuscritos, modelamos a
distribuição desses dados de tal forma que podemos gerar novas amostras de dígitos a partir dos
dados: estes são “dígitos manuscritos” que não são individualizados. – aparecem no conjunto de
dados original, mas capturam as características gerais dos dados de entrada conforme modelados
pelo modelo de mistura. Tal modelo generativo de dígitos pode ser muito útil como componente
de um classificador generativo bayesiano, como veremos na próxima seção.

Em profundidade: estimativa de densidade do kernel

Na seção anterior abordamos modelos de mistura gaussiana (GMM), que são uma espécie de
híbrido entre um estimador de agrupamento e um estimador de densidade. Lembre-se de que um
estimador de densidade é um algoritmo que pega um conjunto de dados D-dimensional e produz
uma estimativa da distribuição de probabilidade D-dimensional da qual esses dados são extraídos.
O algoritmo GMM consegue isso representando a densidade como uma soma ponderada das
distribuições gaussianas. A estimativa de densidade do kernel (KDE) é, em certo sentido, um
algoritmo que leva a ideia da mistura de gaussianas ao seu extremo lógico: ele usa uma mistura
que consiste em um componente gaussiano por ponto, resultando em um estimador de densidade
essencialmente não paramétrico. Nesta seção, exploraremos a motivação e os usos do KDE.
Começamos com as importações padrão:

In[1]: %matplotlib importação


inline matplotlib.pyplot as plt import
seaborn as sns; sns.set() importa
numpy como np

Motivando o KDE: Histogramas

Como já discutido, um estimador de densidade é um algoritmo que busca modelar a distribuição


de probabilidade que gerou um conjunto de dados. Para dados unidimensionais, você
provavelmente já está familiarizado com um estimador de densidade simples: o histograma. Um
histograma divide os dados em compartimentos discretos, conta o número de pontos que caem
em cada compartimento e, em seguida, visualiza os resultados de maneira intuitiva.

Por exemplo, vamos criar alguns dados extraídos de duas distribuições normais:

Em [2]: def make_data(N, f=0,3, rseed=1): rand


= np.random.RandomState(rseed) x =
rand.randn(N) x[int(f
* N):] += 5
retornar x

x = fazer_dados(1000)

Em profundidade: estimativa de densidade do kernel | 491


Machine Translated by Google

Vimos anteriormente que o histograma padrão baseado em contagem pode ser criado com a função
plt.hist() . Ao especificar o parâmetro normado do histograma, terminamos com um histograma
normalizado onde a altura das caixas não reflete as contagens, mas em vez disso reflete a densidade
de probabilidade (Figura 5-140):

Em[3]: hist = plt.hist(x, bins=30, normed=True)

Figura 5-140. Dados extraídos de uma combinação de distribuições normais

Observe que para categorização igual, essa normalização simplesmente altera a escala no eixo y,
deixando as alturas relativas essencialmente as mesmas de um histograma construído a partir de
contagens. Esta normalização é escolhida de forma que a área total sob o histograma seja igual a 1,
como podemos confirmar observando a saída da função histograma:

In[4]: densidade, compartimentos, patches = larguras


históricas = compartimentos[1:] -
compartimentos[:-1] (densidade * larguras).sum()

Fora[4]: 1,0

Um dos problemas de usar um histograma como estimador de densidade é que a escolha do tamanho
e localização do compartimento pode levar a representações que possuem características
qualitativamente diferentes. Por exemplo, se olharmos para uma versão destes dados com apenas
20 pontos, a escolha de como desenhar as caixas pode levar a uma interpretação totalmente diferente dos dados!
Considere este exemplo (visualizado na Figura 5-141):

Em[5]: x = make_data(20)
caixas = np.linspace(-5, 10, 10)

Em[6]: fig, ax = plt.subplots(1, 2, figsize=(12, 4),


sharex=Verdadeiro,
sharey=Verdadeiro,
subplot_kw={'xlim':(-4, 9), 'ylim':(-0,02, 0,3)})
fig.subplots_adjust(wspace=0,05)

492 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

para i, deslocamento em enumerate([0,0, 0,6]):


ax[i].hist(x, bins=bins + offset, normed=True) ax[i].plot(x,
np.full_like(x, -0,01 ), '|k', largura de borda do
marcador = 1)

Figura 5-141. O problema com os histogramas: a localização das caixas pode afetar a interpretação

À esquerda, o histograma deixa claro que se trata de uma distribuição bimodal. À direita, vemos uma
distribuição unimodal com cauda longa. Sem ver o código anterior, você provavelmente não imaginaria
que esses dois histogramas foram construídos a partir dos mesmos dados. Com isso em mente, como
confiar na intuição que os histogramas conferem?
E como podemos melhorar isso?

Voltando atrás, podemos pensar em um histograma como uma pilha de blocos, onde empilhamos um
bloco dentro de cada compartimento no topo de cada ponto do conjunto de dados. Vejamos isso
diretamente (Figura 5-142):

Em [7]: fig, ax = plt.subplots() bins =


np.arange(-3, 8) ax.plot(x,
np.full_like(x, -0.1), '|k',
marcadoredgewidth=1)
para contagem, borda em zip(*np.histogram(x, bins)):
para i no intervalo (contagem):
ax.add_patch(plt.Rectangle((borda, i), 1, 1, alfa=0,5))

ax.set_xlim(-4, 8)
ax.set_ylim(-0,2, 8)

Fora[7]: (-0,2, 8)

Em profundidade: estimativa de densidade do kernel | 493


Machine Translated by Google

Figura 5-142. Histograma como pilha de blocos

O problema com nossos dois agrupamentos decorre do fato de que a altura da pilha de blocos
geralmente reflete não na densidade real dos pontos próximos, mas nas coincidências de como os
compartimentos se alinham com os pontos de dados. Este desalinhamento entre os pontos e seus
blocos é uma causa potencial dos maus resultados do histograma vistos aqui. Mas e se, em vez
de empilharmos os blocos alinhados com as caixas, empilhássemos os blocos alinhados com os
pontos que eles representam? Se fizermos isso, os blocos não ficarão alinhados, mas podemos
somar suas contribuições em cada local ao longo do eixo x para encontrar o resultado. Vamos
tentar isso (Figura 5-143):

In[8]: x_d = np.linspace(-4, 8, 2000) densidade


= sum((abs(xi - x_d) < 0,5) para xi em x)

plt.fill_between(x_d, densidade, alfa=0,5) plt.plot(x,


np.full_like(x, -0,1), '|k', marcadoredgewidth=1)

plt.axis([-4, 8, -0,2, 8]);

494 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

Figura 5-143. Um “histograma” onde os blocos são centralizados em cada ponto individual; este é um
exemplo de estimativa de densidade do kernel

O resultado parece um pouco confuso, mas é um reflexo muito mais robusto das características reais dos
dados do que o histograma padrão. Ainda assim, as arestas não são esteticamente agradáveis, nem refletem
quaisquer propriedades verdadeiras dos dados. Para suavizá-los, podemos decidir substituir os blocos em
cada local por uma função suave, como uma Gaussiana. Vamos usar uma curva normal padrão em cada
ponto em vez de um bloco (Figura 5-144):

In[9]: da norma de importação scipy.stats


x_d = np.linspace(-4, 8, 1000)
densidade = sum(norm(xi).pdf(x_d) para xi em x)

plt.fill_between(x_d, densidade, alfa=0,5) plt.plot(x,


np.full_like(x, -0,1), '|k', marcadoredgewidth=1)

plt.axis([-4, 8, -0,2, 5]);

Em profundidade: estimativa de densidade do kernel | 495


Machine Translated by Google

Figura 5-144. Uma estimativa de densidade do kernel com um kernel gaussiano

Este gráfico suavizado, com uma distribuição gaussiana contribuída na localização de cada ponto de entrada,
dá uma ideia muito mais precisa da forma da distribuição de dados e que tem muito menos variância (ou seja,
muda muito menos na resposta). diferenças na amostragem).

Esses dois últimos gráficos são exemplos de estimativa de densidade de kernel em uma dimensão: o primeiro
usa o chamado kernel “tophat” e o segundo usa um kernel gaussiano. Veremos agora a estimativa da densidade
do kernel com mais detalhes.

Estimativa da densidade do kernel na prática Os

parâmetros livres da estimativa da densidade do kernel são o kernel, que especifica a forma da distribuição
colocada em cada ponto, e a largura de banda do kernel, que controla o tamanho do kernel em cada ponto. Na
prática, existem muitos kernels que você pode usar para uma estimativa de densidade de kernel: em particular,
a implementação do Scikit-Learn KDE suporta um dos seis kernels, sobre os quais você pode ler na
documentação de estimativa de densidade do Scikit-Learn .

Embora existam várias versões de estimativa de densidade de kernel implementadas em Python (principalmente
nos pacotes SciPy e StatsModels), prefiro usar a versão do Scikit-Learn devido à sua eficiência e flexibilidade.
Ele é implementado no estimador sklearn.neigh bors.KernelDensity , que lida com o KDE em múltiplas
dimensões com um dos seis kernels e uma entre algumas dezenas de métricas de distância. Como o KDE pode
ser bastante computacionalmente intensivo, o estimador Scikit-Learn usa um algoritmo baseado em árvore e
pode compensar o tempo de cálculo pela precisão usando os parâmetros atol (tolerância absoluta) e rtol
(tolerância relativa ) . Podemos determinar o

496 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

largura de banda do kernel, que é um parâmetro livre, usando as ferramentas padrão de validação
cruzada do Scikit-Learn, como veremos em breve.

Vamos primeiro ver um exemplo simples de replicação do gráfico anterior usando o Scikit-Learn
Estimador KernelDensity (Figura 5-145):

In[10]: de sklearn.neighbours importa KernelDensity

# instancia e ajusta o modelo KDE kde =


KernelDensity(bandwidth=1.0, kernel='gaussian') kde.fit(x[:, None])

# score_samples retorna o log da densidade de probabilidade logprob =


kde.score_samples(x_d[:, None])

plt.fill_between (x_d, np.exp (logprob), alfa = 0,5) plt.plot (x,


np.full_like (x, -0,01), '| k', marcador largura de borda = 1) plt.ylim (-0,02,
0,22 )

Fora[10]: (-0,02, 0,22)

Figura 5-145. Uma estimativa de densidade do kernel calculada com Scikit-Learn

O resultado aqui é normalizado de modo que a área sob a curva seja igual a 1.

Selecionando a largura de banda via validação

cruzada A escolha da largura de banda dentro do KDE é extremamente importante para encontrar uma
estimativa de densidade adequada, e é o botão que controla a compensação entre polarização e variância
na estimativa de densidade: uma largura de banda muito estreita leva a uma estimativa de alta variância
(ou seja, ajuste excessivo), onde a presença ou ausência de um único ponto faz uma grande diferença.
Uma largura de banda muito ampla leva a uma estimativa de alto viés (isto é, subajuste), onde a estrutura
dos dados é eliminada pelo kernel amplo.

Em profundidade: estimativa de densidade do kernel | 497


Machine Translated by Google

Há uma longa história em estatística de métodos para estimar rapidamente a melhor largura de banda com base
em suposições bastante rigorosas sobre os dados: se você procurar as implementações do KDE nos pacotes SciPy
e StatsModels, por exemplo, você verá implementações baseadas em em algumas dessas regras.

Em contextos de aprendizado de máquina, vimos que esse ajuste de hiperparâmetros geralmente é feito
empiricamente por meio de uma abordagem de validação cruzada. Com isso em mente, o estimador KernelDen
sity no Scikit-Learn foi projetado de forma que possa ser usado diretamente nas ferramentas de pesquisa de grade
padrão do Scikit-Learn. Aqui usaremos GridSearchCV para otimizar a largura de banda do conjunto de dados
anterior. Como estamos analisando um conjunto de dados tão pequeno, usaremos a validação cruzada deixe um
de fora, o que minimiza a redução no tamanho do conjunto de treinamento para cada tentativa de validação cruzada:

In[11]: de sklearn.grid_search importar GridSearchCV


de sklearn.cross_validation importar LeaveOneOut

larguras de banda = 10 ** np.linspace(-1, 1, 100) grid


= GridSearchCV(KernelDensity(kernel='gaussian'), {'bandwidth':
larguras de banda},
cv=LeaveOneOut(len(x)))
grid.fit (x[:, Nenhum]);

Agora podemos encontrar a escolha da largura de banda que maximiza a pontuação (que neste caso o padrão é a
probabilidade de log):

Em[12]: grid.best_params_

Saída[12]: {'largura de banda': 1,1233240329780276}

A largura de banda ideal é muito próxima daquela que usamos no gráfico de exemplo anterior, onde a largura de
banda era 1,0 (ou seja, a largura padrão de scipy.stats.norm).

Exemplo: KDE numa esfera Talvez o uso

mais comum do KDE seja na representação gráfica de distribuições de pontos. Por exemplo, na biblioteca de
visualização Seaborn (discutida anteriormente em “Visualização com Seaborn” na página 311), o KDE é integrado
e usado automaticamente para ajudar a visualizar pontos em uma e duas dimensões.

Aqui veremos um uso um pouco mais sofisticado do KDE para visualização de distribuições. Faremos uso de alguns
dados geográficos que podem ser carregados com o Scikit-Learn: as distribuições geográficas de observações
registradas de dois mamíferos sul-americanos, Bradypus variegatus (a preguiça-de-garganta-marrom) e Microryzomys
minutus (o pequeno rato do arroz da floresta). .

Com o Scikit-Learn, podemos buscar esses dados da seguinte forma:

Em [13]: de sklearn.datasets importar fetch_species_distributions

dados = fetch_species_distributions()

498 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

# Obtenha matrizes/ matrizes de IDs de espécies e locais


latlon = np.vstack([data.train['dd lat'], data.train['dd
long']]).T
espécie = np.array([d.decode('ascii').startswith('micro') para d em
data.train['species']], dtype='int')

Com esses dados carregados, podemos usar o kit de ferramentas Basemap (mencionado anteriormente em
“Dados geográficos com mapa base” na página 298) para traçar as localizações observadas dessas duas espécies no
mapa da América do Sul (Figura 5-146):

Em [14]: de mpl_toolkits.basemap import Basemap de


sklearn.datasets.species_distributions import construct_grids

xgrid, ygrid = construct_grids(dados)

# plotar litorais com Mapa Base m =


Mapa Base(projeção='cyl', resolução='c',
llcrnrlat=ygrid.min(), urcrnrlat=ygrid.max(),
llcrnrlon=xgrid.min(), urcrnrlon=xgrid.max ())
m.drawmapboundary(fill_color='#DDEEFF')
m.fillcontinents(color='#FFEEDD')
m.drawcoastlines(color='gray', zorder=2)
m.drawcountries(color='gray', zorder=2)

# localizações do
gráfico m.scatter(latlon[:, 1], latlon[:, 0], zorder=3,
c=espécie, cmap='arco-íris', latlon=True);

Figura 5-146. Localização das espécies nos dados de treinamento

Infelizmente, isto não dá uma ideia muito boa da densidade das espécies, porque pontos na distribuição das espécies
podem sobrepor-se uns aos outros. Você pode não perceber olhando para este gráfico, mas há mais de 1.600 pontos
mostrados aqui!

Em profundidade: estimativa de densidade do kernel | 499


Machine Translated by Google

Vamos usar a estimativa de densidade do kernel para mostrar esta distribuição de uma forma
mais interpretável: como uma indicação suave de densidade no mapa. Como o sistema de
coordenadas aqui está em uma superfície esférica e não em um plano plano, usaremos a métrica
de distância Haversine , que representará corretamente as distâncias em uma superfície curva.

Há um pouco de código clichê aqui (uma das desvantagens do kit de ferramentas do Mapa Base),
mas o significado de cada bloco de código deve ser claro (Figura 5-147):

In[15]:
# Configure a grade de dados para o gráfico de
contorno X, Y = np.meshgrid(xgrid[::5], ygrid[::5][::-1])
land_reference = data.coverages[6 ][::5, ::5] land_mask
= (land_reference > -9999).ravel() xy =
np.vstack([Y.ravel(), X.ravel()]).T xy =
np.radians( xy[máscara_de_terra])

# Crie dois gráficos lado a lado fig, ax


= plt.subplots(1, 2)
fig.subplots_adjust(left=0.05, right=0.95, wspace=0.05)
species_names = ['Bradypus Variegatus', 'Microryzomys Minutus'] cmaps =
['Roxos', 'Vermelhos']

para i, axi in enumerate(ax):


axi.set_title(species_names[i])

# plotar litorais com Mapa Base m =


Mapa Base(projeção='cyl', llcrnrlat=Y.min(), urcrnrlat=Y.max(),
llcrnrlon=X.min(), urcrnrlon=X.max(),
resolução=' c', machado = eixo)
m.drawmapboundary(fill_color='#DDEEFF')
m.drawcoastlines()
m.drawcountries()

# constrói uma estimativa esférica da densidade do kernel da distribuição kde =


KernelDensity(bandwidth=0.03, metric='haversine')
kde.fit(np.radians(latlon[species == i]))

# avalia apenas na terra: -9999 indica oceano Z =


np.full(land_mask.shape[0], -9999.0)
Z[land_mask] = np.exp(where.score_samples(xy))
Z = Z.remodelar(X.forma)

# traçar contornos dos níveis de


densidade = np.linspace(0, Z.max(), 25)
axi.contourf(X, Y, Z, levels=levels, cmap=cmaps[i])

500 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

Figura 5-147. Uma representação da densidade do kernel das distribuições de espécies

Em comparação com o gráfico de dispersão simples que utilizámos inicialmente, esta visualização mostra uma
imagem muito mais clara da distribuição geográfica das observações destas duas espécies.

Exemplo: Bayes não tão ingênuo Este

exemplo analisa a classificação generativa Bayesiana com o KDE e demonstra como usar a arquitetura Scikit-Learn
para criar um estimador personalizado.

Em “Em profundidade: classificação Naive Bayes” na página 382, demos uma olhada na classificação Bayesiana
ingênua, na qual criamos um modelo generativo simples para cada classe e usamos esses modelos para construir
um classificador rápido. Para Bayes ingênuo, o modelo generativo é um gaussiano simples alinhado ao eixo. Com
um algoritmo de estimativa de densidade como o KDE, podemos remover o elemento “ingênuo” e realizar a mesma
classificação com um modelo generativo mais sofisticado para cada classe. Ainda é uma classificação bayesiana,
mas não é mais
ingênuo.

A abordagem geral para classificação generativa é esta:

1. Divida os dados de treinamento por rótulo.

2. Para cada conjunto, ajuste um KDE para obter um modelo generativo dos dados. Isso permite que qualquer
observação x e rótulo y calcule uma probabilidade P xy .

3. A partir do número de exemplos de cada classe no conjunto de treinamento, calcule a classe


anterior, P e .

4. Para um ponto desconhecido x, a probabilidade posterior para cada classe é P yx P xy P y . A classe que
maximiza esta posterior é o rótulo atribuído ao ponto.

Em profundidade: estimativa de densidade do kernel | 501


Machine Translated by Google

O algoritmo é simples e intuitivo de entender; a parte mais difícil é colocá-lo na estrutura


Scikit-Learn para fazer uso da pesquisa em grade e da arquitetura de validação cruzada.

Este é o código que implementa o algoritmo na estrutura Scikit-Learn; iremos percorrê-


lo seguindo o bloco de código:
In[16]: de sklearn.base importar BaseEstimator, ClassifierMixin

classe KDEClassifier(BaseEstimator, ClassifierMixin):


"""Classificação generativa Bayesiana baseada no KDE

Parâmetros
----------

largura de banda: flutua


a largura de banda do kernel dentro de cada classe
kernel:str
o nome do kernel, passado para KernelDensity
"""

def __init__(self, largura de banda=1.0, kernel='gaussian'):


self.bandwidth = largura de banda
self.kernel = kernel

def fit(self, X, y): self.classes_


= np.sort(np.unique(y)) training_sets = [X[y == yi] para
yi em self.classes_] self.models_ = [KernelDensity(bandwidth) =self.bandwidth,

kernel=self.kernel).fit(Xi)
para Xi em training_sets]
self.logpriors_ = [np.log(Xi.shape[0] / X.shape[0]) para Xi em training_sets]

retornar a si mesmo

def prever_proba(self, X):


logprobs = np.array([model.score_samples(X) para modelo em
self.models_]).T resultado = np.exp(logprobs
+ self.logpriors_) retornar resultado / result.sum(1, keepdims=True)

def prever(self, X): retornar


self.classes_[np.argmax(self.predict_proba(X), 1)]

A anatomia de um estimador personalizado

Vamos percorrer este código e discutir os recursos essenciais:


de sklearn.base importar BaseEstimator, ClassifierMixin

classe KDEClassifier(BaseEstimator, ClassifierMixin):


"""Classificação generativa Bayesiana baseada no KDE

502 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

Parâmetros
----------

largura de banda: flutua


a largura de banda do kernel dentro de cada classe
kernel:str
o nome do kernel, passado para KernelDensity
"""

Cada estimador no Scikit-Learn é uma classe, e é mais conveniente que esta classe herde da classe
BaseEstimator , bem como do mixin apropriado, que fornece funcionalidade padrão. Por exemplo, entre
outras coisas, aqui o BaseEstima tor contém a lógica necessária para clonar/copiar um estimador para
uso em um procedimento de validação cruzada, e ClassifierMixin define um método score() padrão usado
por tais rotinas. Também fornecemos uma docstring, que será capturada pela funcionalidade de ajuda do
IPython (consulte “Ajuda e documentação no IPython” na página 3).

A seguir vem o método de inicialização da classe:

def __init__(self, largura de banda=1.0, kernel='gaussian'):


self.bandwidth = largura de banda
self.kernel = kernel

Este é o código real executado quando o objeto é instanciado com KDEClassi fier(). No Scikit-Learn, é
importante que a inicialização não contenha outras operações além de atribuir os valores passados por
nome a si mesmo. Isso se deve à lógica contida no BaseEstimator necessária para clonar e modificar
estimadores para validação cruzada, pesquisa em grade e outras funções. Da mesma forma, todos os
argumentos para __init__ devem ser explícitos; isto é, *args ou **kwargs devem ser evitados, pois não
serão tratados corretamente nas rotinas de validação cruzada.

Em seguida vem o método fit() , onde tratamos os dados de treinamento:

def fit(self, X, y): self.classes_


= np.sort(np.unique(y)) training_sets = [X[y == yi] para
yi em self.classes_] self.models_ = [KernelDensity(bandwidth) =self.bandwidth,

kernel=self.kernel).fit(Xi)
para Xi em training_sets]
self.logpriors_ = [np.log(Xi.shape[0] / X.shape[0]) para Xi em training_sets]

retornar a si mesmo

Aqui encontramos as classes exclusivas nos dados de treinamento, treinamos um modelo KernelDensity
para cada classe e calculamos os antecedentes das classes com base no número de amostras de entrada.
Finalmente, fit() deve sempre retornar self para que possamos encadear comandos. Por exemplo:

rótulo = modelo.fit(X, y).predict(X)

Em profundidade: estimativa de densidade do kernel | 503


Machine Translated by Google

Observe que cada resultado persistente do ajuste é armazenado com um sublinhado final (por exemplo,
self.logpriors_). Esta é uma convenção usada no Scikit-Learn para que você possa verificar rapidamente os
membros de um estimador (usando o preenchimento de tabulação do IPython) e ver exatamente quais membros
são adequados para os dados de treinamento.

Finalmente, temos a lógica para prever rótulos em novos dados:

def predizer_proba(self, X):


logprobs = np.vstack([model.score_samples(X) para
modelo em self.models_]).T
resultado = np.exp(logprobs + self.logpriors_) retornar
resultado / resultado.sum( 1, keepdims=Verdadeiro)

def prever(self, X):


retornar self.classes_[np.argmax(self.predict_proba(X), 1)]

Como este é um classificador probabilístico, primeiro implementamos predizer_proba(), que retorna uma matriz
de probabilidades de classe de formato [n_samples, n_classes]. A entrada [i, j] desta matriz é a probabilidade
posterior de que a amostra i seja membro da classe j, calculada multiplicando a probabilidade pela classe
anterior e normalizando.

Finalmente, o método predizer() usa essas probabilidades e simplesmente retorna a classe com a maior
probabilidade.

Usando nosso estimador

personalizado Vamos testar esse estimador personalizado em um problema que já vimos antes: a classificação
de dígitos manuscritos. Aqui carregaremos os dígitos e calcularemos a pontuação de validação cruzada para
uma variedade de larguras de banda candidatas usando o metaestimador GridSearchCV (consulte
“Hiperparâmetros e validação de modelo” na página 359 para obter mais informações sobre isso):

In[17]: de sklearn.datasets importar load_digits


de sklearn.grid_search importar GridSearchCV

dígitos = carregar_dígitos()

larguras de banda = 10 ** np.linspace(0, 2, 100)


grid = GridSearchCV(KDEClassifier(), {'bandwidth': larguras de banda})
grid.fit(digits.data, digits.target)

pontuações = [val.mean_validation_score para val em grid.grid_scores_]

A seguir, podemos representar graficamente a pontuação da validação cruzada em função da largura de banda
(Figura 5-148):

Em [18]: plt.semilogx(largura de banda,


pontuações) plt.xlabel('largura
de banda')
plt.ylabel('precisão') plt.title('Desempenho do modelo KDE ')

504 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

imprimir (grid.best_params_)
imprimir ('precisão =', grid.best_score_)

{'largura de banda': 7,0548023107186433}


precisão = 0,966611018364

Figura 5-148. Curva de validação para o classificador bayesiano baseado no KDE

Vemos que esse classificador bayesiano não tão ingênuo atinge uma precisão de validação cruzada de
pouco mais de 96%; isso é comparado a cerca de 80% para a classificação Bayesiana ingênua:

In[19]: de sklearn.naive_bayes importar GaussianNB


de sklearn.cross_validation importar cross_val_score
cross_val_score(GaussianNB(), dígitos.data, dígitos.target).mean()

Fora[19]: 0,81860038035501381

Um benefício desse classificador generativo é a interpretabilidade dos resultados: para cada amostra
desconhecida, não obtemos apenas uma classificação probabilística, mas também um modelo completo
da distribuição de pontos com os quais estamos comparando! Se desejado, isso oferece uma janela
intuitiva sobre as razões para uma classificação específica que algoritmos como SVMs e florestas
aleatórias tendem a obscurecer.

Se você quiser ir mais longe, existem algumas melhorias que podem ser feitas em nosso modelo de
classificador do KDE:

• Poderíamos permitir que a largura de banda em cada classe variasse

independentemente. • Poderíamos otimizar essas larguras de banda não com base em sua pontuação
de previsão, mas na probabilidade dos dados de treinamento sob o modelo generativo dentro de
cada classe (ou seja, usar as pontuações do próprio KernelDensity em vez da precisão da previsão
global ) .

Em profundidade: estimativa de densidade do kernel | 505


Machine Translated by Google

Finalmente, se você quiser praticar a construção de seu próprio estimador, você pode tentar construir
um classificador bayesiano semelhante usando modelos de mistura gaussiana em vez do KDE.

Aplicação: Um pipeline de detecção de rosto


Este capítulo explorou vários conceitos e algoritmos centrais do aprendizado de máquina. Mas passar
destes conceitos para a aplicação no mundo real pode ser um desafio. Os conjuntos de dados do
mundo real são barulhentos e heterogêneos, podem ter recursos ausentes e podem incluir dados
em um formato que é difícil de mapear para uma matriz limpa [n_samples, n_features] . Antes de
aplicar qualquer um dos métodos discutidos aqui, você deve primeiro extrair esses recursos dos
seus dados; não existe uma fórmula de como fazer isso que se aplique a todos os domínios e,
portanto, é aqui que você, como cientista de dados, deve exercitar sua própria intuição e experiência.

Uma aplicação interessante e atraente do aprendizado de máquina é em imagens, e já vimos alguns


exemplos disso onde recursos em nível de pixel são usados para classificação. No mundo real, os
dados raramente são tão uniformes e pixels simples não serão adequados, um fato que levou a uma
grande literatura sobre métodos de extração de recursos para dados de imagem (consulte
“Engenharia de recursos” na página 375) .

Nesta seção, daremos uma olhada em uma dessas técnicas de extração de características, o
Histograma de Gradientes Orientados (HOG), que transforma pixels de imagem em uma
representação vetorial que é sensível a características de imagem amplamente informativas,
independentemente de fatores de confusão como iluminação. Usaremos esses recursos para
desenvolver um pipeline simples de detecção facial, usando algoritmos e conceitos de aprendizado
de máquina que vimos ao longo deste capítulo. Começamos com as importações padrão:

In[1]: %matplotlib importação


inline matplotlib.pyplot as plt import
seaborn as sns; sns.set() importa
numpy como np

Recursos do HOG

O Histograma de Gradientes é um procedimento simples de extração de características que foi


desenvolvido no contexto da identificação de pedestres em imagens. HOG envolve as seguintes
etapas:

1. Opcionalmente, pré-normalize as imagens. Isto leva a características que resistem à dependência


de variações na iluminação.

2. Convolver a imagem com dois filtros sensíveis aos gradientes de brilho horizontais e verticais.
Eles capturam informações de borda, contorno e textura.

3. Subdivida a imagem em células de tamanho predeterminado e calcule um histograma


das orientações do gradiente dentro de cada célula.

506 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

4. Normalize os histogramas em cada célula comparando com o bloco de células vizinhas. Isso suprime
ainda mais o efeito de iluminação na imagem.
5. Construa um vetor de características unidimensional a partir das informações de cada célula.

Um extrator HOG rápido está embutido no projeto Scikit-Image, e podemos experimentá-lo de forma
relativamente rápida e visualizar os gradientes orientados dentro de cada célula (Figura 5-149):

In[2]: de dados de importação de skimage , cor, importação


de recursos skimage.data

imagem = color.rgb2gray(data.chelsea()) hog_vec,


hog_vis = feature.hog(imagem, visualizar=True)

fig, ax = plt.subplots(1, 2, figsize=(12, 6),


subplot_kw=dict(xticks=[], yticks=[]))
ax[0].imshow(image, cmap='gray')
machado[0].set_title(' imagem de entrada')

ax[1].imshow(hog_vis)
ax[1].set_title('visualização dos recursos do HOG');

Figura 5-149. Visualização de recursos HOG calculados a partir de uma imagem

HOG em ação: um detector facial simples Usando

esses recursos do HOG, podemos construir um algoritmo simples de detecção facial com qualquer estimador
Scikit-Learn; aqui usaremos uma máquina de vetores de suporte linear (consulte “Detalhes: Máquinas de
vetores de suporte” na página 405 se precisar de uma atualização sobre isso). As etapas são as seguintes:

1. Obtenha um conjunto de miniaturas de imagens de rostos para constituir um treinamento “positivo”


amostras.

2. Obtenha um conjunto de miniaturas de imagens de não-rostos para constituir um treinamento “negativo”


amostras.

3. Extraia os recursos do HOG desses exemplos de treinamento.

Aplicação: Um pipeline de detecção de rosto | 507


Machine Translated by Google

4. Treine um classificador SVM linear nessas amostras.

5. Para uma imagem “desconhecida”, passe uma janela deslizante pela imagem, usando o
modelo para avaliar se aquela janela contém uma face ou não.

6. Se as detecções se sobrepuserem, combine-as em uma única janela.

Vamos seguir estas etapas e experimentar:

1. Obtenha um conjunto de amostras de treinamento positivas.

Vamos começar encontrando alguns exemplos de treinamento positivos que mostram uma variedade de faces.
Temos um conjunto fácil de dados para trabalhar – o conjunto de dados Labeled Faces in the Wild, que pode ser
baixado pelo Scikit-Learn:

Em [3]: de sklearn.datasets importar fetch_lfw_people faces =


fetch_lfw_people() Positive_patches
= Faces.images Positive_patches.shape

Fora[3]: (13233, 62, 47)

Isso nos dá uma amostra de 13.000 imagens faciais para usar em treinamento.

2. Obtenha um conjunto de amostras de treinamento negativas.

Em seguida, precisamos de um conjunto de miniaturas de tamanhos semelhantes que não tenham um rosto.
Uma maneira de fazer isso é pegar qualquer corpus de imagens de entrada e extrair miniaturas delas em diversas
escalas. Aqui podemos usar algumas das imagens enviadas com o Scikit-Image, junto com o PatchExtractor do Scikit-

Learn:

In[4]: a partir de dados de importação de skimage , transforme

imgs_to_use = ['câmera', 'texto', 'moedas', 'lua', 'página', 'relógio' ,


'imunohistoquímica', 'chelsea', 'café',
'hubble_deep_field'] imagens =
[color.rgb2gray( getattr(dados, nome)())
para nome em imgs_to_use]

Em [5]:
de sklearn.feature_extraction.image importar PatchExtractor

def extract_patches(img, N, escala=1,0,


patch_size=positivo_patches[0].forma):
extraído_patch_size = \
tuple((escala * np.array(patch_size)).astype(int)) extrator =
PatchExtractor(patch_size=extracted_patch_size,
max_patches=N, random_state=0)
patches = extractor.transform(img[np.newaxis]) if scale != 1:
patches =
np.array([transform.resize(patch, patch_size) para patch em patches])

patches de retorno

508 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

negativo_patches = np.vstack([extract_patches(im, 1000, escala) para im


em imagens para escala em [0,5, 1,0, 2,0]])
negativo_patches.shape

Fora[5]: (30000, 62, 47)

Agora temos 30.000 patches de imagens adequados que não contêm rostos. Vamos dar
uma olhada em alguns deles para ter uma ideia de sua aparência (Figura 5-150):
In[6]: fig, ax = plt.subplots(6, 10)
para i, axi in enumerate(ax.flat):
axi.imshow(negative_patches[500 * i], cmap='gray') axi.axis('off')

Figura 5-150. Patches de imagens negativas, que não incluem rostos

Nossa esperança é que isso cubra suficientemente o espaço de “não-faces” que nosso
algoritmo provavelmente verá.
3. Combine conjuntos e extraia recursos do HOG.

Agora que temos essas amostras positivas e negativas, podemos combiná-las e calcular as
características do HOG. Esta etapa demora um pouco, porque os recursos do HOG
envolvem um cálculo não trivial para cada imagem:
Em [7]: da cadeia de importação de
itertools X_train = np.array([feature.hog(im)
para estou em cadeia (patches_positivos,
patches_negativos)])
y_train = np.zeros(X_train.shape[0])
y_train[:positivo_patches.shape[0]] = 1

Em[8]: X_train.shape

Fora[8]: (43233, 1215)

Aplicação: Um pipeline de detecção de rosto | 509


Machine Translated by Google

Ficamos com 43.000 amostras de treinamento em 1.215 dimensões e agora temos nossos dados em um formato
que podemos alimentar no Scikit-Learn!

4. Treine uma máquina de vetores de suporte.

A seguir, usaremos as ferramentas que exploramos neste capítulo para criar um classificador de patches de
miniatura. Para uma tarefa de classificação binária de alta dimensão, uma máquina de vetores de suporte linear é
uma boa escolha. Usaremos a linha arSVC do Scikit-Learn, pois em comparação ao SVC ela geralmente possui
melhor dimensionamento para grande número de amostras.

Primeiro, porém, vamos usar um simples Bayes gaussiano ingênuo para obter uma linha de base rápida:

In[9]: de sklearn.naive_bayes importar GaussianNB


de sklearn.cross_validation importar cross_val_score

cross_val_score(GaussianNB(), X_train, y_train)

Fora[9]: array([ 0,9408785 , 0,8752342 , 0,93976823])

Vemos que em nossos dados de treinamento, mesmo um simples algoritmo ingênuo de Bayes nos leva a mais de
90% de precisão. Vamos tentar a máquina de vetores de suporte, com uma pesquisa em grade sobre algumas
opções do parâmetro C:

Em [10]: de sklearn.svm import LinearSVC de


sklearn.grid_search import GridSearchCV grid =
GridSearchCV(LinearSVC(), {'C': [1.0, 2.0, 4.0, 8.0]}) grid.fit(X_train, y_train) grid .melhor
pontuação_

Saída[10]: 0,98667684407744083

Em[11]: grid.best_params_

Fora[11]: {'C': 4,0}

Vamos pegar o melhor estimador e treiná-lo novamente no conjunto de dados completo:

Em [12]: modelo = grid.best_estimator_ model.fit


(X_train, y_train)

Out[12]: LinearSVC(C=4.0, class_weight=None, dual=True, fit_intercept=True,


intercept_scaling=1, loss='squared_hinge', max_iter=1000,
multi_class='ovr', penalidade='l2', random_state
=Nenhum, tol=0,0001, detalhado=0)

5. Encontre rostos em uma nova imagem.

Agora que temos esse modelo instalado, vamos pegar uma nova imagem e ver como o modelo se sai. Usaremos
uma parte da imagem do astronauta para simplificar (veja a discussão sobre isso em “Advertências e Melhorias” na
página 512), e executaremos uma janela deslizante sobre ela e avaliaremos cada patch (Figura 5-151):

510 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

Em[13]: test_image = skimage.data.astronaut()


test_image = skimage.color.rgb2gray(test_image)
test_image = skimage.transform.rescale(test_image, 0,5) test_image
= test_image[:160, 40:180]

plt.imshow(test_image, cmap='cinza')
plt.axis('off');

Figura 5-151. Uma imagem na qual tentaremos localizar um rosto

A seguir, vamos criar uma janela que itera sobre patches desta imagem e calcular
Recursos do HOG para cada patch:

Em [14]: def janela_deslizante(img, patch_size=positivo_patches[0].shape, istep=2,


jstep=2, escala=1.0): Ni, Nj =
(int(escala * s) para s em patch_size) para i no
intervalo(0, img.shape[0] - Ni, istep):
para j no intervalo (0, img.shape[1] - Ni, jstep): patch
= img[i:i + Ni, j:j + Nj] se escala != 1:
patch =
transform.resize(patch, patch_size ) rendimento (i,
j), patch

índices, patches = zip(*sliding_window(test_image))


patches_hog = np.array([feature.hog(patch) para patch em patches])
patches_hog.shape

Fora[14]: (1911, 1215)

Finalmente, podemos pegar esses patches com recursos do HOG e usar nosso modelo para
avaliar se cada patch contém uma face:

Em[15]: rótulos = model.predict(patches_hog)


rótulos.sum()

Aplicação: Um pipeline de detecção de rosto | 511


Machine Translated by Google

Fora[15]: 33,0

Vemos que de quase 2.000 patches, encontramos 30 detecções. Vamos usar as informações
que temos sobre esses patches para mostrar onde eles estão em nossa imagem de teste,
desenhando-os como retângulos (Figura 5-152):

In[16]: fig, ax = plt.subplots()


ax.imshow(test_image, cmap='gray')
ax.axis('off')

Ni, Nj = patches_positivos[0] .índices de


forma = np.array(índices)

para i, j em índices[labels == 1]:


ax.add_patch(plt.Rectangle((j, i), Nj, Ni, edgecolor='red', alpha=0.3, lw=2,
facecolor='none' ))

Figura 5-152. Janelas que foram determinadas para conter um rosto

Todas as manchas detectadas se sobrepõem e encontram o rosto na imagem! Nada mal para
algumas linhas de Python.

Advertências e melhorias Se você se

aprofundar um pouco mais no código e nos exemplos anteriores, verá que ainda temos um pouco de
trabalho antes de podermos reivindicar um detector facial pronto para produção. Existem vários
problemas com o que fizemos e várias melhorias que poderiam ser feitas. Em particular:

512 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

Nosso conjunto de treinamento, especialmente para recursos negativos, não é


muito completo. A questão central é que existem muitas texturas semelhantes a faces que não
estão no conjunto de treinamento e, portanto, nosso modelo atual é muito propenso a falsos
positivos. Você pode ver isso se testar o algoritmo anterior na imagem completa do astronauta: o
modelo atual leva a muitas detecções falsas em outras regiões da imagem.

Poderíamos imaginar resolver isso adicionando uma variedade maior de imagens ao conjunto de
treinamento negativo, e isso provavelmente traria alguma melhoria. Outra maneira de resolver isso
é usar uma abordagem mais direcionada, como a mineração negativa pesada. Na mineração
negativa pesada, pegamos um novo conjunto de imagens que nosso classificador não viu,
encontramos todos os patches que representam falsos positivos e os adicionamos explicitamente
como instâncias negativas no conjunto de treinamento antes de treinar novamente o classificador.

Nosso pipeline atual pesquisa apenas em uma escala


Conforme escrito atualmente, nosso algoritmo perderá faces que não tenham aproximadamente
62×47 pixels. Podemos resolver isso diretamente usando janelas deslizantes de vários tamanhos
e redimensionando cada patch usando skimage.transform.resize antes de inseri-lo no modelo. Na
verdade, o utilitário deslizante_window() usado aqui já foi construído com isso em mente.

Devemos combinar patches de detecção sobrepostos


Para um pipeline pronto para produção, preferiríamos não ter 30 detecções do mesmo rosto, mas
de alguma forma reduzir grupos sobrepostos de detecções a uma única detecção. Isso poderia
ser feito por meio de uma abordagem de clustering não supervisionado (MeanShift Clustering é
um bom candidato para isso) ou por meio de uma abordagem processual, como supressão não
máxima, um algoritmo comum em visão de máquina.

O pipeline deve ser simplificado Depois


de resolvermos esses problemas, também seria bom criar um pipeline mais simplificado para
ingerir imagens de treinamento e prever resultados de janelas deslizantes.
É aqui que o Python como ferramenta de ciência de dados realmente brilha: com um pouco de
trabalho, poderíamos pegar nosso código de protótipo e empacotá-lo com uma API orientada a
objetos bem projetada que dá ao usuário a capacidade de usá-lo facilmente. Deixarei isso como
um proverbial “exercício para o leitor”.

Avanços mais recentes, como a aprendizagem profunda, devem ser


considerados. Finalmente, devo acrescentar que o HOG e outros métodos procedurais de extração
de características para imagens não são mais técnicas de última geração. Em vez disso, muitos
pipelines modernos de detecção de objetos usam variantes de redes neurais profundas. Uma
maneira de pensar nas redes neurais é que elas são um estimador que determina estratégias
ideais de extração de características dos dados, em vez de confiar na intuição do usuário. Uma
introdução a esses métodos de redes neurais profundas está conceitualmente (e
computacionalmente!) além do escopo desta seção, embora ferramentas abertas como o Google

Aplicação: Um pipeline de detecção de rosto | 513


Machine Translated by Google

O TensorFlow recentemente tornou as abordagens de aprendizagem profunda muito mais


acessíveis do que antes. No momento em que este livro foi escrito, o aprendizado profundo em
Python ainda era relativamente jovem e, portanto, ainda não posso apontar nenhum recurso
definitivo. Dito isto, a lista de referências na seção seguinte deve fornecer um local útil para
começar.

Outros recursos de aprendizado de máquina


Este capítulo foi um rápido tour pelo aprendizado de máquina em Python, usando principalmente as
ferramentas da biblioteca Scikit-Learn. Por mais longo que seja o capítulo, ele ainda é muito curto
para cobrir muitos algoritmos, abordagens e discussões interessantes e importantes.
Quero sugerir aqui alguns recursos para quem deseja aprender mais sobre aprendizado de máquina.

Aprendizado de máquina em Python

Para aprender mais sobre aprendizado de máquina em Python, sugiro alguns dos seguintes
recursos:

O site Scikit-Learn
O site Scikit-Learn possui uma impressionante variedade de documentação e exemplos que
cobrem alguns dos modelos discutidos aqui e muito, muito mais. Se você deseja uma breve
pesquisa sobre os algoritmos de aprendizado de máquina mais importantes e frequentemente
usados, este site é um bom lugar para começar.

Vídeos tutoriais de SciPy, PyCon e PyData


Scikit-Learn e outros tópicos de aprendizado de máquina são favoritos perenes nos tutoriais de
muitas séries de conferências focadas em Python, em particular as conferências PyCon, SciPy
e PyData. Você pode encontrar os mais recentes por meio de uma simples pesquisa na web.

Introdução ao aprendizado de máquina com Python


Escrito por Andreas C. Mueller e Sarah Guido, este livro inclui um tratamento mais completo
dos tópicos deste capítulo. Se você estiver interessado em revisar os fundamentos do
aprendizado de máquina e levar o kit de ferramentas Scikit-Learn ao seu limite, este é um ótimo
recurso, escrito por um dos desenvolvedores mais prolíficos do Scikit-Learn.
equipe.

O livro de Python Machine


Learning Sebastian Raschka concentra-se menos no Scikit-Learn em si e mais na variedade de
ferramentas de aprendizado de máquina disponíveis em Python. Em particular, há uma
discussão muito útil sobre como dimensionar abordagens de aprendizado de máquina baseadas
em Python para conjuntos de dados grandes e complexos.

514 | Capítulo 5: Aprendizado de Máquina


Machine Translated by Google

Aprendizado de máquina geral


É claro que o aprendizado de máquina é muito mais amplo do que apenas o mundo Python.
Existem muitos recursos bons para levar seu conhecimento adiante, e aqui destaco alguns
que considero úteis:

Aprendizado de máquina
ministrado por Andrew Ng (Coursera), este é um curso online gratuito e ensinado de forma muito clara,
cobrindo os fundamentos do aprendizado de máquina de uma perspectiva algorítmica. Ele pressupõe
compreensão de matemática e programação em nível de graduação e percorre considerações detalhadas
de alguns dos algoritmos de aprendizado de máquina mais importantes. As tarefas de casa, que são
avaliadas por algoritmos, permitem que você mesmo implemente alguns desses modelos.

Reconhecimento de padrões e aprendizado de máquina


Escrito por Christopher Bishop, este texto técnico clássico cobre detalhadamente os conceitos de
aprendizado de máquina discutidos neste capítulo. Se você pretende ir mais longe neste assunto, você
deve ter este livro em sua estante.

Aprendizado de máquina: uma perspectiva probabilística


Escrito por Kevin Murphy, este é um excelente texto de pós-graduação que explora quase todos os
algoritmos importantes de aprendizado de máquina a partir de uma perspectiva probabilística unificada e
básica.

Esses recursos são mais técnicos do que o material apresentado neste livro, mas para realmente compreender
os fundamentos desses métodos é necessário um mergulho profundo na matemática por trás deles. Se você está
pronto para o desafio e para levar sua ciência de dados para o próximo nível, não hesite em mergulhar!

Mais recursos de aprendizado de máquina | 515


Machine Translated by Google
Machine Translated by Google

Índice

Símbolos agregados multidimensionais, exemplo

%automagic, 19 de altura média de 60 presidentes, 61 somando

%cpaste, 11 os valores em uma matriz, 59 funções


diversas, 61 agregação
%debug, 22
%history, 16 (Pandas), 158-170

%lprun, 28 operação groupby (), 161-170


MultiIndex, conjunto
%lsmagic , 13
de dados de 140 planetas
%magic, 13
%matplotlib, 219 para, 159 agregação simples,
%memit, 29 159-161 critério de informação de Akaike (AIC), 487,
%mode, 20-22 489 projeção de área igual de Albers,

%mprun, 29 303 eficiência algorítmica

%paste, 11 notação big-O, 92


tamanho do conjunto
%prun, 27
%run, 12 de dados e , 85 e
%time, 25-27 comercial (&), 77

%timeit, 12, 25-27 & Anaconda, xiv e

(e comercial), 77 * palavra-chave, 77 anotação de


(asterisco), 7 : gráficos, 268-275

(dois pontos), setas, 272-275 exemplo de feriados/

44 ? (ponto de nascimentos nos EUA, 269 transformações e

interrogação), 3 ?? (ponto de posição de texto, 270-272 APIs

interrogação duplo), 5 _ atalho (consulte API do Estimador) anexar ( ), método

(sublinhado), 15 | (operador), 77 Pandas vs. Python, 146


método apply(), 167

operadores aritméticos, 52 arrays acessando


Uma função de valor absoluto,
linhas/colunas únicas, 45
54 métodos agregados(), 166
operadores
agregados
aritméticos,
calculados diretamente do objeto, 57
52 atributos, 42
multidimensionais, 60
básicos, 42 booleanos,
conjuntos resumidos de valores com, 61
73-75
agregação (NumPy), 58-63
transmissão, 63-69 centralização, 68 cálculo ativado, 50-58
mínimo e máximo, 59

517
Machine Translated by Google

concatenação, 48, 142 seleção de modelo e regressão linear

criação de cópias, 46 de previsão de tráfego de


criação de listas Python, 39 criação do bicicletas 364-366 , 400
zero, 39 dados como, 33 objeto séries temporais, 202-209
DataFrame notação big-O, 92 ufuncs
como, 102 objeto DataFrame binários, 52 binnings,
construído a partir de, 105 tipo fixo, 38 objeto Index 248 operadores
como matriz lógicos bit a bit, 74 bogosort, 86
imutável, 106 objeto Index vs., 106 indexação:
acessando elementos Bokeh, 330

únicos, 43 remodelagem, 47 série de objetos vs., 99 Matrizes booleanas


fatiamento, 44 Operadores booleanos e, 74
fatiamento de submatrizes entradas de contagem, 73
trabalhando com, 73-75
multidimensionais, 45 fatiamento de submatrizes Máscaras booleanas, 70-78

unidimensionais, 44 classificação, 85-96 Matrizes booleanas como, 75-78


especificação de estatísticas de precipitação,

saída para, 56 divisão, 49 tipos 70 trabalhando com matrizes booleanas, 73-75


de dados Operadores booleanos, 74
padrão, 41 estruturados, 92 transmissão, 63-69 adição
-96 submatrizes como de array bidimensional a array unidimensional, 66
visualizações sem cópia, 46 valores de básico, 63-65 centralização
soma, 59 funções universais, de um array, 68
50-58 setas, 272-275 método definido, 58, 63 na prática,
asfreq(), 197-199 68 plotagem de

asterisco (*), 7 funções automáticas, função


limites de 19 bidimensional, 69 regras, 65 -68 dois arrays
eixos, 228-230 compatíveis, 66

dois arrays incompatíveis, 67

bagging, largura
de banda 426 (consulte largura de banda do Dados categóricos C , 376
kernel) operador de barra rótulos de classe (para ponto de dados),
(|), gráficos de 77 barras, 321 334 tarefas de classificação

Dados geográficos do kit definido, 332

de ferramentas de mapa base com, 298 aprendizado de máquina, 333-335


(ver também dados geográficos) clustering, 332
instalação, regressão básico, 338-339

de função de base 298 , 378, 392-396 GMMs, 353, 476-491 k-


Funções de base gaussiana, 394-396 funções means, 339, 462-476 código

de base polinomial, 393


Classificação Bayesiana, 383, 501-506 comandos mágicos para determinar o tempo de
(veja também classificação ingênua de Bayes) execução, 12

Critério de informação bayesiano (BIC), 487 comandos mágicos para colar blocos, 11 comandos
Folha de estilo de Métodos Bayesianos para Hackers, 288 mágicos para execução externa, 12 perfis e tempo, 25-30
Teorema de Bayess, 383 tempo de trechos, 25-27 coeficiente
largura de banda do kernel de de determinação, 365
compensação de polarização e variância e, 497

518 | Índice
Machine Translated by Google

dois pontos (:), como dicionário, 110-112


compactação de 44 cores, 473-476 como array NumPy generalizado, 102 como
barras de cores dicionário especializado, 103 como
seleção de mapa de cores, array bidimensional, 112-114 construção, 104
personalização 256-259 , seleção de dados em,
255-262 discreto, 110 definidos, 97 alinhamento

exemplo de 260 dígitos manuscritos, 261-262 de índice em,

mapa de cores, 256-259 117 mascaramento, 114


coluna(s) com multiplicação
acesso único, 45 indexada, 136 operações
indexação, 163 entre o objeto Series e, 118 fatiamento, 114 método
MultiIndex para, 133 DataFrame.eval(),
matrizes de classificação, 87 211-213 atribuição, 212 variáveis locais, 213
palavras-chave de sufixos e nomes sobrepostos, método DataFrame.query(),
153 213 conjuntos de dados

operações em colunas, 211-213 atalhos de


histórico de comandos, 9 operadores de
comparação, 71-73 conjuntos de dados anexando, 146
de concatenação, combinação (Panda), 141-158
141-146 de matrizes, concatenação, 141-146 fusão/

48, 142 com pd.concat(), junção, 146-158 módulo datetime,


142-146 matriz de confusão, 357 189 datetime64 dtype, 189
projeções cônicas, 303 módulo dateutil, 189
contorno gráficos, densidade depuração, 22-24 árvores

241-245 e, 241-245 função de decisão, 421-426


tridimensional, 241-245 (veja também aleatório
gráfico tridimensional, 292 Conway, Drew, florestas) criação, overfitting
validação cruzada xi , mapa de cores 422-425 , aprendizado
cubehelix 361-370 , 258 profundo 425 ,
projeções cilíndricas, 301 estimador de densidade
513
GMM, histograma

484-488 como, 492

D KDE (veja estimativa de densidade do kernel (KDE))

dados método description(),


desenvolvimento 164 , criação
como matrizes,
de perfil IPython e código de tempo, 25-30
33 representação de dados
scripts completos de criação de
ausentes (ver dados ausentes) (pacote Scikit-Learn),
343-346 perfil, 27 tempo de trechos de código,

dados como tabela, 25-27 dicionário(s)

343 matriz de recursos, DataFrame como especialização de, 103


Objeto DataFrame construído a partir de uma lista de,
344 matriz de destino,
104
344-345 ciência de dados,
Objeto da série Pandas vs., 100
definição, xi tipos
dígitos, reconhecimento de (ver reconhecimento óptico de
de dados, 34 tipo fixo
caracteres)
matrizes, 38
inteiros, 35 listas, 37-41 redução de dimensionalidade, 261
aprendizado de máquina, 340-342
NumPy, 41
PCA e, 433
Objeto DataFrame (Pandas), 102-105

Índice | 519
Machine Translated by Google

classificação discriminativa, documentação modificando valores com, 82


405-407 , acesso ao IPython, 3-8, seleção de pontos aleatórios, 81
98 Pandas, 98 ponto engenharia de recursos, 375-382
de interrogação recursos categóricos, 376
duplo (??), 5 método dropna(), 125 recursos derivados, 378-380

digitação dinâmica, 34 recursos de imagem, 378


imputação de dados ausentes, 381 pipeline
de processamento, 381 recursos
de texto, 377 recursos,

ponto de dados, 334 matriz de


E eigenfaces, estimador/
recursos, 344 método
método de conjunto 442-445 , 421 (ver
fillna(), 126 método filter(),
também florestas aleatórias) aluno
166
de conjunto, 421 projeção
Folha de estilo FiveThirtyEight, 287
cilíndrica equidistante, 301 erros, visualização de
matrizes de tipo fixo, 38
barras de erro básicas,
238 quantidades contínuas,

239 Matplotlib, 237-240 Estimator G


API, 346-359 básico , 347 Funções de base gaussiana, 394-396
exemplo de classificação Iris, Modelos de mistura gaussiana (GMMs), 476-491 escolha do
351 exemplo tipo de covariância, 484 agrupamento
de clustering Iris, 353 exemplo de com, 353 algoritmo de
dimensionalidade Iris, 352 exemplo estimativa de densidade, 484-488
de regressão linear simples, 347-354 função Generalização E – M, exemplo de
eval(), 210-211 método DataFrame.eval() e, 211-213 geração de dados manuscritos 480-484 ,
função pd.eval() e, 210-211 488-491

quando usar, 214 exceções, controle, 20-22 k-significa fraquezas abordadas por, 477-480
advertências do algoritmo de maximização KDE e, 491
de expectativa (EM), Classificação gaussiana ingênua de Bayes, 351, 357,
467-470 GMM como generalização de, 383-386, 510

480-484 k-means clustering e, 465-476 exponenciais, 55 Regressão de processo gaussiano (GPR), 239 modelos
externos código, generativos, 383 dados
comandos mágicos para execução, geográficos, 298
Kit de ferramentas de mapa base para, 298

Exemplo de população de cidade da Califórnia, 308


desenhando um plano de fundo de mapa, 304-307
12 projeções de mapas, 300-304
plotando dados em mapas, 307

F exemplo de dados de temperatura de superfície, 309


operação get(), 183 método
reconhecimento facial
PORCO, 506-514 get_dummies(), 183 folha de estilo
ggplot, 287 bibliotecas
Isomapa, 456-460
PCA, 442-445 gráficas , 330

SVMs, 416-420 Agregação GroupBy, 170


Objeto GroupBy, 163-165
histogramas facetados, 318
método agregado(), 166 método
gráficos de fatores,
apply(), 167 indexação de
319 indexação sofisticada,
78-85 noções coluna, 163 métodos de
despacho, 164 método filter(),
básicas, 79 dados de
166
binning, 83 combinados com outros esquemas de indexação, 80

520 | Índice
Machine Translated by Google

iteração sobre grupos, 164 método matriz imutável, objeto de índice como, 106
transform(), 167 operação importação, preenchimento de guia para, 7
groupby() (Pandas), 161-170 objeto GroupBy e, Em objetos, IPython,
163-165 exemplo de agrupamento, alinhamento de índice
169 tabelas dinâmicas vs., 13 em DataFrame, 117
171 especificação de em Série, 116
chave dividida, 168 exemplo split- Objeto de índice (Pandas), 105-107
apply-combine , 161-163 como matriz imutável, 106
como conjunto ordenado,

H 106
indexação
dígitos manuscritos, reconhecimento de (ver
sofisticada, 78-85 (consulte
reconhecimento de caracteres)
também indexação sofisticada) hierárquico (consulte indexação hierárquica)
mineração negativa difícil, 513
Matrizes NumPy: acessando elementos únicos, 43
ajuda
Pandas, 107
IPython, 3-8
Objeto IndexSlice, 137
funções mágicas, 13
variáveis de indicador, 183
funções help(), 4
junção interna, 153
binnings hexagonais, 248
histórico de entrada/saída, IPython, 13-16
indexação hierárquica em
séries unidimensionais, 128-141 MultiIndex, Objetos In e Out, 13

128-141, 129-131 (consulte também comandos mágicos relacionados, 16


supressão de saída, 15
tipo MultiIndex) reorganizando
atalhos de sublinhado e saídas anteriores,
multi-índices, 137-140 método unstack(), 130
15
com tuplas Python como
instalação, Python, inteiros xiv ,
chaves, 128 advertências e melhorias do
Python, 35 IPython, 1
histograma de gradientes orientados (HOG), 512-514
acessando
recursos, 506 para pipeline de detecção de
rosto, 506-514 documentação com ?, 3 acessando código-
fonte com ??, 5 comandos de linha de
detector de rosto simples, 507-512 histogramas,
comando no shell, 18 controlando exceções,
245-249 dados binning para criar, 83
20-22 depuração, 22-24 documentação,
facetados, 318 KDE e 248,
3- 8, 34 tratamento de
491-496 personalização manual,
erros, 20-24 módulos de
282-284 função
plt.hexbin(), 248 função exploração com preenchimento

plt.hist2d(), 247 Seaborn, 314-317 de guias, 6-7 ajuda e documentação, 3-8 histórico de
entrada/saída, 13-16 atalhos de
simples, 245-246 bidimensional,
teclado no shell, 8 lançamento de
247-249 conjuntos de validação,
360 Hunter, John, 217 notebook Jupyter, 2 lançamento de
shell, 2 comandos mágicos , 10-13
hiperparâmetros,
349 (ver também validação do notebook (consulte o

modelo) notebook Jupyter) plotagem a


partir do shell, 219 criação de perfil e
código de tempo, 25-30
comandos shell, 16-19 comandos mágicos
relacionados ao shell, 19
recursos da web, 30 correspondências de
curingas, 7 conjuntos
Atributo I iloc (Pandas), 110
de dados Iris
imagens, codificação para análise de aprendizado de
máquina, 378

Índice | 521
Machine Translated by Google

como tabela, Seaborn,


343 classificação, 351 visualização 314 de distribuições geográficas, SVM de
agrupamento, 353 kernel

dimensionalidade, 352 498-501 , transformação de

gráficos de pares, kernel 411-414 , truque de kernel

317 gráficos de 413 , atalhos de


dispersão, 236 visualização de, 345 teclado 413 , shell IPython, histórico de 8
método isnull(), 124 comandos, navegação 9 ,
Redução entrada de texto
da dimensionalidade do isomapa, 341, 355 8,9
dados faciais, 456-460 Knuth, Donald, 25
atributo ix (Pandas), 110

rótulos/tarefa de
J jet colormap, 257 classificação de rotulagem, 333-335

junções, 145 agrupamento, 338-339


(veja também fusão) redução de dimensionalidade e, 340-342 tarefa de
categorias de, 147-149 regressão, 335-338 gráficos de
conjuntos de dados, linhas simples, 230-232
146-158 muitos para Projeção cônica conformada de Lambert, 303
um, 148 um para um, regularização de laço (regularização L1), 399 curvas de
147 conjunto aritmético para, aprendizado, computação, 372 junção
152 distribuições conjuntas, 316, 320 esquerda, 153
Lançamento do notebook palavra-chave left_index, 151-152
Jupyter, 2 legendas, escolha
plotagens de, 220 de elementos de plotagem para, 251
personalização, 249-255

K legendas múltiplas nos mesmos eixos, 254


tamanho do ponto,
k-means clustering, 339, 462-476 básico,
463-465 exemplo de 252 níveis, nomenclatura,
133 limites
compactação de cores, 473-476 algoritmo de
de eixos de plotagem de linha
maximização de expectativa, 465-476
para, 228-230
rotulagem, 230-232 cores e estilos de linha, 226-228
GMM como meio de resolver os pontos fracos de,
aplicação de Matplotlib, perfil linha por
linha 224-232 , regressão linear
dados de dígitos simples 477-480 , kernel 470-473
(definido), largura de banda 28 (em aprendizado de máquina), regressão de função de

do kernel 496 definida, base 390 , regularização 392-396 , 396-400

seleção 496 via


validação cruzada, estimativa de densidade Exemplo de previsão de tráfego de bicicletas em Seattle,
400
do kernel 497 (KDE), 491-506
seleção de largura de banda via validação cruzada, simples, listas

497 390-392 , Python, 37-41


atributo loc (Pandas), 110
Classificação generativa bayesiana com, 501-506
incorporação linear local (LLE), 453-455 logaritmos, 55

estimador personalizado, 501-506

histogramas e, 491-496 na prática,


496-506
Matplotlib, 248 Aprendizado de máquina M , 331

522 | Índice
Machine Translated by Google

noções básicas, (veja também máscaras booleanas)

331-342 categorias Matrizes booleanas, 75-78


de, 332 tarefas de classificação, máscaras booleanas,
333-335 agrupamento, 70-78 interface estilo MATLAB, 222
338-339 árvores de decisão e florestas Matplotlib, 217, 329
aleatórias, 421 limites de eixos para gráficos de linha,
definidas, 332 redução de dimensionalidade, 228-230 alteração de padrões via rcParams,
340-342 recursos educacionais, 284 personalização da barra de cores,
514 pipeline de detecção de rosto, 255-262 configurações e folhas de estilo, 282-
506-514 engenharia de recursos, 375-382 290 gráficos de densidade e contorno,
Hiperparâmetros GMM (ver modelos de 241-245 visualização de erros,
mistura gaussiana) e validação de modelo, 237-240 dicas gerais,
359-375 218-222 dados geográficos com kit de ferramentas
KDE (ver estimativa de densidade do kernel) Basemap, 298
regressão linear (ver regressão linear) pegadinhas, 232 histogramas, binnings e densidade,
aprendizado múltiplo (ver aprendizado múltiplo) 245-249
classificação ingênua de Bayes, 382-390 importação, 218
PCA (ver análise de componentes principais) interfaces, 222 rotulagem de linha simples
exemplos qualitativos, 333-342 gráficos, 230-232 cores e estilos de
tarefa de regressão, 335-338 linha, 226-228 interfaces estilo
Scikit-Learn básico, 343 MATLAB, 222 subtramas
supervisionados, múltiplas, 262-268 hierarquia de
332 SVMs (consulte máquinas de vetores objetos de gráficos, 275 interfaces
de suporte) não orientadas a objetos, 223
supervisionados, 332 personalização de gráficos, 282-284
comandos mágicos contextos de exibição de gráficos, 218-220
colagem de bloco de código, personalização da legenda do
11 tempo de execução enredo, 249-255 plotagem a partir de um
de código, 12 comandos de ajuda, 13 script, 219 plotagem do notebook
histórico de entrada/saída IPython, 220 plotagem do shell IPython, 219
IPython, 16 código recursos e documentação
externo em execução, 12 para, 329 salvando
relacionados ao shell, 19 figuras em arquivo,
coletor aprendizado, 445-462 função 221 Seaborn vs., 311-313
"OLÁ", 446 vantagens/desvantagens, 455 estilos de configuração,
aplicação de 218 linha simples gráficos, 224-232
Isomap em dados de faces, 456-460 definido, 446 folhas de estilo, 285-290 texto e anotação, 268-275 visualização de função tridi
agrupamento de médias k (consulte 241-245
agrupamento plotagem tridimensional, personalização de
de médias k) escalonamento multidimensional, 290-298 ticks, função max()
450-452 PCA vs., 455 275-282 , estimador
visualização de estrutura em de margem máxima 59 , uso de memória
dígitos, 408 (veja também máquinas de vetores de suporte
460-462 junções (SVMs)), criação de perfil,
muitos-para-um, chave de
148 projeções de mapas, mesclagem 29 na
300-304 cônicas, 303 cilíndricas, 301 palavra-chave, especificação
perspectivas, 302 pseudocilíndricas, 149 de, 149-152
302 mapas, margens geográficas (ver dados geográficos), maximização,
fusão,407-
146-158
416 mascaramento,
(ver também junções)
114

Índice | 523
Machine Translated by Google

especificação chave, 149-152


álgebra relacional e, 146 Classificação N ingênua de Bayes, 382-390
Exemplo de dados populacionais do estado dos EUA, vantagens/desvantagens, 389
função 154-158 min(), 59
classificação Bayesiana e, 383
Miniconda, xiv Gaussiana, 383-386
dados faltantes, 120-124 multinomial, 386-389
engenharia de recursos e, 381 exemplo de classificação de texto, valor
manuseio, 119-120 386-389 NaN, 104, 116, 122
NaN e None, 123
atalhos de navegação, 8
operando em valores nulos em Pandas, 124-127 redes neurais, 513 filtro de
Faixa de Möbius, modelo ruído, PCA como, 440-442 Nenhum
296-298 (definido), 334
objeto, 121, 123 embeddings
parâmetros de modelo (definidos), 334 não lineares, MDS e, 452 método notnull(), 124
trade-off de viés-
função np.argsort(), 86
variância de seleção de modelo, curvas
função np.concatenate(), 48,
de validação 364-366 no Scikit-Learn, validação de
143 np.sort () função, 86 valores nulos,
modelo 366-370 , viés-variância
124-127 detecção, 124
359-375 trade-off, validação cruzada eliminação, 125
364-366 , exemplo de pesquisa
preenchimento,
de grade 361-370 , 373 126 NumPy, 33
conjuntos de
agregações,
validação, 360 curvas de 58-63 atributos
aprendizado, 370-373 de array, 42 princípios
abordagem ingênua para, 359
básicos de array, 42
curvas de validação, 366-370 módulos, IPython, 6-7 indexação de array:
Projeção de Mollweide, 302 multi- acessando elementos únicos, 43 fatiamento de array:
indexação (ver indexação hierárquica) escala acessando submatrizes, 44 máscaras
multidimensional (MDS), 450-452 básico, 447-450 booleanas, 70-78
incorporação
transmissão, 63-69
localmente linear e 453-455 incorporações não operadores de comparação como ufuncs, 71-73
lineares, 452 computação em arrays, 50-58 tipos
Tipo MultiIndex, 129-131 de dados em Python, 34
métodos de criação, 131-134
datetime64 dtype, 189
agregações de dados ativadas, documentação, 34
140 construtores explícitos para, 132 indexação sofisticada, 78-85
dimensões extras de dados com, 130 para
palavras-chave e/ou vs. operadores &/|, 77
colunas, 133
matrizes de classificação,
configuração/redefinição de índice, 85-92 tipos de dados padrão,
139 indexação e fatiamento, 134-137 41 matrizes estruturadas,
opção de chaves, 92-96 funções universais, 50-58
144 nomes de nível,
133 multiplicação indexada DataFrames,
136 séries indexadas multiplicadas,
Interface orientada a objetos, 223
134 reorganização, 137-140
deslocamentos, séries
índices classificados/não classificados com,
temporais, 196 por
137 índices de empilhamento/
palavra-chave, 149 codificação
desempilhamento, 138 classificação multinomial ingênua de Bayes, 386-389
one-hot, 376 junções um-
para-um, 147 classificação de dígitos
de reconhecimento óptico de caracteres, 357-358

524 | Índice
Machine Translated by Google

GMMs, agrupamento operações de string vetorizadas, 178-188 função


488-491 k-means, 470-473 pandas.eval(), 210-211 dados do painel,
carregamento/visualização de dados de dígitos, 354 141 fatiamento
Matplotlib, 261-262 parcial, 135
PCA como filtragem de ruído, 440-442 particionamento (classificações
PCA para visualização, 437 parciais), 88 colagem de blocos de código, comandos
florestas aleatórias para classificação de mágicos para, 11 função
dígitos, 430-432 pd.concat() capturando repetições
Aplicativo Scikit-Learn, 354-358 visualizando como erro, 144 concatenação com,
estrutura em dígitos, 460-462 ou palavra-chave, 142-146 concatenação com junções,
77 conjunto 145 índices duplicados, 143
ordenado, objeto de índice como, 106 ignorando o índice, 144
projeção ortográfica, 302 chaves MultiIndex, 144
Objetos externos, IPython, 13 função pd.date_range(), 193 função
junção externa, pd.eval(), 210-211 pd.merge()
153 produtos externos, função, 146-158 categorias de junções,
58 outliers, PCA e, 445 saída, 147-149 palavras-chave, 149-152
supressão, 15 overfitting, 371, palavras-chave left_index/
425 right_index, 151-152 especificação de chave de
mesclagem, 149-152 álgebra relacional e,
146 especificando aritmética de
conjunto para junções, 152 pdb (depurador
Gráficos de pares P , 317
Pandas, 97 Python), 22 Perez, Fernando, 1,
217 Tipo de período, 193
agregação e agrupamento, 158-170 e
projeções de
expressões compostas, 209 conjuntos de
perspectiva, 302 pipelines, 366, 381
dados anexados, 146
documentação integrada, 98 tabelas dinâmicas,
170-178 operação
combinação de conjuntos de dados,
141-158 concatenação de conjuntos de groupby() vs., 171 multinível, 172
sintaxe, 171-173
dados, 141-146 indexação e seleção de
dados, 107 seleção de dados em DataFrame, Exemplo de

110 -215 seleção de dados em série, 107-110 passageiros do Titanic, 170 Exemplo de
dados de taxa de natalidade dos EUA,
Objeto DataFrame, 102-105 eval()
agregação e
e query(), 208-209 manipulação de
agrupamento de conjuntos de dados de
dados ausentes, 119-120 indexação
174-178 planetas,
hierárquica, 128-141
gráficos de 159
Objeto de índice, instalação
105-107 , 97 barras, 321 legendas de gráficos
escolhendo elementos para,
mesclando/juntando conjuntos de dados, 146-158
NaN e None in, 123 valores 251 personalização, 249-255 legendas

nulos, 124-127 objetos, múltiplas nos


mesmos
98-107 operando
eixos,
em dados in, 115-127
(veja também funções universais) tamanho de 254 pontos, 252 Plotly, 330 limites de
eixos de plotagem
pandas.eval(), 210-211
Dados do painel, para simples gráficos de linhas, gráficos de
barras 228-230 , 321
141 tabelas dinâmicas,
alterações de padrões via
objeto da série 170-178 ,
série temporal 99-102 , 188-214 rcParams, 284 barras de cores, 255-262 dados em mapas, 307-329 gráficos de dens

Índice | 525
Machine Translated by Google

contextos de exibição, gráficos exemplo de reconhecimento facial, 442-445


de fator 218-220 , para redução de dimensionalidade, exemplo
319 de um shell IPython, 219 de de 436 dígitos manuscritos, 437-440, 440-442
script, 219
histogramas, binnings e densidade, 245-249 notebook aprendizado múltiplo vs., 455
IPython, 220 distribuições significado de componentes, 438-439
conjuntas, 320 rotulagem de filtragem de ruído, 440-442
gráficos de linhas simples, 230-232 cores e pontos fortes/fracos, 445
estilos de linha , 226-228 personalização visualização com, 437 criação
manual, 282-284 Matplotlib, 217 de perfil de
subparcelas scripts completos,
múltiplas, 262-268 de erros, 27 linha por linha,
237-240 gráficos de 28 uso de memória,
pares, 317 29 projeções (ver projeções de mapa)
legendas de gráficos, projeções pseudocilíndricas, 302 considerações
249-255 Seaborn, de
311-313 gráficos de linhas instalação do Python, xiv Python 2.x vs.
simples, 224-232 gráficos de Python 3, xiii razões para usar, xii
dispersão simples , 233-237
folhas de estilo para, 285-290 texto e
anotação para, 268-275
tridimensional, 290-298 função tridimensional,
Método Q query()
241-245 ticks,
Método DataFrame.query(), 213 quando
275-282 função bidimensional, 69
usar, 214 ponto de
várias bibliotecas gráficas Python, 330 Função
interrogação (?), acessando a documentação IPython com, 3
plt.axes(), 263-264 função algoritmo
plt.contour(), 241-244 função
quicksort, 87
plt.GridSpec(), 266-268 função plt.imshow(),
243-244 comando plt.legend(), 249-254
argumentos de cor da função plt.plot(),
Função de base radial R , 412
226 plt.scatter vs., 237
estatísticas de
gráficos de dispersão com,
precipitação, 70
233-235 plt.scatter()
vantagens/desvantagens de florestas
função plt.plot vs., 237 gráficos
aleatórias, 432 dígitos de classificação
de dispersão simples com,
com, 430-432
235-237 plt.subplot()
definidos, 426 conjuntos de estimadores,
função, 264 função plt.subplots(), 265
426-428 motivação com árvores de decisão,
funções de base polinomial, 393
421-426 regressão,
modelo de regressão polinomial,
428 RandomizedPCA, 442
366 método pop(), 111 dados
dicionário rcParams , alterando os padrões via mapa de cores
populacionais, EUA, operações de
284 RdBu, 258 matrizes
mesclagem e junção
de registros, método
com, 154-158 eixos principais, 434-436 análise de
componentes 96 reduz(), regressão 57 ,
428-433 (veja também
principais (PCA), 433-515
formulários específicos, por exemplo: regressão linear
básico, 433-442 escolha do número de componentes, 440
exemplo de
missão) tarefa de
autofaces, 442-445
regressão
definida, 332 aprendizado de máquina, 335-338

526 | Índice
Machine Translated by Google

expressões regulares, construção, 101


regularização 181 , 396-400 indexação/seleção de dados em, 107-110
regularização de laço, 399 DataFrame como dicionário de, 110-112
regressão de crista, 398 Objeto DataFrame construído a partir de, 104
álgebra relacional, 146 método Objeto DataFrame construído a partir de dicionário de, 105
resample(), 197-199 método matriz NumPy
reset_index(), 139 remodelagem, 47 generalizada, 99 indexação hierárquica
regressão de crista em, 128-141 alinhamento de índice em, 116
(regularização L2), 398 junção à direita, 153 palavra- atributos de indexador, 109
chave right_index, multiplicação indexada, 134

151-152 estatísticas rolantes, 201 matriz unidimensional, 108


configuração de tempo de operações entre DataFrame e, 118
execução (rc), 284 shell, IPython básico, 16 comandos de linha de comando,
18 comandos,
16-19 atalhos
de teclado, 8 inicialização, 2 comandos
Gráficos de dispersão S (ver gráficos de dispersão simples)
mágicos, 19 passagem
Pacote Scikit-Learn, 331, 343-346 API (consulte
de valores de e para, 18 funções
Estimator API) noções básicas,
343-359 dados como shift(), 199-201

tabela, 343 representação atalhos

de dados em, 343-346 Estimator API,


346-354 matriz de recursos,
aplicativo de 344 dígitos
acessando a saída anterior, 15 históricos
manuscritos, 354-358 classificador de vetor de suporte,
de comandos, 9 shell
matriz de destino 408-411 , submódulo
IPython, 8-31 navegação,
scipy.special 344-345 , 56
8 entradas de
plotagem de script de, 219 perfis, 27
texto, 9
Seaborn
histogramas simples, 245-246 limites
de eixos de gráficos
de linha simples para, 228-230

rotulagem, 230-232
gráficos de barras,
cores e estilos de linha, 226- 228
321 conjuntos de dados e tipos de gráficos,
Matplotlib, 224-232 simples
313-329 histogramas facetados,
(Matplotlib), 224-232 regressão linear
318 gráficos de fatores,
simples, 390-392 gráficos de dispersão simples
319 histogramas, KDE e densidades, 314-317 distribuições
Populações de cidades da
conjuntas, exemplo de 320
Califórnia, 249-254 Matplotlib, 233-237 plt.plot,
tempos de finalização de maratona, 322-329 Matplotlib vs.,
233-235 plt.plot vs.
par 311-313 gráficos, folha de
dispersão, 237 plt.
estilo 317 ,
dispersão, 235-237
visualização 289
com, 311-313 Seattle, previsão de
operação slice(), 183
tráfego de bicicletas em regressão linear, série
fatiamento
temporal 400-405 , 202-209
MultiIndex com índices classificados/não classificados,
137
Seattle, estatísticas de precipitação em,
Matrizes NumPy, 44-47
70 aprendizagem semissupervisionada, 333
Matrizes NumPy: acessando submatrizes, 44
Objeto de série (Pandas), 99-102 como
dicionário, 100, 107

Índice | 527
Machine Translated by Google

Matrizes NumPy: submatrizes multidimensionais, ajuste, 408-411


45 núcleos e, 411-414
Matrizes NumPy: submatrizes unidimensionais, maximização da margem, 407-416
44 motivação, 405-420
NumPy vs. Python, 46 detector de face simples, 507
convenções Pandas, 114 margens de suavização, 414-416
matrizes de classificação, gráficos de superfície, tridimensionais, 293-298
85-92 ao longo de linhas ou
colunas, 87
princípios básicos, 85 classificação rápida com
Incorporação de vizinho estocástico distribuído t (t-SNE),
np.sort e np.argsort, exemplo de 86 k conclusão de guia
vizinhos mais
456, 472
próximos, 88-92
explorando módulos IPython com, 6-7 de
particionamento, 88
conteúdo de objeto, 6 ao
fonte código, acesso, 5 matrizes de divisão, 49 operações de string (ver operação de string vetorizada
importar, 7 tabela,
tions) dados como, matriz
matrizes estruturadas, 92-96
de destino 343 , frequência
tipos compostos avançados, 95
de termo 344-345- frequência inversa do documento
criação, 94 (TF-IDF), 378
matrizes de registro, texto, 377
96 folhas de
(ver também anotação de gráficos)
estilo Métodos bayesianos para hackers,
transformações e posição de, 270-272
288 estilo padrão,
atalhos de entrada de
286 estilo FiveThirtyEight, 287
texto, 9 gráficos de contorno de
ggplot, 287
plotagem tridimensional,
Matplotlib, 285-290
292 visualização de faixa de Möbius,
Seaborn, 289
296-298 pontos e linhas,
submatrizes
291 gráficos de superfície,
como não- visualizações
293-298 triangulações de superfície,
de cópia, 46 criação 295-298 wireframes,
de cópias, 46 fatiamento
293 com Matplotlib,
multidimensional, 45 fatiamento personalização de
290-298 ticks (marcas de
unidimensional, 44 subtramas customização
escala), 275-282 formatos
manual, 263-264
sofisticados, 279-281 opções de
múltiplos, 262-268 plt.axes()
formatador/localizador, 281
para, 263-264 plt.GridSpec()
principais e secundários, 276 número de
para, 266-268 plt.subplot()
redução/aumento de, 278
para, 264 plt.subplots() regularização
para, 265 subconjuntos, histogramas
de Tikhonov,
facetados, 318 palavras- 398 gráficos de barras de séries
chave de sufixos, 153 temporais, 321
aprendizagem supervisionada,
datas e horas em Pandas,
332 tarefa de classificação,
191 datetime64, 189 códigos de
333-335 tarefa de regressão,
frequência, 195 dados de indexação por
335-338 vetor de suporte (definido), 409 carimbos de
suporte classificador de vetor, 408-411 data/hora, 192 datas
máquinas de vetores de suporte e horas nativas de Python, 189
(SVMs), 405 vantagens/desvantagens, 420 exemplo de reconhecimento facial, 416-420
deslocamentos, 196 Pandas, 188-209 Estruturas de dados Pandas para, 192-19

528 | Índice
Machine Translated by Google

Python vs. Pandas, 188-192 ufuncs especializados, 56


reamostragem e conversão de frequências, 197-199 especificação de saída, 56
funções trigonométricas, 54 método
estatísticas contínuas, 201 unstack(), 130 agrupamento de

Exemplo de contagem de bicicletas em Seattle, turnos aprendizagem não


de tempo 202-209 , matrizes supervisionado, 338-339, 353
digitadas 199-201 , 189 definido, 332

Tipo timedelta, 193 redução de dimensionalidade, 261, 340-342, 352, 355


Tipo de carimbo de data e
hora, 193 carimbos de data e hora, indexação PCA (ver análise de componentes principais)
de dados por, 192 tempo, de código,
12, 25-27 método transform(), 167
transformações
Curvas de validação de validação V (ver
modificação, 270-272 validação do modelo), 366-370
posição do texto e, 270-272 gráficos variáveis
de superfície triangular, 295-298 funções
digitação dinâmica, 34
trigonométricas, 54 função tshift(),
passagens de e para shell, 18 variância,
199-201 validação cruzada dupla,
compensação de polarização-variância, 364-366 operações
361
vetorizadas, 63 operações de string
vetorizadas, 178-188 noções básicas, 178 variáveis
U de indicador,
ufuncs (ver funções universais) ufuncs 183 métodos semelhantes aos

unários, 52 underfitting, métodos de string Python,


364, 371 atalho de sublinhado 180

(_), 15 funções universais (ufuncs), métodos usando expressões regulares, 181 exemplo
50-58 valor absoluto, 54 recursos avançados, 56 de banco de dados de receitas, 184-188
agregados, 57 aritmética tabelas de, 180-184
de array, 52 básicos, 51 acesso e fatiamento de itens vetorizados, 183
operadores de Vega/Vega-Lite, enredo de
comparação como, 71-73 violino 330 , mapa
exponenciais, de cores de 327 viridis, 258
55 alinhamento de índice, 116-118 Vispy, software
preservação de índice, de visualização 330 (ver Matplotlib) (ver Seaÿ
115 logaritmos, 55 operando em nascer)

dados em Pandas, 115-127


operações entre EM
DataFrame e Series,
Wickham, Hadley,
correspondência de 161
118
curingas, gráfico de 7
produtos externos, 58 wireframes, 293 contagens de palavras, 377-378
lentidão de loops Python, 50

Índice | 529
Machine Translated by Google

Sobre o autor
Jake VanderPlas é um usuário e desenvolvedor de longa data da pilha científica Python. Atualmente,
ele trabalha como diretor de pesquisa interdisciplinar na Universidade de Washington, conduz sua própria
pesquisa astronômica e passa seu tempo aconselhando e consultando cientistas locais de diversas áreas.

Colofão
O animal na capa do Python Data Science Handbook é um lagarto mexicano (Heloderma horridum), um
réptil encontrado no México e em partes da Guatemala. Ele e o monstro Gila (um parente próximo) são
os únicos lagartos venenosos do mundo. No entanto, este animal se alimenta principalmente de ovos,
por isso o veneno é usado como mecanismo de defesa.
Quando se sente ameaçado, o lagarto morde – e como não consegue libertar uma grande quantidade
de veneno de uma só vez, aperta firmemente as mandíbulas e usa um movimento de mastigação para
mover a toxina mais profundamente na ferida. Esta mordida e os efeitos posteriores do veneno são
extremamente dolorosos, embora raramente fatais para os humanos.

A palavra grega heloderma se traduz como “pele cravejada”, referindo-se à textura distinta da pele do
réptil. Essas saliências são osteodermas, cada uma contendo um pequeno pedaço de osso e servindo
como armadura protetora. O lagarto mexicano é preto com manchas e faixas amarelas. Possui cabeça
larga e cauda grossa que armazena gordura para ajudar o animal a sobreviver durante os meses quentes
de verão, quando está inativo. Em média, esses lagartos têm de 22 a 36 polegadas de comprimento e
pesam cerca de 1,8 quilo.

Tal como acontece com a maioria das cobras e lagartos, a língua do lagarto mexicano é o seu principal
órgão sensorial. Ele irá agitá-lo repetidamente para coletar partículas de cheiro do ambiente e detectar
uma presa (ou, durante a época de acasalamento, um parceiro em potencial). Quando a língua bifurcada
é retraída para dentro da boca, ela toca o órgão de Jacobson, um conjunto de células sensoriais que
identificam vários produtos químicos e feromônios.

O veneno do lagarto contém enzimas que foram sintetizadas para ajudar a tratar o diabetes, e mais
pesquisas farmacológicas estão em andamento. Está ameaçado pela perda de habitat, pela caça furtiva
para o comércio de animais de estimação e pela morte por moradores locais que simplesmente têm
medo dele. Este animal é protegido pela legislação dos dois países onde vive.

Muitos dos animais nas capas da O'Reilly estão ameaçados de extinção; todos eles são importantes
para o mundo. Para saber mais sobre como você pode ajudar, acesse pets.oreilly.com.

A imagem da capa é do Wood's Animate Creation. As fontes da capa são URW Typewriter e Guardian
Sans. A fonte do texto é Adobe Minion Pro; a fonte do título é Adobe Myriad Condensed; e a fonte do
código é Ubuntu Mono da Dalton Maag.

Você também pode gostar