3 분 소요

본 게시물은 연관분석에 대해 소개한다.

1. Run-Test

1.1 Concept

연관규칙을 찾기 전, 연속적인 binary 관측 값들이 임의적으로 나타난 값인지 임의적이 아닌지(=연관이 있는지)를 먼저 검정하는 기법

  • H0: 연속적인 관측값이 임의적이다.
  • H1: 연속적인 관측값이 임의적이 아니다. (=연관이 있다.)

1.2 Parameters

runstest_1samp(x, cutoff=mean, correction=True)
  • x: 2개의 관측값으로 이루어진 binary data (관측값은 정수)
  • cutoff: data를 큰 값과 작은 값으로 나누기 위한 기준
  • correction: 50 미만의 샘플사이즈일 경우 사건이 일어날 확률을 정의하기 어려우므로 0.5로 할당

1.3 Returns

  • z-stat: 정규분포를 사용하므로 z 통계량 사용
  • p-value

1.4 Implementation

import pandas as pd 
data = ['a','a','b','b','a','a','a','a','b','b','b','b','b','a','a','b','b','a','b','b']
test_df = pd.DataFrame(data,columns=["product"])
test_df.head()

from statsmodels.sandbox.stats.runs import runstest_1samp
#Run-test를 위한 데이터 변환 
test_df.loc[test_df['product']=='a','product'] =1
test_df.loc[test_df['product']=='b','product'] =0
#Perform Runs test
# - run-test의 귀무가설 : 연속적인 관측값이 임의적이다. 
# - run-test의 대립가설 : 연속적인 관측값이 임의적이 아니다.
runstest_1samp(test_df['product'],cutoff =0.5 , correction=True)
(-1.1144881152070183, 0.26506984027306035)

2. Association analysis

2.1 Concept

사건의 연관규칙을 찾는 방법으로, A 후에 B라는 사건을 시행할 확률을 구함

  • 장바구니 분석: 장바구니에 무엇이 같이 들어갈 것인지 분석
  • 서열분석: A를 산 다음에 B를 살 것

2.2 Metric

  1. 지지도
    • 전체 거래 중 항목 A와 B를 동시에 포함하는 거래의 비율
    • A와 B가 동시에 포함된 거래수 / 전체 거래수
  2. 신뢰도
    • 항목 A를 포함한느 거래 중에서 항목 A와 항목 B가 같이 포함될 확률로 연관성 정도 파악
    • A와 B가 동시에 포함된 거래수 / A를 포함하는 거래수
  3. 향상도
    • A가 구매되지 않았을 때 품목 B의 구매 확률에 비해 A가 구매되었을 때 품목 B의 구매 확률 증가비
      • 품목 A와 B의 구매가 서로 관련이 없는 경우에 향상도가 1
    • A와 B가 동시에 포함된 거래수 / A를 포함하는 거래수 * B를 포함하는 거래수

2.3 Aprori Algorithm

가능한 모든 경우의 수를 탐색하여 지지도, 신뢰도, 향상도가 높은 규칙들을 찾아내는 방식

  1. 아이템이 n개일 때, 탐색해야 할 모든 경우의 수: n*(n-1)
    • 빈발집합: 최소 지지도보다 큰 지지도 값을 갖는 품목의 집합
  2. 계산방법
    • 모든 품목 집합에 대한 지지도를 전부 계산하는 것이 아님
    • 최소 지지도 이상의 빈발항목을 찾은 후 그것들에 대해서만 연관규칙 계산
  3. 장단점
    • 장점: 구현과 이해가 쉬움
    • 단점: 아이템의 개수가 많아지면 계산 복잡도가 증가

2.4 Parameters

  1. apriori

    from mlxtend.frequent_patterns import apriori
    
    • df: 값이 0/1 또는 T/F인 dataframe
    • min_support: 최소 지지도
    • use_colnames: True이면 열 인덱스 대신 반환된 DataFrame의 열 이름을 사용
    • max_len: 생성된 항목 세트의 최대 길이로 None인 경우 모든 항목 세트 길이를 평가
    • low_memory: 메모리 리소스가 제한된 경우에 사용, 속도가 느림
  2. association_rules

    from mlxtend.frequent_patterns import association_rules
    association_rules(df, metric=confidence, min_threshold=0.8, support_only=False)
    
    • df: 값이 0/1 또는 T/F인 dataframe
    • metric: support_only=True인 경우 자동으로 support로 설정
    • min_threshold: metric에 지정된 rule의 최소값
    • support_only: support만 계산하고 다른 메트릭의 열을 NaN으로 출력

