Guia definitivo para cluster hierárquico com Python e Scikit-Learn PlatoBlockchain Data Intelligence. Pesquisa Vertical. Ai.

Guia definitivo para cluster hierárquico com Python e Scikit-Learn

Introdução

Neste guia, vamos nos concentrar na implementação do Algoritmo de agrupamento hierárquico com Scikit-Learn para resolver um problema de marketing.

Depois de ler o guia, você entenderá:

  • Quando aplicar o agrupamento hierárquico
  • Como visualizar o conjunto de dados para entender se ele é adequado para clustering
  • Como pré-processar recursos e projetar novos recursos com base no conjunto de dados
  • Como reduzir a dimensionalidade do conjunto de dados usando o PCA
  • Como usar e ler um dendrograma para separar grupos
  • Quais são os diferentes métodos de vinculação e métricas de distância aplicadas a dendrogramas e algoritmos de agrupamento
  • Quais são as estratégias de agrupamento aglomerativo e divisivo e como elas funcionam
  • Como implementar o cluster hierárquico aglomerativo com o Scikit-Learn
  • Quais são os problemas mais frequentes ao lidar com algoritmos de agrupamento e como resolvê-los

Observação: Você pode baixar o notebook contendo todo o código neste guia SUA PARTICIPAÇÃO FAZ A DIFERENÇA.

Motivação

Imagine um cenário em que você faz parte de uma equipe de ciência de dados que interage com o departamento de marketing. O marketing vem coletando dados de compras dos clientes há algum tempo, e eles querem entender, com base nos dados coletados, se há semelhanças entre clientes. Essas semelhanças dividem os clientes em grupos e ter grupos de clientes ajuda no direcionamento de campanhas, promoções, conversões e na construção de melhores relacionamentos com os clientes.

Existe uma maneira de ajudar a determinar quais clientes são semelhantes? Quantos deles pertencem ao mesmo grupo? E quantos grupos diferentes existem?

Uma maneira de responder a essas perguntas é usando um agrupamento algoritmos, como K-Means, DBSCAN, Hierarchical Clustering, etc. Em termos gerais, os algoritmos de clustering encontram semelhanças entre os pontos de dados e os agrupam.

Nesse caso, nossos dados de marketing são bastante pequenos. Temos informações de apenas 200 clientes. Considerando a equipe de marketing, é importante que possamos explicar claramente a eles como as decisões foram tomadas com base no número de clusters, explicando assim como o algoritmo realmente funciona.

Como nossos dados são pequenos e a explicabilidade é um fator importante, podemos aproveitar Agrupamento hierárquico para resolver este problema. Esse processo também é conhecido como Análise de agrupamento hierárquico (HCA).

Uma das vantagens do HCA é que ele é interpretável e funciona bem em pequenos conjuntos de dados.

Outra coisa a se levar em consideração nesse cenário é que o HCA é um não supervisionado algoritmo. Ao agrupar os dados, não teremos como verificar se estamos identificando corretamente que um usuário pertence a um grupo específico (não conhecemos os grupos). Não há rótulos para compararmos nossos resultados. Se identificarmos os grupos corretamente, isso será posteriormente confirmado pelo departamento de marketing no dia a dia (conforme medido por métricas como ROI, taxas de conversão etc.).

Agora que entendemos o problema que estamos tentando resolver e como resolvê-lo, podemos começar a dar uma olhada em nossos dados!

Breve Análise Exploratória de Dados

Observação: Você pode baixar o conjunto de dados usado neste guia SUA PARTICIPAÇÃO FAZ A DIFERENÇA.

Após baixar o conjunto de dados, observe que é um CSV (valores separados por vírgula) arquivo chamado shopping-data.csv. Para facilitar a exploração e manipulação dos dados, vamos carregá-los em um DataFrame usando Pandas:

import pandas as pd


path_to_file = 'home/projects/datasets/shopping-data.csv'
customer_data = pd.read_csv(path_to_file)

Marketing disse que coletou 200 registros de clientes. Podemos verificar se os dados baixados estão completos com 200 linhas usando o shape atributo. Ele nos dirá quantas linhas e colunas temos, respectivamente:

customer_data.shape

Isto resulta em:

(200, 5)

Excelente! Nossos dados estão completos com 200 linhas (registros do cliente) e também temos 5 colunas (recursos). Para ver quais características o departamento de marketing coletou dos clientes, podemos ver os nomes das colunas com o columns atributo. Para isso, execute:

customer_data.columns

O script acima retorna:

Index(['CustomerID', 'Genre', 'Age', 'Annual Income (k$)',
       'Spending Score (1-100)'],
      dtype='object')

Aqui, vemos que o marketing gerou uma CustomerID, reuniu o Genre, Age, Annual Income (em milhares de dólares) e um Spending Score indo de 1 a 100 para cada um dos 200 clientes. Quando solicitados a esclarecimentos, disseram que os valores no Spending Score coluna significa com que frequência uma pessoa gasta dinheiro em um shopping em uma escala de 1 a 100. Em outras palavras, se um cliente tem uma pontuação de 0, essa pessoa nunca gasta dinheiro, e se a pontuação for 100, acabamos de identificar o maior gastador.

