Data Analysis/Statistics

Python_Statistics_Association

mansoorrr 2024. 3. 13. 14:09

연관분석(Association Analysis)

  • 사건의 연관규칙을 찾는 방법
  • A후에 B를 시행할 확률을 구하는데 사용
  • 소비자의 구매 패턴 분석에 주로 사용됨
  • 장바구니분석이라고도 불림
  • 유투브, 넷플릭스 등과 같은 플랫폼도 이러한 알고리즘을 기반으로 콘텐츠를 추천
  • 연관규칙을 찾기 전 연관성이 있는지를 파악한다.(Run-test)
  • 이후 연관규칙분석을 실시한다(Aporiori)
  • 연관분석에 사용되는 척도
척도명 내용
지지도 - 전체 거래중 A와 B가 함께 거래된 비율
- A와 B를 모두 포함하는 거래 수 / 전체거래수
신뢰도 - A를 구매한 거래중 A와 B가 함께 거래된 비율
- 연관성의 정도를 파악 가능
- 지지도 / A구매비율
향상도 - A가 구매되지 않았을때 B의 구매 확률보다 A가 구매되었을때 B가 구매될 확률 증가비
- 향상도=1 일경우 두 품목은 관련이 없음
- 지지도 / (A구매비율 * B구매비율)

 

1. Run-test

  • 연관규칙을 찾기 전 연속적인 binary값들이 임의적으로 나타난 값인지 아닌지를 검정하는 기법
가설 내용
H0 연속된 값이 임의적이다(연관성이 없다)
H1 연속된 값이 임의적이 아니다(연관성이 있다)
  • statsmodels.sandbox.stats.runstest_1samp(parameters)
 

statsmodels.sandbox.stats.runs.runstest_1samp - statsmodels 0.14.1

statsmodels.sandbox.stats.runs.runstest_1samp statsmodels.sandbox.stats.runs.runstest_1samp(x, cutoff='mean', correction=True)[source] use runs test on binary discretized data above/below cutoff Parameters: xarray_likedata, numeric cutoff{‘mean’, ‘me

www.statsmodels.org

예시) 임의 데이터를 활용한 연관규칙검정(Run-test)

  • 데이터정의
    • 임의 데이터를 만듬
    • Run-test의 경우 binary데이터(이진데이터)만 가능
#데이터 정의
data = ["a", "a", "b", "b", "a", "a", "a", "a", "b", "b", "b", "b", "b", "a", "a", "b", "b", "a", "b", "b"]
df = pd.DataFrame(data, columns=["product"])
df.head()
  • 변환 및 검정
    • binary데이터로 바꿔주는 작업을 실시한다
    • run-test실행 결과 p-value > .05 이므로 귀무가설을 채택한다.
    • 따라서 a, b는 임의적이다 = 연관성이 없다.
#데이터 변환
df.loc[df.loc[:, "product"] == "a", "product"] = 1 #a=1
df.loc[df.loc[:, "product"] == "b", "product"] = 0 #b=0

#runstest_1samp
from statsmodels.sandbox.stats.runs import runstest_1samp

z, p = runstest_1samp(df["product"], cutoff=0.5, correction=True)
print(f"z-stat: {z}\np-value: {p}")

'''
z-stat: -1.1144881152070183
p-value: 0.26506984027306035
'''

 

 

 

2. Aporiori

  • 가능한 모든 경우의 수를 탐색하여 지지도, 신뢰도, 향상도가 높은 규칙들을 찾아내는 방식이 가장 이상적
  • 하지만 아이템 수가 증가할 수록 계산에 소요되는 시간이 기하급수적으로 늘어남
  • 아이템이 n개일때 탐색할 모든 경우의 수 = n*(n-1)
  • 따라서 최소지지도 이상의 빈발항목집합을 찾은 후 그것들에 대해서만 연관규칙 계산
  • 빈발항목집합: 최소지지도보다 큰 지지도 값을 갖는 품목의 집합
  • from mlxtend.preprocessing import TransactionEncoder: 데이터세트를 트랜잭션 데이터로 변경
  • from mlxtend.frequent_patterns import apriori: 빈번항목집합을 출력
  • from mlxtend.frequent_patterns import association_rules: score(점수), confidence(신뢰도), Lift(향상도)를 DataFrame으로 생성

 

 

Apriori - mlxtend

From here you can search these documents. Enter your search terms below.

rasbt.github.io

 

 

예시) groceries데이터로 연관규칙분석 실행

  • 데이터정의 및 전처리
    • 데이터는 csv형태로 되어 있었음
    • value가 str형태로 들어가 있었음 > ','단위로 split하여 2차원 데이터 형태로 변경
#데이터 컬럼명 변경
df.columns = ["product"]
df.columns

#데이터 전처리: str으로 되어있던 value값을 리스트로 변경
product_series = df.iloc[:,0].str.split(",")

#내역의 unique값 확인: null없음
unique_products = [p for product in product_series for p in product]
unique_products = np.unique(unique_products)

#트랜잭션데이터로 만들기 위해 2차원 데이터로 변환
groceries = [pl for pl in product_series]
groceries[:5]

좌: 전처리전 / 후: 전처리 후

  • 트랜잭션데이터 변경
#트랜잭션 데이터로 변경
from mlxtend.preprocessing import TransactionEncoder

te = TransactionEncoder()
encoded_groceries = te.fit_transform(groceries)
encoded_groceries

#DataFrame형식으로 변환
encoded_groceries_df = pd.DataFrame(encoded_groceries, columns=te.columns_) #te.columns_를 하면 groceries의 unique한 값들이 나옴
encoded_groceries_df.head()

 

  • 빈번항목집합(최소지지도 이상의 지지도를 갖는 품목들) 탐색
    • 조건에 부합하는 품목들중 412번을 해석하면 다음과 같다. (butter, other vegetables)를 구매하면 whole milk를 구매할 확률이 57%로 나타난다. 그리고 (butter, other vegetables)를 구매하지 않고 whole milk를 구매할 확률보다 (butter, other vegetables)를 구매하고 whole milk를 구매할 확률이 2.45배 높다.
#---------- 빈번항목집합 탐색
from mlxtend.frequent_patterns import apriori

#지지도가 1%이상인 빈번항목집단 추출
ap = apriori(encoded_groceries_df, min_support=0.01, use_colnames=True)

#---------- 연관규칙분석 수행
from mlxtend.frequent_patterns import association_rules

# 빈번항목집단에서 향상도가 1이상인 연관규칙
rules = association_rules(ap, metric="lift", min_threshold=1)
rules.head()

# 2개이상 구매했을때 추가로 구매하는 물품 확인
# 조건1: 먼저 구매한 물품이 2개 이상 / 신뢰도: 0.4이상 / 향상도: 2이상

#규칙 길이 정하기
rules["antecedents_len"] = rules["antecedents"].apply(lambda x: len(x))
rules.head()

#조건 만족하는것들 추출
rules[
    (rules["antecedents_len"] >= 2) &
    (rules["confidence"] >= 0.4) &
    (rules["lift"] >= 2)
]

좌:빈번항목집합 / 우: 향상도가 1이상인 연관규칙

 

조건에 만족하는 연관규칙