1. 들어가면서
- Clustering은 비지도 학습에서 많이 쓰는 방법이다. 다만 모든 특성이 Numerical할때 사용하기가 편하다. 왜냐하면 서로의 평균과 거리를 통해서 클러스터링을 하기 때문이다.
- 그래서 Categorical Feature에는 사용하기 어려운게 사실이다.
- Categorical과 Numerical Feature가 있는 Data 일때는 어떤 방식으로 Clustering을 할까? (Clustering : 데이터를 유사한 집단으로 나누는것)
- 해당 내용은 아래의 출처를 보고 작성한 내용입니다.
- 출처 : URL https://towardsdatascience.com/clustering-on-numerical-and-categorical-features-6e0ebcf1cbad
2. Gower Distance
- 만일 결혼이라는 Feature에 미혼, 기혼, 이혼이라는 특성이 있다고 한다면 이는 1[미혼], 2[기혼], 3[이혼]으로 Label Encoding을 할수 있다.
- 하지만 이혼이 기혼보다 싱글이 더 유사하다고는 할수 없습니다.(3[이혼] - 기혼[2] = 1, 3[이혼] - 1[미혼] = 2) 1이 2보다 더 이혼과 미혼, 기혼의 거리를 이야기하기는 이상합니다.
- 여기서 Gower Distance(GD, 1 - Gower Similarity, GS)의 개념이 나옵니다. Gower Similarity는 관측치 i와 j간의 유사성을 계산하기 위해 m개 특성에 대한 부분 유사성의 평균으로 계산됩니다.
3. Partial Similarities
- Partial Similarities(PS)는 Numerical과 Categorical에 따라 계산이 다릅니다.
- Numerical은 1에서 두 데이터i와 j 사이의 유사성 부분을 뺀 절대값에 Feature의 범위를 나눠준 값을 뺀것입니다.
- Categorical은 모든 특성에 대해 정확히 같은 값을 가질 경우에만 1입니다. 그렇지 않으면 0입니다.
- Partial Similarities는 항상 0~1사이의 값을 가집니다. 0은 완전히 유사하지 않고 1은 완전히 유사하다는 것을 의미합니다.
- 이러한 결과 떄문에 Categorical Feature와 Numerical Feature가 혼합되어 있을때 Clustering을 할수 있습니다.
4. Gower Distance의 수학적 특성
- Gower Distance(GD)와 Gower Similarity는 유클리드 기하학을 따르지 않는 거리를 사용하기 떄문에 아래의 유클리드 거리를 기반으로하는 Clustering은 사용하지 않습니다.
- K-means
- Ward ‘s, centroid, median method of hierarchical clustering
5. Gower Distance using Python
1
2
3
4
5
6
7
8
9
10
11
12
13
import pandas as pd
# Creating a dictionary with the data
dictionary = {"age": [22, 25, 30, 38, 42, 47, 55, 62, 61, 90],
"gender": ["M", "M", "F", "F", "F", "M", "M", "M", "M", "M"],
"civil_status": ["SINGLE", "SINGLE", "SINGLE", "MARRIED", "MARRIED", "SINGLE", "MARRIED", "DIVORCED", "MARRIED", "DIVORCED"],
"salary": [18000, 23000, 27000, 32000, 34000, 20000, 40000, 42000, 25000, 70000],
"has_children": [False, False, False, True, True, False, False, False, False, True],
"purchaser_type": ["LOW_PURCHASER", "LOW_PURCHASER", "LOW_PURCHASER", "HEAVY_PURCHASER", "HEAVY_PURCHASER", "LOW_PURCHASER", "MEDIUM_PURCHASER", "MEDIUM_PURCHASER", "MEDIUM_PURCHASER", "LOW_PURCHASER"]}
# Creating a Pandas DataFrame from the dictionary
dataframe = pd.DataFrame.from_dict(dictionary)
dataframe
age | gender | civil_status | salary | has_children | purchaser_type | |
---|---|---|---|---|---|---|
0 | 22 | M | SINGLE | 18000 | False | LOW_PURCHASER |
1 | 25 | M | SINGLE | 23000 | False | LOW_PURCHASER |
2 | 30 | F | SINGLE | 27000 | False | LOW_PURCHASER |
3 | 38 | F | MARRIED | 32000 | True | HEAVY_PURCHASER |
4 | 42 | F | MARRIED | 34000 | True | HEAVY_PURCHASER |
5 | 47 | M | SINGLE | 20000 | False | LOW_PURCHASER |
6 | 55 | M | MARRIED | 40000 | False | MEDIUM_PURCHASER |
7 | 62 | M | DIVORCED | 42000 | False | MEDIUM_PURCHASER |
8 | 61 | M | MARRIED | 25000 | False | MEDIUM_PURCHASER |
9 | 90 | M | DIVORCED | 70000 | True | LOW_PURCHASER |
- 임의의 고객 데이터를 만들었습니다. 해당 데이터로 Gower Distance를 계산해보겠습니다.
- 해당 데이터는 총 10명의 고객이 있고 6개의 Feature로 이루어져 있습니다.
- Age(나이): Numerical
- Gender(성별): Categorical
- Civil Status(결혼 상태): Categorical
- Salary(연봉): Numerical
- Does the client have children?(아이의 유무): Binary
- Purchaser Type(구매자 유형): Categorical
1
2
3
4
5
6
7
8
data = {'age':[22, 25, '|22-25|/86', 0.44117647],
'gender' : ['M', 'M', '-', 0],
'civil_status' : ['SINGLE', 'SINGLE', '-', 0],
'salary' : [18000, 23000, '|18000-23000|/52000', 0.096153846],
'has_children' : [False, False, '-', 0],
'purchaser_type' : ['LOW_PURCHASER', 'LOW_PURCHASER', '-', 0]
}
pd.DataFrame(data, index = ['Customer_1', 'Customer_2', 'Partial Dissimilarity - Calculation', 'Partial Dissimilarity - Value'])
age | gender | civil_status | salary | has_children | purchaser_type | |
---|---|---|---|---|---|---|
Customer_1 | 22 | M | SINGLE | 18000 | False | LOW_PURCHASER |
Customer_2 | 25 | M | SINGLE | 23000 | False | LOW_PURCHASER |
Partial Dissimilarity - Calculation | |22-25|/86 | - | - | |18000-23000|/52000 | - | - |
Partial Dissimilarity - Value | 0.441176 | 0 | 0 | 0.0961538 | 0 | 0 |
- Numerical feature는 두 고객 i와 j의 Partial Dissmilarity에서 구한다. salary는 max인 70000과 min인 18000을 뺀 범위로 나누어준다. age도 마찬가지이다.
- Categorical feature는 두 고객 i와 j의 일치한것을 보고 찾는다. 일치하면 0 아니면 1으로 구성된다.
- civil_status, has_children, purchaser_type 모두 일치하기 때문에 0으로 된다.
- Gower Dissimilarity는 모든 Feature의 평균으로 구합니다. 여기서는 (0.441176 + 0 + 0 + 0.0961538 + 0 + 0) / 6 = 0.023379 입니다.
1
2
3
4
5
6
# !pip install gower
import gower
distance_matrix = gower.gower_matrix(dataframe)
columns = [f'Customer_{i}' for i in range(1,11)]
distance_matrix = pd.DataFrame(distance_matrix, index=columns, columns=columns)
- 위의 계산 방식을 기반으로 gower를 사용하여 모든 고객들의 GD를 구하였습니다.
6. Clustering using DBSCAN
1
2
3
4
5
6
7
8
9
10
11
12
13
from sklearn.cluster import DBSCAN
# Configuring the parameters of the clustering algorithm
dbscan_cluster = DBSCAN(eps=0.3,
min_samples=2,
metric="precomputed")
# Fitting the clustering algorithm
dbscan_cluster.fit(distance_matrix)
# Adding the results to a new column in the dataframe
dataframe["cluster"] = dbscan_cluster.labels_
dataframe
age | gender | civil_status | salary | has_children | purchaser_type | cluster | |
---|---|---|---|---|---|---|---|
0 | 22 | M | SINGLE | 18000 | False | LOW_PURCHASER | 0 |
1 | 25 | M | SINGLE | 23000 | False | LOW_PURCHASER | 0 |
2 | 30 | F | SINGLE | 27000 | False | LOW_PURCHASER | 0 |
3 | 38 | F | MARRIED | 32000 | True | HEAVY_PURCHASER | 1 |
4 | 42 | F | MARRIED | 34000 | True | HEAVY_PURCHASER | 1 |
5 | 47 | M | SINGLE | 20000 | False | LOW_PURCHASER | 0 |
6 | 55 | M | MARRIED | 40000 | False | MEDIUM_PURCHASER | 2 |
7 | 62 | M | DIVORCED | 42000 | False | MEDIUM_PURCHASER | 2 |
8 | 61 | M | MARRIED | 25000 | False | MEDIUM_PURCHASER | 2 |
9 | 90 | M | DIVORCED | 70000 | True | LOW_PURCHASER | -1 |
- Sklearn의 DBSCAN을 사용하여 Clustering을 하였습니다.
- Gower Distance를 사용하면 K-means의 알고리즘을 사용할수 없기 때문에 DBSCAN을 사용하였습니다.
DBSCAN이란 밀도 기반의 클러스터링으로, 점이 세밀하게 몰려 있어서 밀도가 높은 부분을 클러스터링 하는 방식으로 어느점을 기준으로 반경 x내에 점이 n개 이상 있으면 하나의 군집으로 인식하는 방식입니다.
- Cluster 0 : 고객들의 연봉이 18,000과 27,000이고 아이가 없으며 자주 구매하지 않는 구매자 유형
- Cluster 1 : 고객들의 연봉이 33,000이고 아이가 있으며 나이는 약 40대의 여성
- Cluster 2 : 60대 남성이며 아이가 없고 자주 구매하는 구매자
- Cluster -1: 어떤 군집에도 포함되지 않는 아웃라이어
7. 결론 및 회고
- 일단 Clustering은 비지도학습이라 지도학습보다 어려운것이 사실입니다.
- 또한 K-means와 같은 일반적인 Clustering 알고리즘은 대부분 수치형 데이터에만 사용하기가 쉽습니다.
- 하지만 Gower Distance를 Python으로 간단하게 구현할수 있음을 알게 된것을 좋게 생각합니다/
- 나중에 실무에서 Clustering을 하게 된다면 분명 이처럼 Data type이 섞여있을텐데 그때 좋은 예제가 된듯 합니다.