Vamos dar uma olhada rápida na distribuição dessa pontuação para inspecionar os hábitos de consumo dos usuários em nosso conjunto de dados. É aí que os pandas hist() método vem para ajudar:

customer_data['Spending Score (1-100)'].hist()

img

Observando o histograma, vemos que mais de 35 clientes têm pontuações entre 40 e 60, então menos de 25 têm pontuações entre 70 e 80. Assim, a maioria dos nossos clientes são gastadores equilibrados, seguido por gastos moderados a altos. Também podemos ver que há uma linha após 0, à esquerda da distribuição, e outra linha antes de 100, à direita da distribuição. Esses espaços em branco provavelmente significam que a distribuição não contém não gastadores, o que teria uma pontuação de 0, e que também não há grandes gastadores com pontuação de 100.

Para verificar se isso é verdade, podemos observar os valores mínimo e máximo da distribuição. Esses valores podem ser facilmente encontrados como parte da estatística descritiva, para que possamos usar o describe() método para entender outras distribuições de valores numéricos:


customer_data.describe().transpose()

Isso nos dará uma tabela de onde podemos ler distribuições de outros valores do nosso conjunto de dados:

 						count 	mean 	std 		min 	25% 	50% 	75% 	max
CustomerID 				200.0 	100.50 	57.879185 	1.0 	50.75 	100.5 	150.25 	200.0
Age 					200.0 	38.85 	13.969007 	18.0 	28.75 	36.0 	49.00 	70.0
Annual Income (k$) 		200.0 	60.56 	26.264721 	15.0 	41.50 	61.5 	78.00 	137.0
Spending Score (1-100) 	200.0 	50.20 	25.823522 	1.0 	34.75 	50.0 	73.00 	99.0

Nossa hipótese está confirmada. o min valor do Spending Score is 1 e o máximo é 99. Então não temos 0 or 100 gastadores de pontuação. Vamos então dar uma olhada nas outras colunas da transposta describe tabela. Ao olhar para o mean e std colunas, podemos ver que para Age que o mean is 38.85 e os votos de std é de aproximadamente 13.97. O mesmo acontece para Annual Income, Com um mean of 60.56 e std 26.26, E para Spending Score com uma mean of 50 e std of 25.82. Para todos os recursos, o mean está longe do desvio padrão, o que indica nossos dados têm alta variabilidade.

Para entender melhor como nossos dados variam, vamos traçar o gráfico Annual Income distribuição:

customer_data['Annual Income (k$)'].hist()

O que nos dará:

img

Observe no histograma que a maioria dos nossos dados, mais de 35 clientes, está concentrada próximo ao número 60, no nosso mean, no eixo horizontal. Mas o que acontece à medida que avançamos em direção aos extremos da distribuição? Ao ir para a esquerda, a partir da média de US$ 60.560, o próximo valor que encontraremos é de US$ 34.300 – a média (US$ 60.560) menos a variação padrão (US$ 26.260). Se formos mais para a esquerda de nossa distribuição de dados, uma regra semelhante se aplica, subtraímos a variação padrão (US$ 26.260) do valor atual (US$ 34.300). Portanto, encontraremos um valor de US$ 8.040. Observe como nossos dados passaram de US$ 60 mil para US$ 8 mil rapidamente. Ele está “saltando” US$ 26.260 a cada vez – variando muito, e é por isso que temos uma variabilidade tão alta.

img

A variabilidade e o tamanho dos dados são importantes na análise de agrupamento porque as medidas de distância da maioria dos algoritmos de agrupamento são sensíveis às magnitudes dos dados. A diferença de tamanho pode alterar os resultados do agrupamento fazendo com que um ponto pareça mais próximo ou mais distante de outro do que realmente é, distorcendo o agrupamento real de dados.

Até agora, vimos a forma de nossos dados, algumas de suas distribuições e estatísticas descritivas. Com o Pandas, também podemos listar nossos tipos de dados e ver se todas as nossas 200 linhas estão preenchidas ou têm alguns null valores:

customer_data.info()

Isto resulta em:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 200 entries, 0 to 199
Data columns (total 5 columns):
 #   Column                  Non-Null Count  Dtype 
---  ------                  --------------  ----- 
 0   CustomerID              200 non-null    int64 
 1   Genre                   200 non-null    object
 2   Age                     200 non-null    int64 
 3   Annual Income (k$)      200 non-null    int64 
 4   Spending Score (1-100)  200 non-null    int64 
dtypes: int64(4), object(1)
memory usage: 7.9+ KB

Aqui vemos que não há null valores nos dados e que temos apenas uma coluna categórica – Genre. Nesta etapa, é importante ter em mente quais recursos parecem interessantes para serem adicionados ao modelo de clustering. Se quisermos adicionar a coluna Gênero ao nosso modelo, precisaremos transformar seus valores de categórico para numérico.

Vamos ver como Genre é preenchido dando uma olhada rápida nos primeiros 5 valores de nossos dados:

customer_data.head() 

Isto resulta em:

    CustomerID 	Genre 	Age 	Annual Income (k$) 	Spending Score (1-100)
0 	1 			Male 	19 		15 					39
1 	2 			Male 	21 		15 					81
2 	3 			Female 	20 		16 					6
3 	4 			Female 	23 		16 					77
4 	5 			Female 	31 		17 					40

