본문 바로가기
Programming_Collective Intelligence/3.군집발견

구매 데이터를 활용한 사용자 군집화

by 볼록티 2019. 12. 29.
728x90
반응형

제 6회 엘포인트 데이터를 가지고 추천을 적용할 아이디어를 만들어 보기 위해 사용자 간의 구매패턴을 활용하여 유사 사용자 군집화를 공부해 보려고 한다. 데이터 분석에 이렇게 투자하고 그 가치를 널리 공유함에 있어서 기업들의 이런 활동들은 늘 감사할 따름이다...ㅠ

 

우선 주어진 데이터를 잘 병합하고, 분석하기 쉬운 형태로 변형시켜주도록 하겠다.

 

1. 사용할 데이터.

  우선 아래의 데이터는 온라인 행동 정보 데이터이다. 한단계 밑에 거래 정보 데이터의 BIZ_UNIT 과 비교해보면 A03이라는 카테고리로만 이루어져 있기 때문에 A03은 온라인을 나타내는 카테고리이며, 온라인 행동 정보 데이터의 가장 마지막 14번째 변수 기기유형을 통해 디바이스의 종류를 알 수 있다. 우선 사용자 군집화를 만들기 위한 것이 목적이고, 

특정 사용자가 구매한 상품들을 토대로 하여 각 사용자간의 유사도를 구할 것이므로 클라이언트 ID를 사용자 고유 넘버로 사용하고, 행동유형의 6.구매완료 인 사람들을 대상으로하여 거래정보데이터의 상품소분류코드를 통해 행렬을 만들어 볼 것이다.

굉장히 sparse한 행렬이 생성될 것으로 예상이 되기 때문에 결과보다는 하는 과정에 최대한 집중을 해 볼 생각이다.

온라인 행동 정보 데이터

 

 

거래정보 데이터

 

 

고객 정보

 

 

상품 분류 정보

 

 

 

온라인 구매 행동 데이터로는 바로 상품 분류 정보로 조인을 할 수 없으므로 거래정보 데이터를 활용하여 조인해야할 듯하다. PD_C변수를 활용하는 것이다. 

 조인하기 전에 분석의 편리성을 위해서 여러번에 나눠서 구매한 경우 그저 한번에 구매한 것으로 친다. 

 

 

온라인 구매 데이터에서 9번 고객의 구매완료한 2번의 경우는 한단계 아래의 표처럼 나누어져 있는데, 이를 전부 한번에 구매했다고 가정하였다.

 

 

분석용 데이터

 

 

 

#1. 구매 완료한 고객 아이디 추출
tmp=onl[onl['action_type']==6]


idx=tmp.drop_duplicates(['clnt_id'], keep='first')
client_id= list(idx['clnt_id']) # 구매 완료한 사람의 id


#2. 거래정보데이터에서 'A03' 인 것 & 구매 완료한 고객만 추출
tmp = tra[tra['biz_unit']=='A03']
idx = [True if i in client_id else False for i in tmp['clnt_id']]
tmp= tmp[idx]
tmp= tmp[tmp['pd_c'] != 'unknown']


#3. 상품번호를 상품이름으로 조인시켜서 보기좋게 만듬
tmp1 = pd.merge(tmp[['clnt_id','pd_c']], product[['pd_c','clac_nm3']], on='pd_c', how='left')


#4. 딕셔너리 형태로 만들어 줄거다.
anal = {}
# id를 딕셔너리의 키로 죽 만들어서 빈 리스트를 하나씩 갖고 있게 한다.
for i in list(set(tmp1['clnt_id'])):
    anal[i]=[]

# 연산을 위해 리스트로 따로 받아둠.
cid=list(tmp1['clnt_id'])
pname=list(tmp1['clac_nm3'])

# id당 아이템을 리스트로 묶어줌
for idx,item in zip(cid,pname):
    if item not in anal[idx]:
        anal[idx].append(item)



#5. 상품 x id 행렬로 만들어 준다.
result = []
prod= list(set(product['clac_nm3']))
for p in prod:
    x = []
    for idx in list(anal.keys()):
        if p in anal[idx]:
            x.append(1)
        else: 
            x.append(0)
    result.append(x)
    
#6. 열에 상품이름 붙여주고, id열 추가
prod =[str(i) for i in prod]

import numpy as np
y=np.array(result)
y=y.T
users= pd.DataFrame(y)
users.columns = prod
users['nan'] = pro_name
users.rename(columns={"nan":"id"}, inplace=True) # 불필요한 열에다가 id를 넣었음.
users.head()

 어째어째해서 아래의 결과처럼 행렬을 만들었고, 다만 아쉬운 것은 평점이나 개수로 하기에는 상당히 sparse 하므로 구매여부에 따라 이진 값으로 생각한다. 동시 구매 개수가 많을 수록 서로 유사하다고 생각한다.

 

 

우선 만들어 놓은 행렬('users')과 앞서 만든 딕셔너리('anal')를 사용해서 사용자 간의 동시 구매한 수량을 구한다.

사실 이 계산은 전치행렬과의 곱으로 바로 구할 수 있다. 

  행과 열의 수가 천단위라서 둘을 곱하면 계산량은 수백만이 되어서 사실 입력은 쉬운 반면 연산량이 많아 오래 걸릴 수 밖에 없다 ...

 

 

y라는 이미 만들어 놓은 array를 가지고 전치행렬과의 곱을 통해서 사용자 x 사용자 행렬을 만들었다. 사회연결망분석에서는 이를 1 -mode 네트워크라고 하며, 이진값일 경우 동시 출현 값으로 변환 시켜줄 수 있어 유용하게 사용될 수 있다.

coocurance=np.matmul(y,y.T)

co_df=pd.DataFrame(coocurance, index=pro_name)

co_df.columns = pro_name
co_df

굉장히 sparse할 줄 알았는데, 생각보다 dense한 느낌의 데이터프레임이라서 다행인 느낌이 좀 들었다.(전체를 다 본 것은 아니므로 일반화는 여기까지) 이제 이 행렬을 가지고 동시 구매 상품 개수가 많은 순으로 자신과 유사한 사용자를 리턴하는 함수를 만든다.

 

하지만 내가 군집에 사용할 알고리즘은 k-means 기법으로 1-mode가 아닌 2-mode 행렬에서 바로 진행이 가능하다.

 

 

 

from sklearn.cluster import KMeans

data_points= users.values
kmeans= KMeans(n_clusters=10).fit(data_points)

users['cluster_id'] = kmeans.labels_
users

 

아래의 그림이 길어서 짤렸지만 어찌됐건 내가 설정한 클러스터 10개에 대해서 클러스터링이 끝난 것을 알 수 있다.

아래의 결과는 군집당 들어있는 개체 수를 의미한다.

result['cluster_id'].value_counts()

군집당 실제로도 유사한지는 파악하지 않을거지만 우선 이런식으로 클러스터링을 진행해보니, 현업에서 의미부여와 도메인에 대한 지식이 너무나도 필요함을 절실히 느낀다 ... ㅠㅜ

 

 

 

 

 

 

 

 

728x90
반응형

댓글