본문 바로가기

Study/class note

머신러닝 / 파이썬으로 연관규칙 모델 구현하기

ㅇ연관규칙이 필요한 이유 > 유튜브 알고리즘을 연상하면 편함

두 아이템간의 연관성을 확인하는 척도

1. 지지도 : 해당 아이템이 전체 거래건수 중에서 얼마나 자주 나타나는지 빈도수(frequency)

> 아이템에 대한 확률을 구하면 됨

> 아이템이 하나일 경우 하나의 확률, 두개 이상일 경우 결합확률을 구하면 됨(X와 Y가 동시에 일어날 확률 = 교집합)

 

2. 신뢰도 : X라는 상품을 샀을 때 Y상품을 살 조건부 확률

> 신뢰도의 범위는 0 ~ 1

 

3. 향상도 : 규칙이 우연에 의해 발생한 것인지 아닌지를 판단하는 연관성 정도의 척도

= X와 Y를 모두 포함하는 거래건수 / (X를 포함하는 거래건수 * Y를 포함하는 거래건수)

> 범위는 0 ~ 무한대

 

 

75 파이썬으로 연관규칙 모델 구현하기

#1. 프롬프터를 통해 mlxtend 패키지 설치

pip install mlxtend

#2. 데이터 로드

#3. 필요한 패키지 로드

#4. 연관규칙 데이터 분석을 위한 데이터 전처리

#5. 출력된 결과를 데이터 프레임으로 만듦

#6. 지지도가  0.5이상인것만 출력

#7. 신뢰도와 향상도도 같이 출력

#2. 데이터 로드
dataset = [['사과', '치즈','생수'],
           ['생수', '호두','치즈','고등어'],
           ['수박','사과','생수'],
           ['생수','호두','치즈','옥수수']]

#3. 필요한 패키지 로드
import pandas as pd
from mlxtend.preprocessing import TransactionEncoder #연관분석을 위한 데이터 전처리 모듈
from mlxtend.frequent_patterns import apriori  #연관분석 모듈

#4. 연관규칙 데이터 분석을 위한 데이터 전처리
te = TransactionEncoder()  #데이터 전처리 클래스를 객체화 시킴
te_ary = te.fit_transform(dataset)  #계산된 내용 변환하여 변수에 넣음
te_ary

#5. 출력된 결과를 데이터 프레임으로 만듦
df = pd.DataFrame(te_ary, columns = te.columns_)
df

#6. 지지도가  0.5이상인것만 출력
apriori(df, min_support = 0.5, use_colnames = True)

#7. 신뢰도와 향상도도 같이 출력
a = apriori(df, min_support = 0.5, use_colnames = True)

from mlxtend.frequent_patterns import association_rules
association_rules(a, metric = "confidence", min_threshold = 0.7)  # 신뢰도 0.7이상만 출력

> leverage(사과→생수) : 사과와 생수가 얼마나 자주 나타나는지 빈도를 관찰해 둘 사이의 차이를 계산하여 사과와 생수가 서로 얼마나 독립적인지를 나타내는 척도. 이 값이 0이면 서로 독립

leverage(사과→생수) = support(사과→생수) - support(사과)*support(생수)

범위 : -1 ~ 1

 

> conviction(사과→생수) : 높은 conviction값은 선행품목과 연관품목이 서로 매우 의존적이다라는 것을 의미함

conviction(사과→생수) = (1-support(생수)) / (1-confidence(사과→생수))

위의 식에서 분모가 0이 되면 conviction의 값이 무한대(inf)로 표시

범위 : 0 ~ 무한대

 

참고사이트)

http://rasbt.github.io/mlxtend/user_guide/frequent_patterns/association_rules/

 

 

문제371. 위에서 분석한 연관규칙의 결과를 다시 출력하는데 이번에는 신뢰도가 아니라 향상도가 1.2이상만 출력되게 하시오.

a = apriori(df, min_support = 0.5, use_colnames = True)

from mlxtend.frequent_patterns import association_rules
association_rules(a, metric = "lift", min_threshold = 1.2)

문제372. 위의 결과를 다시 출력하는데 confidence를 기준으로 정렬해서 출력하시오.

a = apriori(df, min_support = 0.5, use_colnames = True)

from mlxtend.frequent_patterns import association_rules
rules = association_rules(a, metric = "lift", min_threshold = 1.2)  
rules.sort_values(by = 'confidence', ascending = False)

> R에서는 R패키지가 정렬을 해줬는데 파이썬은 직접 정렬을 해줘야함.

 

문제373. 지지도가 0.3이상인 연관규칙들을 출력하시오.

a = apriori(df, min_support = 0.3, use_colnames = True)

from mlxtend.frequent_patterns import association_rules
rules = association_rules(a, metric = "support", min_threshold = 0.3)  
rules

 