Parece que só tem Female e Male categorias. Podemos ter certeza disso examinando seus valores únicos com unique:

customer_data['Genre'].unique()

Isso confirma nossa suposição:

array(['Male', 'Female'], dtype=object)

Até agora, sabemos que temos apenas dois gêneros, se planejamos usar esse recurso em nosso modelo, Male poderia ser transformado em 0 e Female para 1. Também é importante verificar a proporção entre os gêneros, para ver se eles estão equilibrados. Podemos fazer isso com o value_counts() método e seu argumento normalize=True para mostrar a porcentagem entre Male e Female:

customer_data['Genre'].value_counts(normalize=True)

Isso resulta em:

Female    0.56
Male      0.44
Name: Genre, dtype: float64

Temos 56% de mulheres no conjunto de dados e 44% de homens. A diferença entre eles é de apenas 16%, e nossos dados não são 50/50, mas são equilibrado o suficiente para não causar problemas. Se os resultados fossem 70/30, 60/40, talvez fosse necessário coletar mais dados ou empregar algum tipo de técnica de aumento de dados para tornar essa proporção mais equilibrada.

Até agora, todos os recursos, exceto Age, foram brevemente explorados. No que diz respeito Age, geralmente é interessante dividi-lo em bins para poder segmentar os clientes com base em suas faixas etárias. Se fizermos isso, precisaríamos transformar as categorias de idade em um número antes de adicioná-las ao nosso modelo. Dessa forma, ao invés de usar a categoria 15-20 anos, contaríamos quantos clientes existem no 15-20 categoria, e isso seria um número em uma nova coluna chamada 15-20.

Conselho: Neste guia, apresentamos apenas uma breve análise exploratória de dados. Mas você pode ir mais longe e deve ir mais longe. Você pode ver se há diferenças de renda e diferenças de pontuação com base no gênero e na idade. Isso não apenas enriquece a análise, mas leva a melhores resultados do modelo. Para se aprofundar na Análise Exploratória de Dados, confira o capítulo EDA no “Previsão de preço de casa prática – Aprendizado de máquina em Python" Projeto Orientado.

Depois de conjecturar sobre o que poderia ser feito tanto com o categórico – ou o categórico ser – Genre e Age colunas, vamos aplicar o que foi discutido.

Codificação de Variáveis ​​e Engenharia de Recursos

Vamos começar dividindo o Age em grupos que variam em 10, de modo que temos 20-30, 30-40, 40-50 e assim por diante. Como nosso cliente mais jovem tem 15 anos, podemos começar aos 15 e terminar aos 70, que é a idade do cliente mais velho nos dados. Começando em 15 e terminando em 70, teríamos intervalos de 15-20, 20-30, 30-40, 40-50, 50-60 e 60-70.

Para agrupar ou caixa Age valores nesses intervalos, podemos usar o Pandas cut() método para cortá-los em compartimentos e, em seguida, atribuir os compartimentos a um novo Age Groups coluna:

intervals = [15, 20, 30, 40, 50, 60, 70]
col = customer_data['Age']
customer_data['Age Groups'] = pd.cut(x=col, bins=intervals)


customer_data['Age Groups'] 

Isto resulta em:

0      (15, 20]
1      (20, 30]
2      (15, 20]
3      (20, 30]
4      (30, 40]
         ...   
195    (30, 40]
196    (40, 50]
197    (30, 40]
198    (30, 40]
199    (20, 30]
Name: Age Groups, Length: 200, dtype: category
Categories (6, interval[int64, right]): [(15, 20] < (20, 30] < (30, 40] < (40, 50] < (50, 60] < (60, 70]]

Observe que, ao observar os valores da coluna, também há uma linha que especifica que temos 6 categorias e exibe todos os intervalos de dados agrupados. Desta forma, categorizamos nossos dados numéricos anteriores e criamos um novo Age Groups recurso.

E quantos clientes temos em cada categoria? Podemos saber rapidamente que agrupando a coluna e contando os valores com groupby() e count():

customer_data.groupby('Age Groups')['Age Groups'].count()

Isto resulta em:

Age Groups
(15, 20]    17
(20, 30]    45
(30, 40]    60
(40, 50]    38
(50, 60]    23
(60, 70]    17
Name: Age Groups, dtype: int64

É fácil perceber que a maioria dos clientes tem entre 30 e 40 anos, seguido por clientes entre 20 e 30 e depois clientes entre 40 e 50 anos. Essa também é uma boa informação para o departamento de Marketing.

No momento, temos duas variáveis ​​categóricas, Age e Genre, que precisamos transformar em números para poder usar em nosso modelo. Existem muitas maneiras diferentes de fazer essa transformação – usaremos os Pandas get_dummies() método que cria uma nova coluna para cada intervalo e gênero e depois preenche seus valores com 0s e 1s - esse tipo de operação é chamado codificação one-hot. Vamos ver como fica:


customer_data_oh = pd.get_dummies(customer_data)

customer_data_oh 

Isso nos dará uma prévia da tabela resultante:

img

Com a saída, é fácil ver que a coluna Genre foi dividido em colunas – Genre_Female e Genre_Male. Quando o cliente é do sexo feminino, Genre_Female é igual a 1, e quando o cliente é do sexo masculino, é igual 0.

