0% acharam este documento útil (0 voto)
19 visualizações10 páginas

Introducao Python Clusterizacao de Clientes

O documento aborda a clusterização de clientes com base em dados de consumo de energia, utilizando técnicas de Machine Learning. Através da aplicação do algoritmo K-Means e redução de dimensionalidade com PCA, o objetivo é agrupar consumidores por similaridade em seu comportamento de consumo. O processo inclui a limpeza dos dados, visualização dos clusters e avaliação da qualidade dos agrupamentos com o Silhouette Score.

Enviado por

Leandro Massai
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
19 visualizações10 páginas

Introducao Python Clusterizacao de Clientes

O documento aborda a clusterização de clientes com base em dados de consumo de energia, utilizando técnicas de Machine Learning. Através da aplicação do algoritmo K-Means e redução de dimensionalidade com PCA, o objetivo é agrupar consumidores por similaridade em seu comportamento de consumo. O processo inclui a limpeza dos dados, visualização dos clusters e avaliação da qualidade dos agrupamentos com o Silhouette Score.

Enviado por

Leandro Massai
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
Você está na página 1/ 10

22/02/2025, 17:50 Clusterizacao

Machine Learning Clusterização

Agrupamento de Clientes Por Consumo de


Energia
A partir de dados de consumo de energia de clientes, vamos agrupar os consumidores por
similaridade a afim de compreender o comportamento dos clientes e sua relação com o
consumo de energia.

In [83]: # Imports
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import pylab
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split
from scipy.spatial.distance import cdist, pdist
from sklearn.metrics import silhouette_score
import warnings
warnings.filterwarnings("ignore")
%matplotlib inline

In [84]: # Carregando os dados


dataset = pd.read_csv('consumo_energia.txt', delimiter = ';')

In [85]: # Visualizando informações sobre o dataset


dataset.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2075259 entries, 0 to 2075258
Data columns (total 9 columns):
# Column Dtype
--- ------ -----
0 Date object
1 Time object
2 Global_active_power object
3 Global_reactive_power object
4 Voltage object
5 Global_intensity object
6 Sub_metering_1 object
7 Sub_metering_2 object
8 Sub_metering_3 float64
dtypes: float64(1), object(8)
memory usage: 142.5+ MB

In [86]: dataset.head()

localhost:8889/nbconvert/html/Clusterizacao.ipynb?download=false 1/10
22/02/2025, 17:50 Clusterizacao

Out[86]: Date Time Global_active_power Global_reactive_power Voltage Global_intensity Sub

0 16/12/2006 17:24:00 4.216 0.418 234.840 18.400

1 16/12/2006 17:25:00 5.360 0.436 233.630 23.000

2 16/12/2006 17:26:00 5.374 0.498 233.290 23.000

3 16/12/2006 17:27:00 5.388 0.502 233.740 23.000

4 16/12/2006 17:28:00 3.666 0.528 235.680 15.800

In [87]: dataset.shape

(2075259, 9)
Out[87]:

In [88]: dataset.dtypes

Date object
Out[88]:
Time object
Global_active_power object
Global_reactive_power object
Voltage object
Global_intensity object
Sub_metering_1 object
Sub_metering_2 object
Sub_metering_3 float64
dtype: object

In [89]: # Checando se há valores missing


dataset.isnull().values.any()

True
Out[89]:

In [90]: # Remove os registros com valores NA e remove as duas primeiras colunas (não são ne
dataset = dataset.iloc[0:, 2:9].dropna()

In [91]: dataset['Voltage'] = dataset['Voltage'].astype(dtype = 'float64')


