본문 바로가기
데이터 분석 및 시각화

[ML] 연관규칙

by 바다의 공간 2024. 9. 13.

머신러닝 중 지도학습의 연관규칙입니다. 열대과일을 구매했으면 옆에 터키, 치즈, 포도 등등

어떤식으로 어떤 연관이 있는지 확인할 수 있습니다. 

각각의 연관도를 따질 수 있습니다 .(장바구니분석 이라고도 불림)

 

이 부분은 빅데이터분석기사(빅분기) 제 2과목에서도 나오는 항목이기에 좀 더 유심하게 봤습니다.

## 연관규칙 학습(Association Rule Learning)
* 연관 (Association): 서로 관련이 있다는 뜻
* 연관 규칙(Association Rule): 연관에 대한 규칙
* 연관 규칙 학습 (Learning): 머신러닝에서 연관규칙을 학습시킴
* 연관규칙을 한마디로 정의하면 동시에 발생한 사건(Transaction)들 간의 관계를 정의한 규칙

(1)연관규칙 관련 용어
    1) itemset(항목집합) : 항목들을 모음
    2) k-itemset(k-항목집합): k개의 항목직합  ex) 2-itemset: {기저귀:맥주}
    3) support (지지도) :  전체 경우의 수 중에서 두 아이템이 같이 나오는 비율
                         = 항목집합의 지지횟수 / 전체거래 데이터 수
        ex) {기저귀: 우유}
            {기저귀: 우유: 맥주}
            {우유: 맥주}
            {기저귀: 우유: 맥주}
            {기저귀}
            전체경우의 수 : 5개 에서 두 아이템({기저귀:우유})이 같이 나오는 비율
            =지지회수/거래회수(트랜잭션 수)
            = 3/5 = 0.6

   4) support count(지지회수) : 부분항목집합이 나타난 거래의 수 (위 예에서는 3)
   5) 빈발 항목집합 : 지정된 지지도 이상의 지지도를 갖는 항목집합
   6) confidence(신뢰도) : X가 나온 경우 중에서 X와 Y가 함게 나오는 비율
                          예) 위 예에서 '기저귀'가 나왔을때 '기저귀,우유'가 나올 비율
                             쉽계 얘기하면 기저귀를 샀을 때 우유도 같이 살 비율
   7) lift (향상도) : 동시에 두 사건이 발생할 비율
                     X와 Y가 같이 나오는 비율을 X가 나올 비율과 Y과 나올 비율의 곱으로 나눈 값
                     향상도가
                     1보다 높을때 positively correlation /긍정적 상관관계
                     1일때 independent / 독립적
                     1미만일때 negatively correlation / 부정적 상관관계

(2) 쇼핑데이터 예시
    거래번호            구매항목
    -------------------------------------------
    T1                  빵, 우유
    T2                  기저귀, 달걀, 맥주, 빵
    T3                  기저기, 맥주, 우유, 콜라
    T4                  기저귀, 맥주, 빵, 우유
    T5                  기저귀, 빵, 우유, 콜라
     -------------------------------------------


(3) 알고리즘
- apriori 알고리즘
    1) 대표적인 연관규칙학습 알고리즘
    2) 빈발항목들을 선택하고 그 중 신뢰도(confidence)가 높은 연관규칙 생성
    3) 빈발항목집합들을 점진적으로 생성해나감

(4) 연관규칙학습 사용 예시
    소비자 구매행동패턴 분석, 상품 추천, 신용카드 사기 탐지, 웹 사용자 행동 분석 등등 추천시스템에서 굉장히 많이 사용

(5) 연관규칙학습 구현 주요 단계
    1) 데이터 수집 :  거래데이터, 로그데이터 수집, 항목들의 집합을 구성
    2) 데이터 전처리: 중복된 항목들을 제거, 불필요한 정보들을 정리, 데이터들을 트랜잭션 형태로 정리
    3) 항목집합 생성: 각 트랜잭션에서 어떤 항목들이 함께 발생하는지 파악, 연관성 파악
    4) 연관규칙 탐색 :  Apriori 알고리즘 등을 활용해 연관규칙 탐색
                      빈도수 기반으로 연관성을 계산
                       불필요한 규칙 제거
                       중요한 규칙을 강조하기 위한 후처리 작업 수행
    5) 규칙평가 : 지지도, 신뢰도, 향상도 등의 지표를 사용해서 규칙을 평가
    6) 결과 해석 및 활용 :  찾아낸 연관규칙을 해석, 실제 업무에 적용
    7) 주기적 업데이트 : 데이터가 변경 또는 추가될 때 주기적으로 업데이트
                       연관성을 최신상태로 유지

 