Também o Age Groups coluna foi dividida em 6 colunas, uma para cada intervalo, como Age Groups_(15, 20], Age Groups_(20, 30], e assim por diante. Da mesma maneira que Genre, quando o cliente tiver 18 anos, o Age Groups_(15, 20] valor é 1 e o valor de todas as outras colunas é 0.

A vantagem da codificação one-hot é a simplicidade na representação dos valores das colunas, é simples entender o que está acontecendo - enquanto o desvantagem é que agora criamos 8 colunas adicionais, para resumir com as colunas que já tínhamos.

Aviso: se você tiver um conjunto de dados no qual o número de colunas codificadas one-hot excede o número de linhas, é melhor empregar outro método de codificação para evitar problemas de dimensionalidade de dados.

A codificação one-hot também adiciona 0s aos nossos dados, tornando-os mais esparsos, o que pode ser um problema para alguns algoritmos que são sensíveis à escassez de dados.

Para nossas necessidades de cluster, a codificação one-hot parece funcionar. Mas podemos plotar os dados para ver se realmente existem grupos distintos para agruparmos.

Plotagem básica e redução de dimensionalidade

Nosso conjunto de dados tem 11 colunas e existem algumas maneiras de visualizar esses dados. O primeiro é plotando-o em 10 dimensões (boa sorte com isso). Dez porque o Customer_ID coluna não está sendo considerada. A segunda é plotando nossas feições numéricas iniciais, e a terceira é transformando nossas 10 feições em 2 – portanto, realizando uma redução de dimensionalidade.

Plotando cada par de dados

Como plotar 10 dimensões é um pouco impossível, vamos optar pela segunda abordagem – vamos plotar nossos recursos iniciais. Podemos escolher dois deles para nossa análise de agrupamento. Uma maneira de ver todos os nossos pares de dados combinados é com um Seaborn pairplot():

import seaborn as sns


customer_data = customer_data.drop('CustomerID', axis=1)

sns.pairplot(customer_data)

Que exibe:

img

De relance, podemos identificar os gráficos de dispersão que parecem ter grupos de dados. Um que parece interessante é o gráfico de dispersão que combina Annual Income e Spending Score. Observe que não há uma separação clara entre outros gráficos de dispersão de variáveis. No máximo, podemos dizer que existem duas concentrações distintas de pontos no Spending Score vs Age gráfico de dispersão.

Ambos os gráficos de dispersão consistem em Annual Income e Spending Score são essencialmente os mesmos. Podemos vê-lo duas vezes porque os eixos x e y foram trocados. Ao dar uma olhada em qualquer um deles, podemos ver o que parecem ser cinco grupos diferentes. Vamos plotar apenas esses dois recursos com um Seaborn scatterplot() para dar uma olhada mais de perto:

sns.scatterplot(x=customer_data['Annual Income (k$)'],
                y=customer_data['Spending Score (1-100)'])

img

Olhando mais de perto, podemos definitivamente distinguir 5 grupos diferentes de dados. Parece que nossos clientes podem ser agrupados com base em quanto ganham em um ano e quanto gastam. Este é outro ponto relevante em nossa análise. É importante levarmos em consideração apenas duas características para agrupar nossos clientes. Qualquer outra informação que tenhamos sobre eles não está entrando na equação. Isso dá significado à análise – se soubermos quanto um cliente ganha e gasta, podemos encontrar facilmente as semelhanças que precisamos.

img

Isso é ótimo! Até agora, já temos duas variáveis ​​para construir nosso modelo. Além do que isso representa, também torna o modelo mais simples, parcimonioso e mais explicável.

Confira nosso guia prático e prático para aprender Git, com práticas recomendadas, padrões aceitos pelo setor e folha de dicas incluída. Pare de pesquisar comandos Git no Google e realmente aprender -lo!

Observação: A Ciência de Dados geralmente favorece abordagens o mais simples possível. Não só porque é mais fácil de explicar para o negócio, mas também porque é mais direto – com 2 funcionalidades e um modelo explicável, fica claro o que o modelo está fazendo e como está funcionando.

Plotando dados após usar o PCA

Parece que nossa segunda abordagem é provavelmente a melhor, mas vamos também dar uma olhada em nossa terceira abordagem. Pode ser útil quando não podemos plotar os dados porque há muitas dimensões ou quando não há concentrações de dados ou separação clara em grupos. Quando essas situações ocorrem, é recomendável tentar reduzir as dimensões dos dados com um método chamado Análise de Componentes Principais (PCA).

Observação: A maioria das pessoas usa PCA para redução de dimensionalidade antes da visualização. Existem outros métodos que auxiliam na visualização de dados antes do agrupamento, como Agrupamento Espacial de Aplicativos com Ruído Baseado em Densidade (DBSCAN) e Mapas auto-organizados (SOM) agrupamento. Ambos são algoritmos de agrupamento, mas também podem ser usados ​​para visualização de dados. Como a análise de clustering não tem um padrão-ouro, é importante comparar diferentes visualizações e diferentes algoritmos.

O PCA reduzirá as dimensões de nossos dados enquanto tenta preservar o máximo possível de suas informações. Vamos primeiro ter uma ideia de como o PCA funciona e, em seguida, podemos escolher para quantas dimensões de dados reduziremos nossos dados.