문제374. 위의 결과를 다시 정렬해서 출력하는데 신뢰도가 높은 것부터 출력되게 하시오.

a = apriori(df, min_support = 0.3, use_colnames = True)

from mlxtend.frequent_patterns import association_rules
rules = association_rules(a, metric = "support", min_threshold = 0.3)  
rules.sort_values(by = 'confidence', ascending = False)

 

문제375. 다음의 리스트를 연관규칙을 하기 위한 데이터 전처리를 하고, 판다스 데이터 프레임으로 생성하시오.

import pandas as pd
from mlxtend.preprocessing import TransactionEncoder #연관분석을 위한 데이터 전처리 모듈
from mlxtend.frequent_patterns import apriori  #연관분석 모듈
from mlxtend.frequent_patterns import association_rules


dataset = [['우유', '양파', '육두구', '강낭콩', '계란', '요구르트'],
           ['딜', '양파', '육두구', '강낭콩', '계란', '요구르트'],
           ['우유', '사과', '강낭콩', '계란'],
           ['우유', '유니콘', '옥수수', '강낭콩', '요구르트'],
           ['옥수수', '양파', '양파', '강낭콩', '아이스크림', '계란'] ]

encd = TransactionEncoder()
pre = encd.fit_transform(dataset)

df = pd.DataFrame(pre, columns = encd.columns_)
df

문제376. 위에서 전처리한 데이터를 가지고 연관분석을 하는데 가장 연관성이 높은 품목이 서로 어떻게 되는지 지지도 0.6이상, 신뢰도 0.7이상인 품목들을 출력하시오.

a = apriori(df, min_support = 0.6, use_colnames = True)
rules = association_rules(a, metric = "confidence", min_threshold = 0.7)  
rules

문제377. 위의 결과를 신뢰도가 높은것부터 출력하시오.

a = apriori(df, min_support = 0.6, use_colnames = True)
rules = association_rules(a, metric = "confidence", min_threshold = 0.7)  
rules.sort_values(by = ['support','confidence'], ascending = False)

> 지지도가 높은순으로 먼저 정렬하고 그 다음 신뢰도가 높은 순으로 정렬함

 

문제378. 위의 결과에서 향상도가 1.2이상인것만 출력하시오.

a = apriori(df, min_support = 0.6, use_colnames = True)
rules = association_rules(a, metric = "confidence", min_threshold = 0.7)  
rules2 = rules.sort_values(by = ['support','confidence'], ascending = False)  
rules2[:][rules2.lift >= 1.2]

문제379. 위의 결과에서 선행아이템(antecedents)이 2개인것만 출력하시오.

rules2[:][rules2.antecedents.apply(lambda x: len(x) == 2)]

 

 

- 보습학원 데이터(building.csv)를 파이썬의 apriori 알고리즘으로 연관분석하기 

 

import pandas as pd
from mlxtend.preprocessing import TransactionEncoder #연관분석을 위한 데이터 전처리 모듈
from mlxtend.frequent_patterns import apriori  #연관분석 모듈
from mlxtend.frequent_patterns import association_rules

#1. 데이터 로드
dataset = pd.read_csv("c:\\data\\building.csv", encoding = 'CP949',index_col = 0 )
dataset.head()

#2. 결측치 확인 및 치환
dataset.isnull().sum()
dataset_filled = dataset.fillna(0).astype(int)
dataset_filled

#3. 데이터프레임을 리스트로 변경
dataset_filled

#4. 연관규칙 분석을 위한 데이터로 전처리
a = []
colnames = dataset.columns

for j in range(0,20):
    b = []
    for i,k in list(enumerate(colnames)):
        if dataset_filled.iloc[j,i] == 1:
            b.append(k)   #컬럼명을 b리스트에 append
        else:
            pass  #아무것도 하지 않음
    a.append(b)   

dataset2 = a
dataset2

#5. 전처리한 데이터를 다시 데이터 프레임으로 생성
te = TransactionEncoder()
te_ary = te.fit_transform(dataset2)
te_ary

df = pd.DataFrame(te_ary, columns = te.columns_)
df

#6. 데이터 연관분석 지지도 0.1이상
a = apriori(df, min_support = 0.1, use_colnames = True)

#7. 나머지 성능척도도 출력
result = association_rules(a, metric = 'confidence',min_threshold = 0.3)
result

문제381. 위의 결과를 다시 출력하는데 지지도-신뢰도를 높은것부터 출력하시오

result.sort_values(by = ['support', 'confidence'], ascending = False)

문제382. 위에서 중간에 생략된 행들을 모두 다 출력되게 하시오.

pd.set_option('display.max_rows', None)
result.sort_values(by = ['support', 'confidence'], ascending = False)

 

 

 