2.5 Implementation1

import pandas as pd
from mlxtend.preprocessing import TransactionEncoder
dataset = [['Apple', 'Beer', 'Rice', 'Chicken'],
 ['Apple', 'Beer', 'Rice'],
 ['Apple', 'Beer'],
 ['Apple', 'Bananas'],
 ['Milk', 'Beer', 'Rice', 'Chicken'],
 ['Milk', 'Beer', 'Rice'],
 ['Milk', 'Beer'],
 ['Apple', 'Bananas']]
te = TransactionEncoder()
te_ary = te.fit_transform(dataset)
print(te.columns_)
te_ary
['Apple', 'Bananas', 'Beer', 'Chicken', 'Milk', 'Rice']
array([[ True, False,  True,  True, False,  True],
       [ True, False,  True, False, False,  True],
       [ True, False,  True, False, False, False],
       [ True,  True, False, False, False, False],
       [False, False,  True,  True,  True,  True],
       [False, False,  True, False,  True,  True],
       [False, False,  True, False,  True, False],
       [ True,  True, False, False, False, False]])
  • TransactionEncoder를 통해 데이터세트를 트랜잭션 형태로 변경
    • 원본 데이터의 unique 값을 컬럼으로 지정하고 True/False로 변환
df = pd.DataFrame(te_ary,columns = te.columns_)
df

## 지지도 60% 이상인 품목만 추출 
from mlxtend.frequent_patterns import apriori
apriori(df, min_support=0.6, use_colnames=True)

  • 최소 지지도가 0.6 이상인 품목
## 규칙의 길이를 추출하는 방법 
frequent_itemsets = apriori(df, min_support=0.3, use_colnames=True)
frequent_itemsets['length'] = frequent_itemsets['itemsets'].apply(lambda x: len(x))
frequent_itemsets

  • 최소 지지도가 0.3 이상인 규칙만 추출하고 규칙의 길이 파악

2.6 Implementation2

df= pd.read_csv("https://raw.githubusercontent.com/ADPclass/ADP_book_ver01/main/data/groceries.csv",)
df

df_split = df.iloc[:,0].str.split(',',expand=True)
df_split.values
array([['tropical fruit', 'yogurt', 'coffee', ..., None, None, None],
       ['whole milk', None, None, ..., None, None, None],
       ['pip fruit', 'yogurt', 'cream cheese', ..., None, None, None],
       ...,
       ['chicken', 'citrus fruit', 'other vegetables', ..., None, None,
        None],
       ['semi-finished bread', 'bottled water', 'soda', ..., None, None,
        None],
       ['chicken', 'tropical fruit', 'other vegetables', ..., None, None,
        None]], dtype=object)
  • 전처리
df_split_ary = df_split.values
groceries = []
for i in range(len(df_split_ary)) : 
  temp = list(filter(None,df_split_ary[i]))
  groceries.append(temp)
 
groceries
[['tropical fruit', 'yogurt', 'coffee'],
 ['whole milk'],
 ['pip fruit', 'yogurt', 'cream cheese', 'meat spreads'],
 ['other vegetables',
  'whole milk',
  'condensed milk',
  'long life bakery product'],
 ...]
  • None을 지우고 트랜잭션 형태로 바꿈
from mlxtend.preprocessing import TransactionEncoder
import pandas as pd
te = TransactionEncoder()
groceries_tr = te.fit(groceries).transform(groceries)
groceries_tr = pd.DataFrame(groceries_tr, columns=te.columns_)
groceries_tr

from mlxtend.frequent_patterns import apriori
# 지지도가 5% 이상인 빈번항목집합 탐색
groceries_ap = apriori(groceries_tr, min_support=0.01, 
 use_colnames=True)
groceries_ap

  • 지지도가 5% 이상인 빈번항목 집합
from mlxtend.frequent_patterns import association_rules
# 신뢰도가 0.3 이상인 빈번항목집합 탐색
association_rules(groceries_ap, metric="confidence", min_threshold=0.3)

  • assoication_rules를 통해 규칙 파악
rules = association_rules(groceries_ap, metric="lift", min_threshold=1)
# 규칙의 길이 컬럼 생성 
rules["antecedent_len"] = rules["antecedents"].apply(lambda x: len(x))
rules[ (rules['antecedent_len'] >=2) &
       (rules['confidence'] >=0.4) &
       (rules['lift'] >=3) ]

  • 규칙 길이가 2 이상, 신뢰도가 0.4 이상, 향상도가 3이상인 규칙 추출

댓글남기기