Para cada par de características, o PCA verifica se os maiores valores de uma variável correspondem aos maiores valores da outra variável e faz o mesmo para os menores valores. Então, ele essencialmente calcula o quanto os valores dos recursos variam entre si – chamamos isso de covariância. Esses resultados são então organizados em uma matriz, obtendo uma matriz de covariância.

Depois de obter a matriz de covariância, o PCA tenta encontrar uma combinação linear de características que melhor a explique – ajusta modelos lineares até identificar aquele que explica o máximo quantidade de variação.

Note: PCA é uma transformação linear e a linearidade é sensível à escala dos dados. Portanto, o PCA funciona melhor quando todos os valores de dados estão na mesma escala. Isso pode ser feito subtraindo a coluna significar de seus valores e dividindo o resultado pelo seu desvio padrão. Isso é chamado padronização de dados. Antes de usar o PCA, verifique se os dados estão dimensionados! Se você não tem certeza de como, leia nosso “Feature Scaling Data com Scikit-Learn para Machine Learning em Python”!

Com a melhor linha (combinação linear) encontrada, o PCA obtém as direções de seus eixos, chamados autovetores, e seus coeficientes lineares, o autovalores. A combinação dos autovetores e autovalores – ou direções e coeficientes dos eixos – são os Componentes principais do PCA. E é aí que podemos escolher o nosso número de dimensões com base na variância explicada de cada característica, compreendendo quais componentes principais queremos manter ou descartar com base na quantidade de variância que eles explicam.

Após obter os componentes principais, o PCA utiliza os autovetores para formar um vetor de feições que reorienta os dados dos eixos originais para os representados pelos componentes principais – é assim que as dimensões dos dados são reduzidas.

Observação: Um detalhe importante a ser considerado aqui é que, devido à sua natureza linear, o PCA concentrará a maior parte da variância explicada nos primeiros componentes principais. Então, ao olhar para a variância explicada, normalmente nossos dois primeiros componentes serão suficientes. Mas isso pode ser enganoso em alguns casos – então tente continuar comparando gráficos e algoritmos diferentes ao agrupar para ver se eles mantêm resultados semelhantes.

Antes de aplicar o PCA, precisamos escolher entre o Age coluna ou o Age Groups colunas em nossos dados codificados anteriormente one-hot. Como ambas as colunas representam as mesmas informações, introduzi-las duas vezes afeta nossa variação de dados. Se o Age Groups coluna for escolhida, basta remover a Age coluna usando os Pandas drop() método e reatribuí-lo ao customer_data_oh variável:

customer_data_oh = customer_data_oh.drop(['Age'], axis=1)
customer_data_oh.shape 

Agora nossos dados têm 10 colunas, o que significa que podemos obter um componente principal por coluna e escolher quantos deles usaremos medindo o quanto a introdução de uma nova dimensão explica mais a variação de nossos dados.

Vamos fazer isso com o Scikit-Learn PCA. Vamos calcular a variância explicada de cada dimensão, dada por explained_variance_ratio_ , e então veja sua soma acumulada com cumsum() :

from sklearn.decomposition import PCA

pca = PCA(n_components=10)
pca.fit_transform(customer_data_oh)
pca.explained_variance_ratio_.cumsum()

Nossas variações cumulativas explicadas são:

array([0.509337  , 0.99909504, 0.99946364, 0.99965506, 0.99977937,
       0.99986848, 0.99993716, 1.        , 1.        , 1.        ])

Podemos ver que a primeira dimensão explica 50% dos dados e, quando combinada à segunda dimensão, explica 99% por cento. Isso significa que as 2 primeiras dimensões já explicam 99% dos nossos dados. Assim podemos aplicar um PCA com 2 componentes, obter nossos componentes principais e plotá-los:

from sklearn.decomposition import PCA

pca = PCA(n_components=2)
pcs = pca.fit_transform(customer_data_oh)

pc1_values = pcs[:,0]
pc2_values = pcs[:,1]
sns.scatterplot(x=pc1_values, y=pc2_values)

img

O gráfico de dados após o PCA é muito semelhante ao gráfico que está usando apenas duas colunas dos dados sem o PCA. Observe que os pontos que estão formando grupos estão mais próximos e um pouco mais concentrados após a PCA do que antes.

img

Visualizando a estrutura hierárquica com dendrogramas

Até agora, exploramos os dados, colunas categóricas codificadas one-hot, decidimos quais colunas eram adequadas para agrupamento e reduzimos a dimensionalidade dos dados. Os gráficos indicam que temos 5 clusters em nossos dados, mas também há outra maneira de visualizar as relações entre nossos pontos e ajudar a determinar o número de clusters - criando um dendrograma (comumente escrito incorretamente como dendograma). dendro significa árvore em latim.

A dendrograma é o resultado da ligação de pontos em um conjunto de dados. É uma representação visual do processo de agrupamento hierárquico. E como funciona o processo de agrupamento hierárquico? Bem… depende – provavelmente uma resposta que você já ouviu muito em Data Science.

Entendendo o cluster hierárquico

