Achei que ficaria melhor visualmente representando com o seguinte código:
silhouette_values = []
for quantile in np.linspace(0.02, 0.5, 30):
bw = estimate_bandwidth(X=norm_df, quantile=quantile)
agg = MeanShift(bandwidth=bw).fit(norm_df)
try:
score = silhouette_score(norm_df, agg.predict(norm_df))
silhouette_values.append([score, quantile])
except ValueError:
silhouette_values.append([0, quantile])
silhouette_values_df = pd.DataFrame(silhouette_values, columns=['score','quantile'])
fig = go.Figure()
fig.add_trace(go.Scatter(x = silhouette_values_df['quantile'],
y = silhouette_values_df['score'])
)
fig.update_layout(dict(title = 'Silhouette values',
xaxis_title = 'Quantile',
yaxis_title='Silhouette score')
)
fig.show()
Desse modo não precisa usar o if pois o try irá capturar o erro e ainda podemos escolher um valor arbitrário para o score de modo que visualize quando os quartis começam a gerar apenas 1 cluster.
Obs: eu utilizei os dados normalizados, não entendi por qual motivo o instrutor usou os dados originais uma vez que há o problema da escala.