Análise de cluster – Como ordenar agrupamentos

No post de análise de cluster, foram utilizados algoritmos de agrupamento para classificar dados. No entanto, os números de cluster atribuídos não têm uma ordem. Na verdade, são números apenas por conveniência – poderiam ser letras também. Quando fizer mais de uma rodada ou for comparar resultados de diferentes séries, isso acaba sendo um grande problema. Se você deseja impor uma ordem ou nomes específicos a eles, você pode rotulá-los novamente como quiser, já que isso não é função do algoritmo de agrupamento. Por exemplo, você pode classificar os centros pela coordenada X e remarcá-los.

Como o início da localização dos grupos é randômica, a combinação “cor x número do grupo” pode variar a cada rodada no gráfico. Um primeiro passo pode ser o de fixar a semente inicial através do parâmetro “random_state=0”. No entanto, se quiser que os rótulos (‘labels’) de cada grupo permaneçam em uma certa sequência, isso não garante uma correlação correta entre rótulo dado pelo algoritmo e o que você deseja.

No exemplo a seguir, é criado um vetor com as classes desejadas, que são números de 1 a 20 (‘day_classes’). Também é criado um vetor com os números dos clusters calculados pelo algoritmo, que são de 0 a 19 (‘cluster_numbers’) e calculado outro vetor com as médias da variável ‘qs’ para cada agrupamento (‘mean_classes’), posteriormente unidos em um dicionário. Cada item desse dicionário é composto por chave (número do agrupamento) e valor (média de ‘qs’ do agrupamento). Posteriormente, ele é ordenado pelo valor de ‘qs’ e extraída uma lista somente com as chaves (‘before’). O vetor ‘after’ será o ordenamento final, formado pelo vetor de classes desejadas.

Para renomear as classes originais dos agrupamentos (‘before’) para a nova sequência desejada (‘after’) diretamente na coluna de rótulos do dataframe original (df[‘label’]), deve ser criada uma máscara indicando a posição de cada número (‘mdk’). Em seguida, essa máscara é aplicada na coluna com os rótulos originais. Pronto, a dataframe está com os rótulo redefinidos – nesse caso, seguindo uma ordem de 1 a 20 conforme o valor de uma das variáveis.

O método definido a seguir recebe a dataframe contendo os dados a serem agrupados e uma lista com o nome das colunas a serem utilizadas (duas ou três variáveis). São fixados 20 agrupamentos, cujas variáveis são selecionadas da dataframe e servem de entrada para o método de cálculo do k-means. Os rótulos são guardados em uma coluna da dataframe, que é renomeada conforme já foi descrito. Por fim, são feitos gráficos das variáveis, com opções 2D e 3D (as cores indicam o número de cada classe).

from sklearn.cluster import k_means
from matplotlib import pyplot as plt
from mpl_toolkits import mplot3d

def kmeans(df, var_lst):
	n_clusters = 20
	# Create numpy.ndarray selecting columns
	data = df.loc[:, var_lst].values

	centroids, labels, sse = k_means(data, n_clusters=n_clusters, random_state=0, n_init=100)
	df['label'] = labels

	## Sort Clusters ##

	# Calculate QS mean from every class
	day_classes = list(range(1, n_clusters+1))
	cluster_numbers = list(range(0, n_clusters))
	mean_classes = [0] * n_clusters
	for x in range(n_clusters):
		selection = df[df['label'] == x]
		mean_classes[x] = selection['qs'].mean()
	clusters_info = dict(zip(cluster_numbers, mean_classes))

	# Sort dictionary by value
	clusters_sorted = {k: v for k, v in sorted(clusters_info.items(), key=lambda item: item[1])}

	# Create lists from key values
	before = list(clusters_sorted.keys())
	after = day_classes
		
	# Relabel classes numbers according to QS values
	mdk = [df['label'] == i for i in before]
	for l in range(len(after)):
		#df['label'][mdk[l]] = after[l] #SettingWithCopyWarning
		df.loc[mdk[l], 'label'] = after[l]

	###################

	# 2D plot
	plt.scatter(df['qs'], df['label'], c=df['label'], cmap='jet')
	plt.title('Classes numbers according QS values')
	plt.xlabel('QS')
	plt.ylabel('Day Class')
	plt.ylim(0, 20)
	plt.yticks(np.arange(0, 20, 2))
	plt.show()
		
	# 3D Plot
	fig = plt.figure()
	ax = plt.axes(projection="3d")
	ax.scatter3D(df[var_lst[0]], df[var_lst[0]], df[var_lst[0]], c=df['label'], cmap='jet')
	ax.set_xlabel(var_lst[0].upper())
	ax.set_ylabel(var_lst[1].upper())
	ax.set_zlabel(var_lst[2].upper())
	plt.show()

Veja como agora os valores médios de QS ordenados definem os números das classes calculadas pelo algoritmo k-means (antes e depois):

Agrupamentos numerados aleatoriamente, de 0 a 19
Agrupamentos numerados aleatoriamente, de 0 a 19
Agrupamentos reordenados conforme valores médios de QS, de 1 a 20
Agrupamentos reordenados conforme valores médios de QS, de 1 a 20

Uma forma alternativa de realizar essa reordenação pode ser vista no Stackoverflow – How to set k-Means clustering labels from highest to lowest with Python?

One comment

Leave a Reply

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.