Quando o Algoritmo de agrupamento hierárquico (HCA) começa a ligar os pontos e encontrar clusters, ele pode primeiro dividir os pontos em 2 grandes grupos, e então dividir cada um desses dois grupos em 2 grupos menores, com 4 grupos no total, que é o divisivo e top-down abordagem.

Alternativamente, ele pode fazer o oposto – pode olhar para todos os pontos de dados, encontrar 2 pontos mais próximos um do outro, vinculá-los e, em seguida, encontrar outros pontos que sejam os mais próximos desses pontos vinculados e continuar construindo os 2 grupos de debaixo para cima. Qual é o aglomerativo abordagem que desenvolveremos.

Etapas para executar cluster hierárquico aglomerativo

Para tornar ainda mais clara a abordagem aglomerativa, existem etapas do Clustering Hierárquico Aglomerativo (AHC) algoritmo:

  1. No início, trate cada ponto de dados como um cluster. Portanto, o número de clusters no início será K – enquanto K é um número inteiro que representa o número de pontos de dados.
  2. Forme um cluster juntando os dois pontos de dados mais próximos, resultando em clusters K-1.
  3. Forme mais clusters juntando os dois clusters mais próximos, resultando em clusters K-2.
  4. Repita as três etapas acima até que um grande cluster seja formado.

Note: Para simplificar, estamos dizendo “dois pontos de dados mais próximos” nas etapas 2 e 3. Mas há mais maneiras de vincular pontos, como veremos em breve.

Se você inverter as etapas do algoritmo ACH, passando de 4 para 1 – essas seriam as etapas para *Clustering Hierárquico Divisivo (DHC)*.

Observe que os HCAs podem ser divisivos e de cima para baixo ou aglomerativos e de baixo para cima. A abordagem DHC de cima para baixo funciona melhor quando você tem menos clusters, mas maiores, portanto, é mais caro computacionalmente. Por outro lado, a abordagem AHC de baixo para cima é adequada para quando você tem muitos clusters menores. É computacionalmente mais simples, mais usado e mais disponível.

Observação: Seja de cima para baixo ou de baixo para cima, a representação do dendrograma do processo de agrupamento sempre começará com uma divisão em dois e terminará com cada ponto individual discriminado, uma vez que sua estrutura subjacente é de uma árvore binária.

Vamos traçar nosso dendrograma de dados do cliente para visualizar as relações hierárquicas dos dados. Desta vez, usaremos o scipy biblioteca para criar o dendrograma para nosso conjunto de dados:

import scipy.cluster.hierarchy as shc
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 7))
plt.title("Customers Dendrogram")


selected_data = customer_data_oh.iloc[:, 1:3]
clusters = shc.linkage(selected_data, 
            method='ward', 
            metric="euclidean")
shc.dendrogram(Z=clusters)
plt.show()

A saída do script fica assim:

img

No script acima, geramos os clusters e subclusters com nossos pontos, definimos como nossos pontos seriam vinculados (aplicando o ward método), e como medir a distância entre os pontos (usando o euclidean métrica).

Com o gráfico do dendrograma, os processos descritos de DHC e AHC podem ser visualizados. Para visualizar a abordagem de cima para baixo, comece do topo do dendrograma e desça, e faça o oposto, começando para baixo e subindo para visualizar a abordagem de baixo para cima.

Métodos de ligação

Existem muitos outros métodos de vinculação, entendendo melhor como eles funcionam, você poderá escolher o mais adequado às suas necessidades. Além disso, cada um deles trará resultados diferentes quando aplicados. Não existe uma regra fixa na análise de agrupamento, se possível, estude a natureza do problema para ver qual se encaixa melhor, teste diferentes métodos e inspecione os resultados.

Alguns dos métodos de ligação são:

  • Ligação única: também conhecido como Vizinho mais próximo (NN). A distância entre os clusters é definida pela distância entre seus membros mais próximos.

img

  • Ligação completa: também conhecido como Vizinho mais distante (FN), Algoritmo do ponto mais distanteou Algoritmo Voor Hees. A distância entre clusters é definida pela distância entre seus membros mais distantes. Este método é computacionalmente caro.

img

  • Ligação média: também conhecido como UPGMA (Método de grupo de pares não ponderado com média aritmética). A porcentagem do número de pontos de cada cluster é calculada em relação ao número de pontos dos dois clusters se eles foram mesclados.

img

  • Ligação ponderada: também conhecido como WPGMA (Método de Grupo de Pares Ponderados com média aritmética). Os pontos individuais dos dois clusters contribuem para a distância agregada entre um cluster menor e um cluster maior.
  • Ligação centroide: também conhecido como UPGMC (Método de Grupo de Pares Não Ponderados usando Centroides). Um ponto definido pela média de todos os pontos (centroid) é calculado para cada cluster e a distância entre clusters é a distância entre seus respectivos centróides.

img

  • Ligação da ala: Também conhecido como MISSQ (Aumento mínimo da soma dos quadrados). Ele especifica a distância entre dois clusters, calcula o erro da soma dos quadrados (ESS) e escolhe sucessivamente os próximos clusters com base no ESS menor. O Método de Ward busca minimizar o aumento da ESS a cada etapa. Portanto, minimizando o erro.

img

Métricas de distância