문제383. 출력되는 결과중에 선행품목(antecedents)가 보습학원인것만 출력하시오.

result[:][result.antecedents.apply(lambda x: str(x).count('보습학원') >= 1)]
#result[:][result.antecedents.apply(str).str.contains('보습학원')] 이렇게 가져와도 됨

문제384. 위에서 출력되는 결과중에 연관품목(consequents)이 병원인 것들만 출력하시오.

result2[:][result2.consequents.apply(lambda x: str(x).count('병원') >= 1)]

 

 

+) 데이터 전처리 안하고 출력하는 방법

import pandas as pd
from mlxtend.preprocessing import TransactionEncoder #연관분석을 위한 데이터 전처리 모듈
from mlxtend.frequent_patterns import apriori  #연관분석 모듈
from mlxtend.frequent_patterns import association_rules

#1. 데이터 로드
dataset = pd.read_csv("c:\\data\\building.csv", encoding = 'CP949',index_col = 0 )
dataset.head()

#2. 결측치 확인 및 치환
dataset.isnull().sum()
dataset_filled = dataset.fillna(0).astype(int)
dataset_filled

dataset3 = dataset_filled.astype(bool)

df3 = pd.DataFrame(dataset3)
df3

# 6. 데이터 연관분석 지지도 0.1이상
a3 = apriori(df3, min_support = 0.1, use_colnames = True)
a3
# 7. 나머지 성능척도도 출력
result3 = association_rules(a3, metric = 'confidence',min_threshold = 0.3)
result3

>데이터를 모두 boolean형식으로 가져오기만 하면 됨.

 

 

- 54만건의 온라인 주문내역을 연관분석해서 가장 연관이 높은 상품들이 무엇이 있는지 알아보기

데이터셋 : OnlineRetail.csv (캐글에서 자료 얻을 수 있음)

InvoiceNo : 주문번호

StockCode : 상품코드

Description : 상품설명

Quantity : 주문량

InvoiceDate : 주문날짜

UnitPrice : 달러로 환원했을 때의 금액

CustomerID : 고객번호

Country : 주문한 나라

 

> 온라인 주문 내역을 연관분석하기 전에 알아야할 파이썬 문법 2가지

1. groupby

2. unstack

 

문제385. 사원 데이터 프레임에서 부서번호, 부서번호별 토탈월급을 출력하시오(세로출력)

import pandas as pd

emp = pd.read_csv("c:\\data\\emp2.csv")
emp.groupby('deptno')['sal'].sum().reset_index()

문제386. 직업, 직업별 평균월급을 출력하시오.

import pandas as pd

emp = pd.read_csv("c:\\data\\emp2.csv")
emp.groupby('job')['sal'].mean().reset_index()

문제387. 월급이 1000이상인 사원들의 직업, 직업별 토탈월급을 출력하시오.

import pandas as pd

emp = pd.read_csv("c:\\data\\emp2.csv",index_col = 0)

a = emp[:][emp.sal >= 1000]
a.groupby('job')['sal'].sum().reset_index()

문제388. 직업이 SALESMAN, ANALYST인 사원들의 부서번호, 부서번호별 토탈월급을 출력하시오.

a = emp[:][emp.job.isin(['SALESMAN','ANALYST'])]
a.groupby('deptno')['sal'].sum().reset_index()

 

문제389. 아래의 SQL을 판다스로 구현하시오.

-- SQL
select deptno, job, sum(sal)
 from emp
 groupby deptno, job
 order by deptno, job;
#python
a = emp.groupby(['deptno','job'])['sal'].sum().reset_index()
a.sort_values(by = ['deptno','job'], ascending = True)

문제390. 위의 결과에서 판다스의 문법 중 하나인 unstack()을 써서 결과를 출력하고 어떤 결과인지 분석하시오.

emp.groupby(['deptno','job'])['sal'].sum().unstack()

문제391. 부서번호, 관리자 번호, 부서번호별 관리자 번호별 평균 월급을 출력하시오.