코드실습
파일명 : association.py
## association.py
## 연관규칙 학습 (Association Rule Learning)

def p(str):
    print(str, '\n')

# mlxtend 라이브러리 설치

# 라이브러리 로딩
import mlxtend
import numpy as np
import pandas as pd
from mlxtend.preprocessing import TransactionEncoder
from mlxtend.frequent_patterns import apriori
from mlxtend.frequent_patterns import association_rules

# itemset
# 리스트를 넘파이 배열로
data = np.array([
    ['우유', '기저귀', '쥬스', ''],
    ['상추', '기저귀', '맥주', ''],
    ['우유', '양상치', '기저귀', '맥주'],
    ['양상치', '맥주', '', '']
])

# 트랜잭션 인코더
te = TransactionEncoder()

# 데이터 학습 후 변환
te_array = te.fit(data).transform(data)

# 데이터프레임으로 변환
df = pd.DataFrame(te_array, columns=te.columns_)
#p(df)

# 지지도, 신뢰도 설정
min_support_per = 0.5 # 최소 지지도 설정 (기본 0.5)
min_threshold_per = 0.5 # 최소 신뢰도 (기본 0.8)

# apriori 알고리즘 적용
result = apriori(
    df, # 데이터프레임
    min_support=min_support_per, # 최소 지지도
    use_colnames=True # 컬럼명 사용여부
)

# 연관규칙 생성
result_rules = association_rules(
    result, # 알고리즘 적용 결과
    metric='confidence', # 신뢰도
    min_threshold=min_threshold_per # 최소 신뢰도
)

#p(result_rules)
#p(result_rules['support']) # 지지도
#p(result_rules['confidence']) # 신뢰도

 


코드실습
파일명 : association_chipotle.py

 

## association_chipotle.py
import matplotlib.pyplot as plt


## 연관규칙 학습

def p(str):
    print(str, '\n')


#라이브러리 로딩
import pandas as pd
from mlxtend import frequent_patterns
from mlxtend import preprocessing

#데이터프레임
df = pd.read_csv('../assets/chipotle.csv')
df.info()

#chipotle.csv 데이터 구성
'''
order_id  주문번호
quantity : 수량
item_name : 아이템명
choice_description: 선택옵션
item_price : 아이템가격
'''

# 연관분석 함수를 사용하기 위해 리스트로 변환
df_temp =df[['order_id', 'item_name']]
# p(df_temp)
df_temp_arr = [[] for i in range(1835)]
# p(df_temp_arr)
num = 0
for i in df_temp['item_name']:
    df_temp_arr[df_temp['order_id'][num]].append(i)
    num += 1
p(df_temp_arr)

# order_id 는 1부터 시작하므로 빈값 제거
#그러면 [] 이 값이 제거됨
df_temp_arr.pop(0)
# p(df_temp_arr)

# set으로 중복값을 제거 후 list로 반환
num = 0
for i in df_temp_arr:
    df_temp_arr[num] = list(set(df_temp_arr[num]))
    num += 1

p(df_temp_arr)


#uniqe한 아이템명
p(df['item_name'].unique())

# 트랜잭션 인코더 생성
te = preprocessing.TransactionEncoder()

#학습시키고 변환
te_arr = te.fit(df_temp_arr).transform(df_temp_arr)
p(te_arr) #T와 F로 변환

# 변환된 이진행렬을 데이터프레임으로 변환 후
# 각 열의 이름을 아이템명으로 설정함
df1 = pd.DataFrame(te_arr, columns=te.columns_)
p(df1) #50개
df1.info()

#정규표현식 라이브러리
import re

#경고 무시
import warnings
warnings.filterwarnings('ignore')

#csv파일을 보면 아이템가격의 $가 있는데 $를 없애보려고 함
#1) 정규표현식
num = 0
for i in df['item_price']:
    df['item_price'][num] = re.sub(pattern='[$]', repl=' ',string=i)
    num += 1

# p(df['item_price'])