Além do linkage, também podemos especificar algumas das métricas de distância mais utilizadas:

  • Euclidiano: também conhecido como Pitágoras ou em linha reta distância. Ele calcula a distância entre dois pontos no espaço, medindo o comprimento de um segmento de linha que passa entre eles. Ele usa o teorema de Pitágoras e o valor da distância é o resultado (C) da equação:

$$
c^2 = a^2 + b^2
$$

  • Manhattan: também chamado Bloco da cidade, Táxi distância. É a soma das diferenças absolutas entre as medidas em todas as dimensões de dois pontos. Se essas dimensões forem duas, é análogo a virar à direita e depois à esquerda ao caminhar um quarteirão.

img

  • Minkowski: é uma generalização das distâncias euclidiana e de Manhattan. É uma maneira de calcular distâncias com base nas diferenças absolutas da ordem da métrica de Minkowski p. Embora seja definido para qualquer p> 0, raramente é usado para valores diferentes de 1, 2 e ∞ (infinito). A distância de Minkowski é igual à distância de Manhattan quando p = 1, e o mesmo que a distância euclidiana quando p = 2.

$$
Desquerda(X,Ydireita) = esquerda(soma_{i=1}^n |x_i-y_i|^pright)^{frac{1}{p}}
$$

img

  • Chebyshev: também conhecido como Tabuleiro de xadrez distância. É o caso extremo da distância de Minkowski. Quando usamos infinito como o valor do parâmetro p (p = ∞), acabamos com uma métrica que define a distância como a diferença absoluta máxima entre as coordenadas.
  • Cosseno: é a distância cosseno angular entre duas sequências de pontos, ou vetores. A similaridade do cosseno é o produto escalar dos vetores dividido pelo produto de seus comprimentos.
  • jaccard: mede a similaridade entre conjuntos finitos de pontos. É definido como o número total de pontos (cardinalidade) nos pontos comuns em cada conjunto (interseção), dividido pelo número total de pontos (cardinalidade) do total de pontos de ambos os conjuntos (união).
  • Jensen-Shannon: baseado na divergência de Kullback-Leibler. Ele considera as distribuições de probabilidade dos pontos e mede a similaridade entre essas distribuições. É um método popular de teoria da probabilidade e estatística.

Nós escolhemos Enfermaria e Euclidiano para o dendrograma porque eles são o método e a métrica mais comumente usados. Eles geralmente dão bons resultados, pois Ward vincula pontos com base na minimização dos erros, e o Euclidiano funciona bem em dimensões mais baixas.

Neste exemplo, estamos trabalhando com dois recursos (colunas) dos dados de marketing e 200 observações ou linhas. Como o número de observações é maior que o número de feições (200 > 2), estamos trabalhando em um espaço de baixa dimensão.

Quando o número de recursos (F) é maior que o número de observações (N) – principalmente escrito como f >> N, significa que temos um espaço de alta dimensão.

Se incluíssemos mais atributos, então temos mais de 200 feições, a distância euclidiana pode não funcionar muito bem, pois teria dificuldade em medir todas as pequenas distâncias em um espaço muito grande que só aumenta. Em outras palavras, a abordagem da distância euclidiana tem dificuldades em trabalhar com os dados esparsidade. Esta é uma questão que se chama a maldição da dimensionalidade. Os valores de distância ficariam tão pequenos, como se ficassem “diluídos” no espaço maior, distorcidos até se tornarem 0.

Observação: Se você encontrar um conjunto de dados com f >> p, você provavelmente usará outras métricas de distância, como o Mahalanobis distância. Como alternativa, você também pode reduzir as dimensões do conjunto de dados usando Análise de Componentes Principais (PCA). Esse problema é frequente, especialmente ao agrupar dados de sequenciamento biológico.

Já discutimos métricas, vínculos e como cada um deles pode impactar nossos resultados. Vamos agora continuar a análise do dendrograma e ver como ela pode nos dar uma indicação do número de clusters em nosso conjunto de dados.

Encontrar um número interessante de clusters em um dendrograma é o mesmo que encontrar o maior espaço horizontal que não possui linhas verticais (o espaço com as linhas verticais mais longas). Isso significa que há mais separação entre os clusters.

Podemos traçar uma linha horizontal que passa por essa distância mais longa:

plt.figure(figsize=(10, 7))
plt.title("Customers Dendogram with line")
clusters = shc.linkage(selected_data, 
            method='ward', 
            metric="euclidean")
shc.dendrogram(clusters)
plt.axhline(y = 125, color = 'r', linestyle = '-')

img

Após localizar a linha horizontal, contamos quantas vezes nossas linhas verticais foram cruzadas por ela – neste exemplo, 5 vezes. Portanto, 5 parece uma boa indicação do número de clusters que possuem a maior distância entre eles.

Note: O dendrograma deve ser considerado apenas como referência quando usado para escolher o número de clusters. Ele pode facilmente reduzir esse número e é completamente influenciado pelo tipo de ligação e pelas métricas de distância. Ao realizar uma análise de cluster em profundidade, é aconselhável observar dendrogramas com diferentes ligações e métricas e observar os resultados gerados com as três primeiras linhas em que os clusters têm maior distância entre eles.

Implementando um Cluster Hierárquico Aglomerativo

Usando dados originais