dataset['Global_active_power'] = dataset['Global_active_power'].astype(dtype = 'flo
dataset['Global_reactive_power'] = dataset['Global_reactive_power'].astype(dtype =
dataset['Global_intensity'] = dataset['Global_intensity'].astype(dtype = 'float64')
dataset['Sub_metering_1'] = dataset['Sub_metering_1'].astype(dtype = 'float64')
dataset['Sub_metering_2'] = dataset['Sub_metering_2'].astype(dtype = 'float64')
dataset['Sub_metering_3'] = dataset['Sub_metering_3'].astype(dtype = 'float64')

In [92]: dataset.info()

<class 'pandas.core.frame.DataFrame'>
Int64Index: 2049280 entries, 0 to 2075258
Data columns (total 7 columns):
# Column Dtype
--- ------ -----
0 Global_active_power float64
1 Global_reactive_power float64
2 Voltage float64
3 Global_intensity float64
4 Sub_metering_1 float64
5 Sub_metering_2 float64
6 Sub_metering_3 float64
dtypes: float64(7)
memory usage: 125.1 MB

localhost:8889/nbconvert/html/Clusterizacao.ipynb?download=false 2/10
22/02/2025, 17:50 Clusterizacao

In [93]: dataset.head()

Out[93]: Global_active_power Global_reactive_power Voltage Global_intensity Sub_metering_1 Sub_met

0 4.216 0.418 234.84 18.4 0.0

1 5.360 0.436 233.63 23.0 0.0

2 5.374 0.498 233.29 23.0 0.0

3 5.388 0.502 233.74 23.0 0.0

4 3.666 0.528 235.68 15.8 0.0

In [94]: # Checando se há valores missing


dataset.isnull().values.any()

False
Out[94]:

In [95]: # Obtém os valores dos atributos. Neste caso as variaveis foram carregadas como cat
dataset_atrib = dataset.values

In [96]: dataset_atrib

array([[ 4.216, 0.418, 234.84 , ..., 0. , 1. , 17. ],


Out[96]:
[ 5.36 , 0.436, 233.63 , ..., 0. , 1. , 16. ],
[ 5.374, 0.498, 233.29 , ..., 0. , 2. , 17. ],
...,
[ 0.938, 0. , 239.82 , ..., 0. , 0. , 0. ],
[ 0.934, 0. , 239.7 , ..., 0. , 0. , 0. ],
[ 0.932, 0. , 239.55 , ..., 0. , 0. , 0. ]])

In [97]: # Coleta uma amostra de 1% dos dados para não comprometer a memória do computador
amostra1, amostra2 = train_test_split(dataset_atrib, train_size = .01)

In [98]: amostra1.shape

(20492, 7)
Out[98]:

In [99]: # Aplica redução de dimensionalidade


# Transforma as 7 variáveis em 2 variaveis principais. Esse método utiliza Algebra
# entre os dados e assim "juntar" as variaveis, medindo a semelhança pela variância
pca = PCA(n_components = 2).fit_transform(amostra1)

In [100… # Determinando um range de K


k_range = range(1,12)

In [103… # Aplicando o modelo K-Means para cada valor de K (esta célula pode levar bastante
k_means_var = [KMeans(n_clusters = k).fit(pca) for k in k_range]

In [104… # Ajustando o centróide do cluster para cada modelo


centroids = [X.cluster_centers_ for X in k_means_var]

In [105… # Calculando a distância euclidiana de cada ponto de dado para o centróide


k_euclid = [cdist(pca, cent, 'euclidean') for cent in centroids]
dist = [np.min(ke, axis = 1) for ke in k_euclid]

In [106… # Soma dos quadrados das distâncias dentro do cluster


soma_quadrados_intra_cluster = [sum(d**2) for d in dist]
localhost:8889/nbconvert/html/Clusterizacao.ipynb?download=false 3/10
22/02/2025, 17:50 Clusterizacao

In [107… # Soma total dos quadrados


soma_total = sum(pdist(pca)**2)/pca.shape[0]

In [108… # Soma dos quadrados entre clusters


soma_quadrados_inter_cluster = soma_total - soma_quadrados_intra_cluster

In [109… # Curva de Elbow


fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(k_range, soma_quadrados_inter_cluster/soma_total * 100, 'b*-')
ax.set_ylim((0,100))
plt.grid(True)
plt.xlabel('Número de Clusters')
plt.ylabel('Percentual de Variância Explicada')
plt.title('Variância Explicada x Valor de K')

Text(0.5, 1.0, 'Variância Explicada x Valor de K')


Out[109]:

In [112… # Criando um modelo com K = 8


modelo_v1 = KMeans(n_clusters = 8)
modelo_v1.fit(pca)

KMeans()
Out[112]:

In [ ]:

In [ ]:

In [113… # Obtém os valores mínimos e máximos e organiza o shape


x_min, x_max = pca[:, 0].min() - 5, pca[:, 0].max() - 1
y_min, y_max = pca[:, 1].min() + 1, pca[:, 1].max() + 5
xx, yy = np.meshgrid(np.arange(x_min, x_max, .02), np.arange(y_min, y_max, .02))

localhost:8889/nbconvert/html/Clusterizacao.ipynb?download=false 4/10
22/02/2025, 17:50 Clusterizacao
Z = modelo_v1.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

In [114… # Plot das áreas dos clusters


plt.figure(1)
plt.clf()
plt.imshow(Z,
interpolation = 'nearest',
extent = (xx.min(), xx.max(), yy.min(), yy.max()),
cmap = plt.cm.Paired,
aspect = 'auto',
origin = 'lower')

<matplotlib.image.AxesImage at 0x23c8588cd30>
Out[114]:

In [115… # Plot dos centróides


plt.plot(pca[:, 0], pca[:, 1], 'k.', markersize = 4)
centroids = modelo_v1.cluster_centers_
inert = modelo_v1.inertia_
plt.scatter(centroids[:, 0], centroids[:, 1], marker = 'x', s = 169, linewidths = 3
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.xticks(())
plt.yticks(())
plt.show()

localhost:8889/nbconvert/html/Clusterizacao.ipynb?download=false 5/10
22/02/2025, 17:50 Clusterizacao

In [117… #?silhouette_score

In [118… # Silhouette Score


labels = modelo_v1.labels_
silhouette_score(pca, labels, metric = 'euclidean')

0.8088812305122378
Out[118]:

In [119… # Criando um modelo com K = 10


modelo_v2 = KMeans(n_clusters = 10)
modelo_v2.fit(pca)

KMeans(n_clusters=10)
Out[119]:

In [120… # Obtém os valores mínimos e máximos e organiza o shape


x_min, x_max = pca[:, 0].min() - 5, pca[:, 0].max() - 1
y_min, y_max = pca[:, 1].min() + 1, pca[:, 1].max() + 5
xx, yy = np.meshgrid(np.arange(x_min, x_max, .02), np.arange(y_min, y_max, .02))
Z = modelo_v2.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

In [121… # Plot das áreas dos clusters


plt.figure(1)
plt.clf()
plt.imshow(Z,
interpolation = 'nearest',
extent = (xx.min(), xx.max(), yy.min(), yy.max()),
cmap = plt.cm.Paired,
aspect = 'auto',
origin = 'lower')

<matplotlib.image.AxesImage at 0x23c998d0040>
Out[121]:

localhost:8889/nbconvert/html/Clusterizacao.ipynb?download=false 6/10
22/02/2025, 17:50 Clusterizacao

In [122… # Plot dos centróides


plt.plot(pca[:, 0], pca[:, 1], 'k.', markersize = 4)
centroids = modelo_v2.cluster_centers_
inert = modelo_v2.inertia_
plt.scatter(centroids[:, 0], centroids[:, 1], marker = 'x', s = 169, linewidths = 3
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.xticks(())
plt.yticks(())
plt.show()

localhost:8889/nbconvert/html/Clusterizacao.ipynb?download=false 7/10
22/02/2025, 17:50 Clusterizacao

In [123… # Silhouette Score -- utilizamos para avaliar se o numero de cluster é o ideal... m


labels = modelo_v2.labels_
silhouette_score(pca, labels, metric = 'euclidean')

0.682286610628249
Out[123]:

Criando o Cluster Map com os clusters do Modelo V1 que apresentou melhor Silhouette
Score.

In [124… # Lista com nomes das colunas


names = ['Global_active_power', 'Global_reactive_power', 'Voltage', 'Global_intensi

In [125… # Cria o cluster map


cluster_map = pd.DataFrame(amostra1, columns = names)
cluster_map['Global_active_power'] = pd.to_numeric(cluster_map['Global_active_power
cluster_map['cluster'] = modelo_v1.labels_

In [128… cluster_map

Out[128]: Global_active_power Global_reactive_power Voltage Global_intensity Sub_metering_1 Sub

0 0.318 0.114 242.34 1.4 0.0

1 2.184 0.134 242.47 9.0 0.0

2 0.392 0.366 243.91 2.2 0.0

3 3.426 0.000 232.05 14.6 35.0

4 1.514 0.194 239.18 6.4 0.0

... ... ... ... ... ...

20487 0.394 0.000 241.34 1.6 2.0

20488 1.450 0.108 240.64 6.0 0.0

20489 0.320 0.084 242.66 1.4 0.0

20490 0.376 0.000 243.32 1.6 0.0

20491 0.202 0.000 239.46 0.8 0.0

20492 rows × 8 columns

In [129… # Calcula a média de consumo de energia por cluster


cluster_map.groupby('cluster')['Global_active_power'].mean()

cluster
Out[129]:
0 0.515455
1 1.810525
2 4.635189
3 3.511884
4 3.776012
5 1.106406
6 2.352873
7 2.556937
Name: Global_active_power, dtype: float64

In [130… # Calcula a quantidade de observacoes por cluster


cluster_map.groupby('cluster')['Global_active_power'].count()

localhost:8889/nbconvert/html/Clusterizacao.ipynb?download=false 8/10
22/02/2025, 17:50 Clusterizacao
cluster
Out[130]:
0 12853
1 5894
2 397
3 207
4 324
5 399
6 181
7 237
Name: Global_active_power, dtype: int64

In [ ]:

Gerando Cluster com dados normalizados


In [131… # Obtém os valores dos atributos. Neste caso as variaveis foram carregadas como cat
dataset_atrib = dataset.values

# Importa biblioteca para fazer a normalizacao


from sklearn.preprocessing import MinMaxScaler

# Cria o objeto para normalizar e faz a normalizacao dos dados


Padronizador = MinMaxScaler()
dataset_atrib = Padronizador.fit_transform(dataset_atrib)

amostra1, amostra2 = train_test_split(dataset_atrib, train_size = .01)


pca = PCA(n_components = 2).fit_transform(amostra1)
k_range = range(1,12)
k_means_var = [KMeans(n_clusters = k).fit(pca) for k in k_range]
centroids = [X.cluster_centers_ for X in k_means_var]
k_euclid = [cdist(pca, cent, 'euclidean') for cent in centroids]
dist = [np.min(ke, axis = 1) for ke in k_euclid]
soma_quadrados_intra_cluster = [sum(d**2) for d in dist]
soma_total = sum(pdist(pca)**2)/pca.shape[0]
# Soma dos quadrados entre clusters
soma_quadrados_inter_cluster = soma_total - soma_quadrados_intra_cluster
# Criando um modelo com K = 8
modelo_v1 = KMeans(n_clusters = 8)
modelo_v1.fit(pca)
# Obtém os valores mínimos e máximos e organiza o shape
x_min, x_max = pca[:, 0].min() - 5, pca[:, 0].max() - 1
y_min, y_max = pca[:, 1].min() + 1, pca[:, 1].max() + 5
xx, yy = np.meshgrid(np.arange(x_min, x_max, .02), np.arange(y_min, y_max, .02))
Z = modelo_v1.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
# Silhouette Score
labels = modelo_v1.labels_
silhouette_score(pca, labels, metric = 'euclidean')
# Lista com nomes das colunas
names = ['Global_active_power', 'Global_reactive_power', 'Voltage', 'Global_intensi

# Cria o cluster map


cluster_map = pd.DataFrame(amostra1, columns = names)
cluster_map['Global_active_power'] = pd.to_numeric(cluster_map['Global_active_power
cluster_map['cluster'] = modelo_v1.labels_
cluster_map

localhost:8889/nbconvert/html/Clusterizacao.ipynb?download=false 9/10
22/02/2025, 17:50 Clusterizacao

Out[131]: Global_active_power Global_reactive_power Voltage Global_intensity Sub_metering_1 Su

0 0.113706 0.000000 0.619063 0.107884 0.011364

1 0.019736 0.000000 0.491438 0.029046 0.000000

2 0.016658 0.000000 0.745719 0.016598 0.000000

3 0.015571 0.113669 0.665267 0.020747 0.000000

4 0.167663 0.034532 0.470436 0.161826 0.000000

... ... ... ... ... ...

20487 0.017563 0.054676 0.589338 0.020747 0.000000

20488 0.055948 0.166906 0.680775 0.058091 0.000000

20489 0.081115 0.195683 0.602585 0.082988 0.000000

20490 0.033134 0.143885 0.586430 0.037344 0.000000

20491 0.138874 0.000000 0.487561 0.132780 0.011364

20492 rows × 8 columns

In [132… # Calcula da quantidade de observações por cluster


cluster_map.groupby('cluster')['Global_active_power'].count()

cluster
Out[132]:
0 4276
1 3639
2 9073
3 627
4 1750
5 536
6 417
7 174
Name: Global_active_power, dtype: int64

In [ ]:

In [ ]:

localhost:8889/nbconvert/html/Clusterizacao.ipynb?download=false 10/10

Você também pode gostar