Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

Clusterização com MeanShift e DBSCAN. Só consegui obter 1 cluster. O que está errado?

Estou usando o dataset dígitos do sklearn para clustering. No KMeans, defino o número de clusters com antecedência, mas não é verdade para o DBSCAN e o MeanShift. São 10 dígitos mas só consegui 1 cluster...

#!/usr/bin/env python
# coding: utf-8

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
#%matplotib inline
from sklearn.cluster import DBSCAN,MeanShift
from sklearn.datasets import load_digits
from sklearn.preprocessing import StandardScaler
from sklearn import metrics
from sklearn.decomposition import PCA
from time import time


digits = load_digits()
digits

digits.data.shape
X = digits.data
y = digits.target


fig, axes = plt.subplots(2,5, subplot_kw=dict(xticks=[], yticks=[]))
for ax, digit in zip(axes.flat, digits.data[:10]):
    ax.imshow(digit.reshape(8,8), cmap="gray")


pca = PCA(n_components=2)
pca = pca.fit(digits.data)
digits_pca = pca.transform(digits.data)


t0=time()
# print len(digits.data) #1797
colors = ["#476A2A","#7851B8",'#BD3430','#4A2D4E','#875525',
          '#A83683','#4E655E','#853541','#3A3120','#535D8E']


plt.figure(figsize=(10,10))
plt.xlim(digits_pca[:,0].min(), digits_pca[:,0].max())
plt.ylim(digits_pca[:,1].min(), digits_pca[:,1].max())

for i in range(len(digits.data)):
    plt.text(digits_pca[i,0], digits_pca[i,1], str(digits.target[i]),
             color = colors[digits.target[i]],
             fontdict={'weight':'bold', 'size':9})
plt.title('PCA')
plt.xlabel("first PC")
plt.ylabel("second PC")
print("PCA time: ", time()-t0)
plt.show()



#feature scaling
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler = scaler.fit(digits_pca)
scaled_p = scaler.transform(digits_pca)


# # DBSCAN
X, labels_true = load_digits(return_X_y=True) 
X = StandardScaler().fit_transform(X)

#Next, we can extract our cluster labels and outliers to plot our results.

labels = db.labels_
core_samples_mask = np.zeros_like(labels, dtype = bool)
core_samples_mask[db.core_sample_indices_] = True


# # Compute DBSCAN
t2 = time()
db = DBSCAN(eps=0.8, min_samples=50).fit(scaled_p)  ## default parameter values You will construct a DBSCAN object that requires a minimum of 15 data points in a neighborhood of radius 0.5 to be considered a core point.


labels = db.labels_
n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)
print( "number of clusters in pca-DBSCAN: ", n_clusters_)


plt.scatter(scaled_p[:,0], scaled_p[:,1], c=labels, s=60, edgecolors='black')
plt.title('PCA -> DBSCAN')
plt.xlabel("first PC")
plt.ylabel("second PC")
print( "DBSCAN time: ", time()-t2)
plt.show()


# # MeanShift

db = MeanShift().fit(scaled_p)  ## default parameter values You will construct a DBSCAN object that requires a minimum of 15 data points in a neighborhood of radius 0.5 to be considered a core point.


labels = db.labels_
n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)


print( "number of clusters in pca-MeanShift: ", n_clusters_)


plt.scatter(scaled_p[:,0], scaled_p[:,1], c=labels, s=60, edgecolors='black')
plt.title('PCA -> MeanShift')
plt.xlabel("first PC")
plt.ylabel("second PC")

plt.show()
1 resposta
solução!

Oii Edson, tudo certinho por aí?

Primeiramente, desculpa pela demora em te dar uma resposta aqui, mas vamos lá! Diferente do KMeans, que nós definimos o número de clusters que queremos, o DBSCAN faz as cluters com base nos parâmetros que definimos, então precisamos ajustar esses parâmetros pra que não vire uma única cluster ou também apenas ruídos. Temos os parâmetros eps, min_samples e metric, que nos auxiliam muito para que o modelo consiga fazer clusters da maneira mais adequada, vou explicar um pouco de como cada um deles funciona, mesmo vendo que você já estava usando o eps e o min_samples.

• O eps siginifica distância mínima entre os pontos para que sejam considerados vizinhos. Se for usado um valor muito pequeno, o DBSCAN considera tudo como ruído (-1) e quando usamos um valor muito alto para o eps, o DBSCAN considera tudo como apenas uma cluster (0).

• O parâmetro min_samples significa a quantidade mínima de amostras que cada cluster precisa ter, ou seja, se for colocado o valor 1, cada ponto por si só vai ser considerado um cluster, o que não é inteligente, e se for um número muito grande eles vão ser considerados ruídos também, já que o valor mínimo para que seja uma cluster excede o número de dados que temos.

• Por fim, o metric é a métrica usada para definir como serão feitas as distâncias, por exemplo se é cosseno, linha reta, etc. No scikit-learn nós temos as métricas: ‘cityblock’, ‘cosine’, ‘euclidean’, ‘l1’, ‘l2’, ‘manhattan’, você pode colocar como metric = manhattan por exemplo, a fim de testar como seu DBSCAN reagiria.

Já no MeanShift não é necessário passar nenhum parâmetro, mas podemos passar uma largura de banda pra ajudar nessa organização dos clusters. Para definir essa largura de banda, nós definimos no código um valor de quantile, quanto maior o valor do quantile, maior o valor da largura de banda e menos clusters vamos ter e se o quantile for menor, a largura de banda diminui e o número de clusters aumenta. Para fazer essa largura de banda, primeiro importamos o estimador de largura de banda, e depois definimos essa largura, dessa forma aqui:

from sklearn.cluster import estimate_bandwidth

BW = estimate_bandwidth(df, quantile=0.3)
agrupador = MeanShift(BW)
agrupador.fit(df)
agrupador.labels_

Espero que eu tenha deixado claro pra ti mudanças que podem ser feitas para que o seu número de clusters mudem, qualquer outra dúvida é só me chamar!

Bons estudos ^^