Até agora calculamos o número sugerido de clusters para nosso conjunto de dados que corroboram com nossa análise inicial e nossa análise de PCA. Agora podemos criar nosso modelo de cluster hierárquico aglomerativo usando Scikit-Learn AgglomerativeClustering e conheça os rótulos dos pontos de marketing com labels_:

from sklearn.cluster import AgglomerativeClustering

clustering_model = AgglomerativeClustering(n_clusters=5, affinity='euclidean', linkage='ward')
clustering_model.fit(selected_data)
clustering_model.labels_

Isto resulta em:

array([4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3,
       4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 1,
       4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 0, 2, 0, 2,
       1, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 2, 1, 2, 0, 2, 0, 2, 0, 2,
       0, 2, 0, 2, 0, 2, 1, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2,
       0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2,
       0, 2])

Investigamos muito para chegar a este ponto. E o que significam esses rótulos? Aqui, temos cada ponto de nossos dados rotulados como um grupo de 0 a 4:

data_labels = clustering_model.labels_
sns.scatterplot(x='Annual Income (k$)', 
                y='Spending Score (1-100)', 
                data=selected_data, 
                hue=data_labels,
                pallete="rainbow").set_title('Labeled Customer Data')

img

Estes são nossos dados clusterizados finais. Você pode ver os pontos de dados codificados por cores na forma de cinco clusters.

Os pontos de dados no canto inferior direito (rótulo: 0, pontos de dados roxos) pertencem aos clientes com salários altos, mas gastos baixos. Estes são os clientes que gastam seu dinheiro com cuidado.

Da mesma forma, os clientes no canto superior direito (rótulo: 2, pontos de dados verdes), são os clientes com altos salários e altos gastos. Esses são os tipos de clientes que as empresas têm como alvo.

Os clientes no meio (etiqueta: 1, pontos de dados azuis) são aqueles com renda média e gastos médios. Os maiores números de clientes pertencem a esta categoria. As empresas também podem segmentar esses clientes, já que eles estão em grande número.

Os clientes no canto inferior esquerdo (etiqueta: 4, vermelho) são os clientes que têm baixos salários e baixos gastos, eles podem ser atraídos pela oferta de promoções.

E, finalmente, os clientes no canto superior esquerdo (etiqueta: 3, pontos de dados laranja) são aqueles com alta renda e baixo gasto, que são idealmente visados ​​pelo marketing.

Usando o resultado do PCA

Se estivéssemos em um cenário diferente, em que tivéssemos que reduzir a dimensionalidade dos dados. Também poderíamos plotar facilmente os resultados do PCA clusterizado. Isso pode ser feito criando outro modelo de cluster aglomerativo e obtendo um rótulo de dados para cada componente principal:

clustering_model_pca = AgglomerativeClustering(n_clusters=5, affinity='euclidean', linkage='ward')
clustering_model_pca.fit(pcs)

data_labels_pca = clustering_model_pca.labels_

sns.scatterplot(x=pc1_values, 
                y=pc2_values,
                hue=data_labels_pca,
                palette="rainbow").set_title('Labeled Customer Data Reduced with PCA')

img

Observe que ambos os resultados são muito semelhantes. A principal diferença é que o primeiro resultado com os dados originais é muito mais fácil de explicar. É claro que os clientes podem ser divididos em cinco grupos por sua renda anual e pontuação de gastos. Enquanto, na abordagem PCA, estamos levando em consideração todos os nossos recursos, por mais que possamos observar a variação explicada por cada um deles, esse é um conceito mais difícil de entender, especialmente quando se reporta a um departamento de Marketing.

Quanto menos tivermos para transformar nossos dados, melhor.

Se você tiver um conjunto de dados muito grande e complexo no qual deve executar uma redução de dimensionalidade antes do agrupamento - tente analisar as relações lineares entre cada um dos recursos e seus resíduos para apoiar o uso do PCA e melhorar a explicabilidade do processo. Ao fazer um modelo linear por par de recursos, você poderá entender como os recursos interagem.

Se o volume de dados for tão grande, torna-se impossível traçar os pares de características, selecionar uma amostra de seus dados, o mais equilibrada e próxima da distribuição normal possível e realizar a análise na amostra primeiro, entendê-la, ajustar - e aplicá-lo posteriormente a todo o conjunto de dados.

Você sempre pode escolher diferentes técnicas de visualização de cluster de acordo com a natureza de seus dados (linear, não linear) e combinar ou testar todas elas, se necessário.

Conclusão

A técnica de agrupamento pode ser muito útil quando se trata de dados não rotulados. Como a maioria dos dados no mundo real não é rotulada e anotar os dados tem custos mais altos, técnicas de agrupamento podem ser usadas para rotular dados não rotulados.

Neste guia, trouxemos um problema real de ciência de dados, uma vez que as técnicas de agrupamento são amplamente utilizadas na análise de marketing (e também na análise biológica). Também explicamos muitas das etapas de investigação para chegar a um bom modelo de agrupamento hierárquico e como ler dendrogramas e questionamos se o PCA é uma etapa necessária. Nosso principal objetivo é que algumas das armadilhas e diferentes cenários em que podemos encontrar agrupamentos hierárquicos sejam cobertos.

Boa aglomeração!

Carimbo de hora:

Mais de Abuso de pilha