#2) 람다(lambda)함수 반복
#apply : 앞에있는것 하나하나에 뒤에 있는 람다함수를 적용
df['item_price'] = df['item_price'].apply(lambda x:x.lstrip('$'))
p(df)

# 아이템가격을 float로 변환
df['item_price'] = df['item_price'].astype(float)
p(df['item_price'].sum())

#null인 것의 합계
# p(df.isnull().sum())
#choice_description    1246개

#null인것들은 'default'로 채움
df['choice_description'] = df['choice_description'].fillna('default')
p(df.isnull().sum())

#알파벳과 쉼표를 제외한 모든 문자 제거
num = 0
for i in df['choice_description']:
    df['choice_description'][num]\
        = re.sub(pattern='[^a-zA-Z,]', repl='', string=i)
    num += 1

# p(df['choice_description'])

# 아이템명과 선택옵션의 값의 수를 시리즈로 변경
result = df.groupby(['item_name','choice_description']).value_counts()
p(result)

# 시리즈의 인덱스로 리스트변환
temp_index = result.index.tolist()
# p(temp_index)

# 시리즈의 값들을 리스트 변환
temp_values = result.values.tolist()
# p(temp_values)

# #시각화
# import matplotlib.pyplot as plt
# plt.figure(figsize=(16, 8))
# x= df['item_name']
# y= df['quantity']
# plt.bar(x,y)
# plt.xticks(rotation=45)
# plt.show()

# 중복된 아이템 제거하고 판매량 합게 계산
# p(df.groupby('item_name')['quantity'].sum())

# 가장 많이 팔린 메뉴 중 10개 막대그래프로 그리기
top_items = df.groupby('item_name')['quantity'].sum().sort_values(ascending=False).head(10)
p(top_items)

#nlargest함수(가장 큰 값을 가지는 아이템 추출) 사용해서 상위 10개 아이템 추출
top_items = df.groupby('item_name')['quantity'].sum().nlargest(10)
# p(top_items)

# #막대그래프
# plt.figure(figsize=(10,6))
# top_items.plot(kind='bar')
# plt.xlabel('item_name')
# plt.ylabel('quantity')
# plt.show()

#연관학습 라이브러리
from mlxtend.frequent_patterns import apriori
from mlxtend.frequent_patterns import association_rules

#그룹핑 후 확인
#unstack : 인덱스 값을 컬럼으로 사용
df_grouped = df.groupby(['order_id', 'item_name'])['quantity']\
            .sum().unstack().reset_index()
# p(df_grouped)

#판매량이 1이상인 경우 1로 변경
df_group = df_grouped.applymap(lambda x:1 if x>=1 else 0)
# p(df_group)

#apriori 알고리즘을 사용해 연관규칙 학습
frequent = apriori(
    df_group.drop('order_id', axis=1), #데이터프레임
    min_support=0.01, #최소 지지율
    use_colnames=True #컬럼명 사용여부
)

# 연관규칙 추출
# lift : 향상도(규칙이 얼마나 의미있는지?)
rules = association_rules(
    frequent,
    metric='lift',
    min_threshold=1.0
)
# p(rules)

# 최종적으로는 <연관학습 결과>를 알아야 함
# p(rules['support'])
p(rules['confidence'])

 


이미지 시각화 변환


여기서 조금 난이도가 있었던 부분은 for문으로

# 연관분석 함수를 사용하기 위해 리스트로 변환
df_temp =df[['order_id', 'item_name']]
# p(df_temp)
df_temp_arr = [[] for i in range(1835)]
# p(df_temp_arr)
num = 0
for i in df_temp['item_name']:
    df_temp_arr[df_temp['order_id'][num]].append(i)
    num += 1
p(df_temp_arr)

이 부분입니다. 결과는 아래와 같습니다.

값들이 너무 많이 나와서 
[[], ['Chips and Fresh Tomato Salsa', 'Izze', 'Nantucket Nectar',  이런식으로 리스트에 넣어지게 됩니다.

이 부분에서는 중복된 셀이 다 들어가게됩니다. 이후 중복된 셀을 없애기 위해서는 set을 사용해서 중복된 값을 제거해주었습니다.

# set으로 중복값을 제거 후 list로 반환
num = 0
for i in df_temp_arr:
    df_temp_arr[num] = list(set(df_temp_arr[num]))
    num += 1

p(df_temp_arr)