--SQL
select deptno, mgr, avg(sal
 from emp
 group by deptno, mgr
 order by deptno, mgr;
#python
emp.groupby(['deptno','mgr'])['sal'].mean().reset_index()

문제392. 위의 결과에서 mgr을 컬럼으로 출력하시오(unstack()사용)

emp.groupby(['deptno','mgr'])['sal'].mean().unstack()

문제393. OnlineRetail 데이터를 판다스 데이터 프레임으로 생성하시오.

import pandas as pd

df = pd.read_csv("c:\\data\\OnlineRetail.csv", encoding = 'unicode_escape')
df.head()

문제394. stockcode가 84406B인 stockcode와 Description을 출력하시오.

df[['StockCode','Description']][df.StockCode == '84406B']

문제395. df 데이터 프레임에서 주문한 나라가 United Kingdom인 곳의 주문번호와 Description을 출력하시오.

df[['InvoiceNo','Description']][df.Country == 'United Kingdom']

문제396. 주문한 나라가 영국인 데이터에서 주문번호별, 상품번호별 토탈수량을 출력하시오.

df2 = df[:][df.Country == 'United Kingdom']
df2.groupby(['InvoiceNo','Description'])['Quantity'].sum().reset_index()

문제397. 위의결과에서 Description을 컬럼으로 출력되게 하시오.

df2 = df[:][df.Country == 'United Kingdom']
df2.groupby(['InvoiceNo','Description'])['Quantity'].sum().unstack()

문제398. 주문번호에 알파벳 대문자 C를 포함하는 주문내역의 모든 컬럼을 출력하시오.

=> 주문취소한 데이터

df[:][df.InvoiceNo.str.contains('C')]

문제399. 주문번호에 알파벳 대문자 C를 포함하지 않는 주문내역의 모든 컬럼을 출력하시오.

df[:][~ df.InvoiceNo.str.contains('C')]

문제400. 위에서 출력되고 있는 결과중에서 나라가 영국인 데이터만 df_uk에 담으시오.

df_uk = df[:][(~ df.InvoiceNo.str.contains('C')) & (df.Country == 'United Kingdom')]
df_uk

문제401. 위의 df_uk에서 주문번호, 상품 상세설명별 토탈 상품수량값을 출력하는데 상품 상세 설명 데이터를 컬럼으로 만드시오.

df_uk = df[:][(~ df.InvoiceNo.str.contains('C')) & (df.Country == 'United Kingdom')]

result = df_uk.groupby(['InvoiceNo','Description'])['Quantity'].sum().unstack()
result.shape  #(18668, 4188)

문제402. 위에서 출력되고 있는 결과의 결측치를 0으로 변경하시오.

result = df_uk.groupby(['InvoiceNo','Description'])['Quantity'].sum().unstack()
result.shape  #(18668, 4188)
result.fillna(0, inplace = True)
result

문제403. 위의 result의 결과에서 수량이 1이상이면 1이 되게 하고 0보다 작거나 같으면 0이 되게끔 데이터를 변경하시오.

df_uk = df[:][(~ df.InvoiceNo.str.contains('C')) & (df.Country == 'United Kingdom')]

result = df_uk.groupby(['InvoiceNo','Description'])['Quantity'].sum().unstack()
result.shape  #(18668, 4188)
result.fillna(0, inplace = True)

def func1(x):
    if x >= 1.0:
        return 1
    else:
        return 0
result2 = result.applymap(func1)

result2

# result2 = result.astype(bool) 해줘도 됨

문제404. mlxtend 패키지의 apriori함수를 이용해서 상품별로 가장 연관이 있는 상품이 어떤 것인지 연관분석을 하시오.

from mlxtend.frequent_patterns import apriori

a = apriori(result2, min_support = 0.03, use_colnames = True)
a

> 지지도가 0.03 이상인 상품들만 a변수에 담음

 

문제405. 위의 a를 가지고 association_rules 함수를 이용해서 향상도가 0.5 이상인 연관규칙을 출력하시오.

from mlxtend.frequent_patterns import apriori

a = apriori(result2, min_support = 0.03, use_colnames = True)

from mlxtend.frequent_patterns import association_rules

association_rules(a, metric = 'lift', min_threshold = 0.5)

문제406. 위의 결과를 지지도, 신뢰도가 높은 것부터 출력하시오.

a2 = association_rules(a, metric = 'lift', min_threshold = 0.5)
a2.sort_values(by = ['support','confidence'], ascending = False)

 

문제407. (오늘의 마지막 문제) 프랑스에서 주문한 상품들의 연관규칙을 출력하시오. 지지도 0.03이상, 향상도 0.5이상으로.

import pandas as pd
from mlxtend.frequent_patterns import apriori
from mlxtend.frequent_patterns import association_rules

df = pd.read_csv("c:\\data\\OnlineRetail.csv", encoding = 'unicode_escape')
df.head()

df_fr = df[:][(~ df.InvoiceNo.str.contains('C')) & (df.Country == 'France')]

df_fr2 = df_fr.groupby(['InvoiceNo','Description'])['Quantity'].sum().unstack()
df_fr2.shape  #(392, 1564)
df_fr2.fillna(0, inplace = True)

result = df_fr2.astype(bool)  #0은 False, 0 이상은 True를 뱉어냄

# 연관분석
a = apriori(result, min_support = 0.03, use_colnames = True)
a_rules = association_rules(a, metric = 'lift', min_threshold = 0.5)
a_rules.sort_values(by = ['support','confidence'], ascending = False)  #지지도, 신뢰도 asc 정렬

 

반응형