Applied unsupervised learning with python 책을 기반으로 작성된 글입니다.

 

장바구니 분석의 기본적인 아이디어는 고객의 행동 패턴이나 제품 간의 관계에 대한 통찰을 끌어낼 수 있을 정도로 충분하게 함께 판매되는 제품 또는 제품 그룹 간의 관계와 빈도를 분석하는데 있다.

 

장바구니는 경제 시스템 내에 존재하는 유지되는 상품의 집합이다. 유지 된다는 말은 카탈로그에서 없애기 전까지는 계속 구매가 가능하다는 말로 이해하면 된다. 제품에는 일반적으니 모든 상품이나 서비스가 속할 수 있으며 경제 시스템은 하나의 회사나 행동 주체, 심지어 국가도 이에 해당할수 있다.

7장에 배운 토픽 모델에서는 자주 발생하는 단어 그룹을 찾았다면 이번 장에서는 자주 발생하는 제품 그룹을 찾는 형태이다. 따라서 토픽 모델에서의 단어 클러스터링이 장바구니 분석에 활용될 수 있다. 하지만 가장 큰 차이점은 장바구니에서의 클러스터는 몇개의 제품만 포함하는 작은 단위라는 점이며 클러스터 내 항목의 순서가 확률적 지표를 계산할 때 중요하다는 점이다. 이런 지표가 무엇을 의미하고 어떻게 계산하는지를 살펴 보겠다. 또한 장바구니 분석을 하기전에 요구되는 사항으로는 아이템의 컬렉션으로 구성된 리스트 형태의 데이터를 말한다.

 

 활용 사례

전통적인 소매업에서 적용할 수 있는 3가지 분야로는 1. 가격 개선 2. 쿠폰과 할인 추천 3. 매장의 배치 이다. 

모델을 사용해 제품 간의 관계를 알아내면 이를 전략적으로 활용해 제품을 배치하면 고객들이 더 많은 제품을 구매하도록 유도할 수있다. 둘 이상의 제품 간 관계가 충분히 강하고 단독으로는 잘 구매되지 않는 특성을 가진 제품(예를 들면 고기와 야채)이라면 이를 매장에서 서로 먼곳으로 배치하여 고객들이 두 제품을 구매하러 가면서 다른 제품도 중간에 구매할수 있게 유도할 수 있다. 반대로 관계가 약한 두 제품을 옆에 나란히 배치하면 이를 통해 추가적으로 구매를 유도할 가능성이 있다. 예를 들면 기저귀와 맥주 미국에 아기를 가진 아버지가 매장에 와서 기저귀를 고르고 맥주를 사는 사람이 많은것을 확인하고 바로 옆에 두고 판매를 하니 대부분이 기저귀를 구매하고 맥주를 구매하는 분들이 많았다 라는 것을 예로 들수가 있다. 

가격 개선과 쿠폰 및 할인 추천은 모두 상품의 가격을 다룬다는 측면에서 유사한 전략이다. 다시말해 어떤 제품은 가격을 올리고 어떤 제품은 가격을 내릴 것인가로 설명가능하다. 연관성이 높은 두제품을 생각해보면 이 두 제품은 함께 구매 될 가능성이 높기 떄문에 두 제품 중 하나의 가격을 올리더라도 함께 구매가 이뤄지면서 수익성이 개선 될 수 있다. 하지만 일반적으로 제품의 가격을 올리면 구매 빈도가 감소할 가능성이 있지만 연관성이 높은 상품이라면 risk(위험성)은 줄어든다. 비슷한 방식으로 관련이 별로 없는 제품에 대해서는 한 제품을 구매할 때 나머지 제품의 할인이나 쿠폰을 제공해 구매를 유도 할 수도 있다.

1. 중요한 확률 지표

- 장바구니 분석은 다양한 확률 지표를 기반으로 계산하는데 5가지 지표로는 1. 지지도 2. 신뢰도 3. 향상도 4. 레버리지 5. 확신 로 구성 된다.

1. 지지도 

 - 단순히 아이템 세트가 데이터 내에 나타날 확률로 전체 거래 횟수에 대한 해당 아이템 세트의 거래 횟수 비중으로 간단하게 계산할수 있다. (단 아이템 세트는 단일 또는 묶음 일수 있다.)

- 지지도는 매우 단순하지만 신뢰도 및 연관의 강도를 판단하는데 있어서 중요한 지표이다.

- 지지도는 확률이므로 값의 범위는 [0-1]이다. 

Support(X =>Y) = Support(X,Y) = P(X,Y) = Frequency(X,Y) / N

example) 샘플 데이터가 10개중에 우유와 빵이 함께 나온 데이터를 세어보면 4번 동시에 판매 되었다. 그러면 지지도는 4/10 으로 0.4로 쉽게 계산 가능하다.

2. 신뢰도

- 신뢰도 지표는 기본적으로 제품 A의 구매에 따른 제품 B의 구매 확률이기 때문에 조건부 확률 측면으로 생각해야한다. 신뢰도는 일반적으로 A=>B로 표기하며, A가 포함된 거래에 B가 포함되는 비율을 표현한다. 

- 신뢰도도 확률이므로 값의 범위는 [0-1]이다.

Confidence(X=>Y) = P( Y | X ) = Support(X,Y) / P(X)  = Frequency(X,Y) /N / Frequency(X) / N

즉 , Frequency(X,Y) / Frequency(X) 로 나타낼 수 있다.

example) 맥주 와인 아이템 중 특히 맥주 => 와인의 신뢰도를 계산해보자.

일단 맥주를 포함하는 거래를 식별한다. 거래는 3건이며 거래 2, 6, 7번이 해당하며 이 해당 거래 중에 얼마나 와인이 많이 포함 됐는지를 살펴보면 되는데 결과는 모든 거래에 와인이 포함 돼 있다. 따라서  맥주 => 와인 신뢰도는 1이다. 즉 고객이 맥주를 살 때 항상 와인을 함께 샀다는 의미이다.

3. 항상도(Lfit) 와 레버리지(Leverage)

- 두 지표는 동일한 질문의 답을 찾는다. 신뢰도처럼 향상도와 레버리지는 A=>B로 표현한다. 하지만 답을 찾는 질문은 " 하나의 항목 A가 다른 항목 B와 관련된 항목을 결정하는데 사용할 수 있는가 여부이다." 다시말해 어떤 소비자가 A 제품을 구매하는 경우 제품 B를 구매할지 여부를 어느정도 정도의 확신을 갖고 말할 수 있는 가? 이다. 

- A와 B가 독립적이지 않은 것으로 가정되는 표준 사례에서 A와 B의 지지도두 제품의 독립적으로 가정될 때를 비교함으로써 답을 찾을수 있다.

- 항상도는 두 사례의 비율로 계산되기 때문에 가질 수 있는 값의 범위는 [0, Infinity]이다. 만일 향상도의 값이 1이면 두제품은 서로 독립적이라는 의미이다. 그래서 제품 A의 구매가 제품 B의 구매에 미치는 영향은 없다라는것이다.

Lfit(X=>Y) = Support(X,Y) / (Support(X) * Support(Y)) = P(X,Y) / (P(X) * P(Y))

-레버리지는 두 케이스 간의 차이를 계산하기 때문에 값의 범위는 [-1, 1]이다. 레버리지가 0이면 향상도가 1일때 상황이다.

Leverage(X=>Y) = Support(X,Y) - (Support(X) * Support(Y)) = P(X,Y) - (P(X) * P(Y))

>> 위 지표값은 아이템간의 고나계 강도나 방향을 측정한다.

만일 향상도 값이 0, 1 이라면 두 아이템간의 관계는 부정적인 방향을 강하다고 할수 있다. 한 아이템을 구매하면 나머지는 잘 구매하지 않는다는 의미이다. 양과 음의 관계는 독립성과는 분리된다. 그래서 향상도가 1경우 레버리지가 0인 경우로 부터 멀어질수록 연관성이 강해진다.

 

4. 확신

- 다른 지표에 비해 덜 직관적이다. 확신은 X와 Y가 부정확한 예측 빈도와 무관한 경우, Y의 발생과 무고나하게 X가 발행하는 예상 빈도의 비율이다. 

- 값의 범위는 [0, Inf] 이다

Conviction(X=>Y) = ( 1 - Support(Y)) / (1 - Confidence(X=>Y)) 이다.

example) 반대 관계인 와인 =>맥주를 생각해보자.  Support(Y) 이번 경우라면  Support(맥주)는 3/10 이고 확신 X=>Y는 신뢰도 와인 => 맥주는 3/4dlek. 따라서 확신 :  와인 => 맥주는 [] 이다. 만일 와인과 맥주가 독립적이라면 와인 => 맥주는 2.8배가 더 부적확 할것이라고 할수있다. 하지만 이전에 업급하길 와인과 맥주 사이의 연관성은 성립한다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

토픽 모델링은 컴퓨터와 인간 언어의 관계를 탐구하는 컴퓨터 과학 분야인 자연 언어 처리의 한 부분으로, 텍스트 데이터 셋의 가용성이 증가하면서 인기를 끌고 있다.

NLP는 텍스트, 음성 및 이미지를 포함해 거의 모든 형태의 언어를 다룰 수 있다.

토픽 모델

토픽 모델은 거의 대부분 주제를 사전에 알지 못하기 때문에 비지도 학습 영역에 속한다. 비지도 학습 관점에서 토픽 모델은 클러스터링 알고리즘, 특히 k-평균 클러스터링과 가장 유사하고 시작할 때 주제의 수를 선택한 후 모델에서 해당 주제를 구성하는 단어를 추출한다. 

라이브러리 용도
langdetect 언어 종류 감지
matplotlib.pyplot 기본 도표 그리기
nltk 다양한 자연어 처리 작업
numpy 배열과 행렬 작업
pandas 데이터 프레임 작업
pyLDAvis 잠재 디리클레 할당 모델의 결과 시각화
pyLDAvis.sklearn pyLDAvis를 sklearn 모델과 함께 실행
regex 정규표현식 작성 및 실행
sklearn 머신러닝 구축

토픽 모델 개요

잠재적으로 관련이 있는 대량의 텍스트 데이터를 분석할 때 토픽 모델이 좋은 해법이 될 수 있다. 여기에서 연관된 데이터라는 것은 이상적으로 동일한 출처의 문서를 의미한다.

토픽 모델은 문서 모음으로부터 말뭉치(corpus)라는 부르는 단어들을 사용해 추상적인 주제를 식별한다. 즉 문장에 급여나 직원, 회의라는 단어가 포함돼 있다면 그 문장은 일에 관한 것이라고 가정한다고 생각해도 무방하다. 

토픽모델은 동일한 문서에 있는 단어가 연관돼 있다고 가정하고 가정하고 그 가정을 사용해 반복적으로 유사하게 나타나는 단어 그룹을 찾아 추상적인 주제를 정의한다. 이와 같이 이러한 모델은 감지되는 패턴이 단어로 구성돼 있는 고전적인 패턴 인식 알고리즘이다.

토픽 모델링 알고리즘에 4가지 단계

1. 토픽의 수를 정의한다.(모델을 피팅하기 전에 주제의 수를 선택)

2. 문서를 스캔하면서 동시에 등장하는 단어나 구절을 인식한다.

3. 문서의 특성을 나타내는 단어의 클러스터를 스스로 학습한다.

4. 말뭉치를 단어 클러스터로 특성화하는 추상 토픽을 출력한다.

- 일반적인 토픽 모델링 작업 흐름

일반적인 토픽 모델링 작업 흐름

> 가능한 최적의 주제 수를 선택해야 모델이 미리 정의된 주제 수의 제약하에 말뭉치에 가장 적합한 단어 그룹을 찾기 때문이다. 주제 수가 너무 많으면 주제가 부적절하게 좁아지면서 지나치게 세분화된 주제는 오버쿡드 라고 말한다. 마찬가지로 주제의 수가 너무 적으면 주제가 일반적으로 모호해지고, 위 상황을 언더쿡드 라고 말한다.

토픽 모델의 주요 특징

- 특정한 단어 또는 한 구절의 주제를 생성하지 않고 각각 추상 주제를 나타내는 단어 모음을 생성한다

- 직접 내용을 확인하지 않은 문서에 대해서도 주제를 예측해낼 수 있다. (단 문서에 학습 데이터에 없는 단어가 있는 경우 모델은 학습 데이터에서 식별된 주제 중 하나에 연결된 경우에도 해당 단어를 처리할 수 없다.) 그래서 예측보다는 탐색 분석 및 추론에 더 많이 사용되는 경향이 있다.

- 토픽 모델링을 논의할때 주제를 나타내는 단어 그룹이 개념적으로 연관된 것이 아니고 근접성으로만 연관된 것이라는 사실을 지속적으로 강화하는 것이 중요하다. 

* 근접성의 판단

- 동일한 문서에 등장하는 모든 단어는 관련이 있다는 가정에 따르면 자주 근접하는 단어는 주제를 정의하기에 충분하다. 하지만 위 방법의 가정이 일관된 주제를 형성하기에 너무 일반적일 수도 있다. 

* 추상적인 주제를 해석 할려면

- 텍스트 데이터의 고유 특성과 생성된 단어 그룹을 균형 있게 조정해야한다. 

* 추가로 고려할점

- 텍스트 데이터가 갖는 기본적인 노이즈 특성으로 인해 토픽 모델이 주제 중 하나와 관련이 없는 단어를 해당 주제에 지정할 수도 있다.

 

토픽 모델링의 알고리즘 

1. 잠재 디리클레 할당(LDA)

2. 음수 미포함 행렬 분해(NMF)

 

비지니스 활용

- 제약 사항이 있음에도 토픽 모델링은 적당한 곳에 제대로 사용하면 사업적인 가치를 이끌어낼 수 있는 실행 가능한 통찰을 제공하며 예를 들면 개인이 이전에 읽은 글을 토대로 구성된 모음을 사용해 토픽 모델은 독자가 읽기 원하는 글의 유형을 알려준다. 이는 사용자에게 단순성과 사용 편의성을 높여주는 맞춤형 큐레이션이다.

 

연습 1

1. 데이터 로드

//필요한 모듈 임포트

import langdetect
import matplotlib.pyplot
import nltk
import numpy
import pandas
import pyLDAvis
import pyLDAvis.sklearn
import regex
import sklearn

// 전처리 과정에서 사용될 2개의 사전을 로드

nltk.download('wordnet')
nltk.download('stopwords')

// 데이터 로드

path = "News_Final.csv"
df = pandas.read_csv(path, header=0)

// 데이터 모양과 열들을 출력한다.

def dataframe_quick_look(df, nrows):
    print("SHAPE:\n{shape}\n".format(shape=df.shape))
    print("COLUMN NAMES:\n{names}\n".format(names=df.columns))
    print("HEAD:\n{head}\n".format(head=df.head(nrows)))

dataframe_quick_look(df, nrows=2)

// Topic열에는 실제로 토픽 모델이 확인하려는 정보가 포함돼 있다. 그래서 자체적으로 주제를 생성한 후 이를 제공된 주제 데이터와 서로 결과를 비교할수 있게 미리 고유한 주제와 발생 횟수를 출력

print("TOPICS:\n{topics}\n".format(topics=df["Topic"].value_counts()))

 

// 헤드라인 데이터를 추출하고 추출된 데이터를 리스트(list) 오브젝트로 변환한다. 그 후 출력을 해본다.

raw = df["Headline"].tolist()
print("HEADLINES:\n{lines}\n".format(lines=raw[:5]))
print("LENGTH:\n{length}\n".format(length=len(raw)))

2. 텍스트 데이터 정리

// 텍스트가 영어인지 아닌지 식별하는 함수

def do_language_identifying(txt):
try:
 the_language = langdetect.detect(txt)
except: 
the_language = 'none'
return 
the_language

// 표제어를 추출하는 함수

def do_lemmatizing(wrd):
out = nltk.corpus.wordnet.morphy(wrd)
 return 
(wrd if out is None else out)

// 메인 전처리 함수 코드

def do_headline_cleaning(txt):
# 언어를 식별한다.
# 영어가 아니면 return을 null 로 한다. 
    lg = do_language_identifying(txt)
    if lg != 'en': 
        return None
# 공백을 사용해 문자열을 토큰이라고하는 조각으로 나눈다.
    out = txt.split(" ")
# URL(http:s)을 식별해 "URL"이라는 문자열로 교체
    out = ['URL' if bool(regex.search("http[s]?://", i)) else i for i in out]
# 정규 표현식을 사용해 모든 문장 부호와 줄 바꾸기 기호를 빈문자열로 교체
    out = [regex.sub("[^\\w\\s]|\n", "", i) for i in out]
# 정규 표현식을 이용해 숫자를 모두 빈문자열로 교체
    out = [regex.sub("^[0-9]*$", "", i) for i in out]
# 모든 대문자를 소문자로 변경(복잡도를 줄이기 위해서)
    out = [i.lower() if i not in "URL" else i for i in out]
# URL이라는 문자열을 제거하자(왜냐 문자열과 주제 사이에 연결이 발생할 가능성이 있어서)
    out = [i for i in out if i not in "URL"]
# ntlk에서 stopwords을 불러와 stopwords를 제거
    list_stop_words = nltk.corpus.stopwords.words("English")
    list_stop_words = [regex.sub("[^\\w\\s]", "", i) for i in list_stop_words]
    out = [i for i in out if i not in list_stop_words]
# 각 헤드라인에 적용할 수 있는 함수를 정의해 표제어 추출 이때 wordnet사전을 불러서 사용
    out = [do_lemmatizing(i) for i in out]
# 토큰 목록에서 길이가 4 미만인 단어를 제거한다.(이는 대체로 짧은 단어는 일반적인 단어이고 주제와 관련이 적다는 가정을 전제로 한다.) 
    out = [i for i in out if len(i) >= 5]
    return out

clean = list(map(do_headline_cleaning, raw))

clean = list(filter(None.__ne__, clean))
print("HEADLINES:\n{lines}\n".format(lines=clean[:5]))
print("LENGTH:\n{length}\n".format(length=len(clean)))

// 각 헤더라인에 대해 공백을 사용해 토큰들을 연결한다.

clean_sentences = [" ".join(i) for in clean]
print(clean_sentences[0:10])

 

1) 잠재 디리클레 할당(LDA)

- 주어진 문서에 대하여 각 문서에 어떤 주제들이 존재하는지를 서술하는 대한 확률적 토픽 모델 기법 중 하나이며, 미리 알고 있는 주제별 단어수 분포를 바탕으로, 주어진 문서에서 발견된 단어수 분포를 분석함으로써 해당 문서가 어떤 주제들을 함께 다루고 있을지를 예측할 수 있다.

- LDA는 생식 확률 모델이며, 확률로 표현된 데이터를 생성한 프로세스를 알고있다고 가정한 다음 데이터로 부터 이를 생성한 매개변수를 역으로 찾는 작업이다.

LDA에서 중요한 가정

 - 단어의 교환성(exchangeability)이다. 이는 '단어 주머니(bag of words)'라고 표현하며, 교환성은 단어들의 순서는 상관하지 않고 오로지 단어들의 유무만이 중요하다는 가정이다. 예를 들어, 'Apple is red'와 'Red is apple' 간에 차이가 없다고 생각하는 것이다. 단어의 순서를 무시할 경우 문헌은 단순히 그 안에 포함되는 단어들의 빈도수만을 가지고 표현이 가능하게 된다. 이 가정을 기반으로 단어와 문서들의 교환성을 포함하는 혼합 모형을 제시한 것이 바로 LDA이다. 하지만 단순히 단어 하나를 단위로 생각하는 것이 아니라 특정 단어들의 묶음을 한 단위로 생각하는 방식(n-gram)으로 LDA의 교환성 가정을 확장시킬 수도 있다.

LDA 모델의 그래픽 표현

- M개의 문서가 주어져 있고, 모든 문서는 각각 k개의 주제중 하나에 속할때, 문서는 N개의 단어의 연속이며, 전집은 M개의 문서의 집합이며, 생성 프로세스는 말뭉치의 모든 문서에 대해 실행됐으므로 M으로 표시된 가장 바깥쪽 플레이트는 각문서에 대한 반복을 나태낸다. 마찬가지로 단어에 대한 반복은 N으로 표기된 다이어그램의 가장 안쪽 프레이트로 표시된다. 원은 매개변수와 분포, 결과를 나타내고 w로 표시된 음영 처리된 원은 선택된 단어로, 유일하게 알고 있는 데이터 조각이므로 생성 과정을 역으로 엔지니어링 하는 데 사용된다.

- 4가지 변수

* α : 주제 문서 디리클레 배포용 하이퍼파라미터

* β : 각 주제에 대한 단어의 분포

* Z : 주제에 대한 잠재 변수

* θ : 각 문서의 주제 배포를 위한 잠재 변수

>> αβ는 문서 내 주제와 주제 내 단어의 빈도를 제어한다. 만일 α가 증가하면 각 문서의 주제 수가 증가함에 따라 문서가 점점 유사해진다. 반면에 α가 줄어들면 각 문서의 주제 수가 감소함에 따라 문서의 유사성이 낮아진다. β 또한 비슷하게 동작한다.

변분 추론

LDA가 가진 큰 문제는 조건부 확률, 분포의 평가를 관리할 수 없으므로 직접 계산하는 대신 확률을 추정한다는 점이다. 

변수 추론은 더 간단한 근사 알고리즘 중 하나지만 확률에 관한 상당한 지식을 필요로 하는 광범위한 파생이 존재한다.

변수추론은 각 문서의 각 단어를 주제 중 하나에 무작위로 할당해 시작하고 각 문서와 각 문서의 각 단어에 대한 두 비율을 계산하며 이 두 비율 중 하나는 문서에 대한 주제의 비율 P(Topic | Document)이며, 나머지 하나는 주제에 대한 단어의 비율 P(Word | Topic)이다. 이 두 비율을 곱하고 결과 비율을 사용해 단어를 새 주제에 할당하고 주제 할당이 크게 변하지 않는 정상 상태에 도달할 때까지 이 과정을 반복한다. 이후에 문서 내 주제 혼합 및 주제 내 단어 혼합을 추정하는데 사용된다.

변수 추론의 목적

- 실제 분포가 다루기 어려운 형태일 때, 초기 분포와 매우 유사하면서도 다루기 쉬운 간단한 변형 분포를 사용하려는  데 있다.

 

Bag of words

- 텍스트는 머신 러닝으로 전달 할수 없어서 먼저 숫자 형태로 인코딩을 해야한다. 머신러닝에서 텍스트를 사용하는 간단한 방법은 Bag of words 모델을 사용하는 것이다.

- 이 모델은 단어 순서에 관한 모든 정보를 제거하고 각 단어의 존재하는 정도(횟수 또는 빈도)에 중점을 둔다.

Bag of words 데이터 구조로 변환하기 위해 CountVectorizer를 실행 예제

number_words, number_docs, number_features를 정의하며 첫 두개의 변수는 LAD 결과의 시각화를 제어하며 마지막 인자는 특징 공간에 유지할 단어의 수를 제어한다.

number_words = 10
number_docs = 10
number_features = 1000

카운트 벡터라이저를 실행하기 전에 입력값을 세가지 max_df, min_df, max_features이다. 이들 매개변수는 말뭉치의 단어 수를 모델에 영향을 줄 수 있는 수준까지 추가 필터링을 한다. 적은 수의 문서에만 등장하는 단어는 주제에 속하기 너무 드물기 때문에 이를 제거하기 위해 min_df는 지정된 수보다 적은 수의 문서에 등자하는 단어를 버리는데 사용된다. 너무 많은 문서에 나타나는 단어는 특정 주제와 연결될 만큼 구체적이지 않으므로 max_df는 지정된 백분율보다 더 많은 문서에 등장하는 단어를 버리기 위해 사용된다. 마지막으로 너무 과한 모델 피팅을 원치는 않으므로 모델에 맞는 단어의 수는 가장 자주 발생하는 지정된 수(max_features)로 제한한다.

vectorizer1 = sklearn.feature_extraction.text.CountVectorizer(
    analyzer="word",
    max_df=0.5
    min_df=20
    max_features=number_features
)
clean_vec1 = vectorizer1.fit_transform(clean_sentences)
print(clean_vec1[0])

벡터라이저에서 항상 이름과 단어를 추출한다. 모델은 단어를 숫자로 인코딩된 형래로만 제공하므로 형상 이름 벡터를 결과와 병합하면 해석이 쉬워진다.

feature_names_vec1 = vectorizer1.get_feature_names()

퍼블렉서티

- 모델에는 일반적으로 성능을 평가하는 데 활용할 수 있는 지표가 있다. 성능에 대한 정의가 살짝 다르다. 회귀 및 분류에서 예측값은 성과에 대한 명확한 측정값을 계산할 수 있는 실제값과 비교할 수 있다. 토픽 모델을 사용하면 모델이 학습한 단어만 알기 때문에 동일한 주제를 사용하더라도 새 문서에 해당 단어가 포함되지 않을 수 있으므로 예측의 신뢰성이 떨어진다. 이러한 차이로 인해 토픽 모델은 퍼플렉서티라는 언어 모델에 특화된 지표를 사용해 평가한다.

-퍼플렉서티는 PP라고 줄여 부르고, 주어진 단어를 평균적으로 따를 수 있는 가장 가능성이 높은 다른 단어들의 수를 측정한다.

평균적으로 가장 가능성이 높은 소수의 단어들이 뒤따를 수 있는 단어가 더 구체적이고 주제와 더 밀접하게 연관될 수 있다는 생각을 할수 있다. 이와 같이 낮은 퍼플렉서티 점수는 더 나은 언어 모델임을 의미하며, 더 나은 최적의 주제 수를 선택하는데 사용할 수 있다.

n은 단어의 나열에 속한 단어의 수를 의미한다.

연습 : 주제 선택

- LDA는 2개의 입력을 가진다. 첫 번째는 문서 자체이며, 두 번째는 주제의 수이다. 

최적의 수를 찾는 방법

- 여러 개의 주제를 검색하고 가장 퍼플렉서티 값이 작은 주제 수를 선택하는 것이다. 위 방식을 격자 검색이라고 한다.

// 다양한 주제에 LDA 모델을 피팅하는 함수를 정의하고 퍼플렉서티 점수를 계산하고 주제와 퍼플렉서티 점수의 데이터 프레임이고 또다른 하나는 최소 퍼플렉서티 점수를 갖는 주제의 수의 데이터프레임을 반환한다.

def perplexity_by_ntopic(data, ntopics):
    output_dict = {
        "Number Of Topics": [], 
        "Perplexity Score": []
    }
    
    for in ntopics:
        lda = sklearn.decomposition.LatentDirichletAllocation(
            n_components=t,
            learning_method="online",
            random_state=0
        )
        lda.fit(data)
        
        output_dict["Number Of Topics"].append(t)
        output_dict["Perplexity Score"].append(lda.perplexity(data))
        
    output_df = pandas.DataFrame(output_dict)
    
    index_min_perplexity = output_df["Perplexity Score"].idxmin()
    output_num_topics = output_df.loc[
        index_min_perplexity,  # 인덱스
        "Number Of Topics"  # 컬럼 
    ]
        
    return (output_df, output_num_topics)

//퍼플렉서티 함수 실행

df_perplexity, optimal_num_topics = perplexity_by_ntopic(
    clean_vec1, 
    ntopics=[1, 2, 3, 4, 6, 8, 10]
)
print(df_perplexity)

// 시각화

df_perplexity.plot.line("Number Of Topics""Perplexity Score")

그림으로 보았을때, 퍼플렉서티를 통한 최적의 주제 수는 3개이다. 하지만 위에서 Topic에 포함된 주제 수는 4개였다. 그래서 3개가 반환된 이유가 있다 그 이유는 잠시뒤에 다루겠다.

Applied unsupervised learning with python 책을 기반으로 작성된 글입니다.

 

1) 차원 축소란 무엇인가?

1.1) 차원이란?

- 차원은 데이터 샘플과 관련된 치수, 형상 또는 변수의 수를 말한다.

- 스프레드시트의 열의 수로 생각하면 편하다.

 

1.2) 차원 축소

- 차원 축소는 해결 중인 문제 또는 데이터 셋의 종류에 따라 제공된 정보를 잃지 않으면서도 차원은 줄이고자 한다.

- 차원 축소를 사용하면 불필요한 노이즈를 상당 부분 제거할 수 있고, 이는 데이터에 적용하는 알고리즘 성능을 높여주고 데이터의 크기를 줄여줘서 하드웨어 요구 사항을 낮추는 데 기여할 수 있다.

 

2) 차원 축소가 적용되는 사례

 a. 사전 처리/ 기능 엔지어링 : 가장 일반적인 사례 가운데 하나는 사전 처리 또는 머신 러닝 솔류션의 개발 단계에서의 초기 기능 구현 단계로, PCA을 통해 가장 중요한 정보 구성 요소를 데이터에서 분리하고 이를 모델에 제공해 가장 관련성이 높은 정보만 제공하게 된다.

 b. 노이즈 감소 :  차원 축소는 효과적인 노이즈 감소/ 필터링 기법으로도 사용할 수 있다. 예를 들면 아래 그림처럼 왼쪽 사진의 중요한 요소들이 오른쪽 사진으로도 보아도 눈에 보이는 것을 확인할 수 있다.

 c. 신뢰 가능한 인공 데이터셋 생성 : PCA가 데이터셋을 정보의 구성 요소로 나눔에 따라 우리는 각 구성 요소의 영향을 조사하거나 고윳값 사이의 비율을 조정해 새로운 데이터셋 샘플을 만들 수 있고 이러한 데이터의 모야을 통계적 형태 모델링이라고 한다.

 d. 재무 모델링 / 위험 분석 : 차원 축소는 다수의 개별 시장 지표 또는 신호를 더 적은 수의 구성 요소로 통합할  수 있으므로 금융 산업에 유용한 더 빠르고 효율적인 도구를 제공할 수 있다. 마찬가지로 위험도가 높은 제품이나 회사를 찾아내기 위해 사용된다.

3) 차원 저주

일반적으로 특징 공간에 많은 수의 차원을 가진 데이터를 갖고 작업해야 할 때 흔히 사용하며, 데이터 셋에 둘러싼 공간이 넓고 밀도가 낮아진 데이터 셋을 보고 차원 저주라고 한다.

3.1) 차원 축소를 하는 이유

- 데이터 셋의 밀도 문제를 해결하지 않고선 아무리 추가 기능에 관한 feature 정보를 얻을 수 있더라고 통계적인 상관관계를 만들기가 어려워서 성능을 개선하지 못한다. 하지만 차원 축소를 하면 유용한 정보는 유지하면서도 밀도에 따른 부정적인 영향을 최소화를 시켜 모델의 성능을 개선하는데 강력하게 만든다.

4) 차원 축소 기법 개요

4.1) 차원 축소는?

- 유용한 정보는 유지하면서 데이터세의 밀도를 관리하는 것이므로 차원 축소는 일반적으로 분류 단계 전에 사용되는 중요한 사전 처리 단계를 차지한다.

4.2) 차원 축소 기법

 a. 데이터 밀도를 높이기 위해 더 높은 차원 공간의 데이터를 낮은 차원의 공간으로 저정하는 형상 투영 프로세스를 사용해 작업을 한다.

4.3) 차원 축소에 고려 해야할점

- 항상 낮은 차원의 공간으로 투명해 발생하는 정보 손실의 균형을 유지하도록 노력해야한다.

5) 차원 축소와 비지도 학습

5.1) 차원 축소 기법들

a. 선형 판별 분석(LDA, Linear Discriminant Analysis) : 차원 축소 뿐만 아니라 분류에도 사용할 수 있는 꽤 편리한 기법이다.

b. 음수 미포함 행렬 분해(NNMF, Non-negative matrix factorization) : 다양한 차원 축소 기법처럼 데이터셋의 특징 수를 줄이기 위해 사용되며 선형 대수의 특성을 활용한다.

c. 특이값 분해(SVD, Singular Value Decomposition) : PCA와 관련 깊으며 행렬을 분해하는 과정이다.

d. 독립 성분 분석(ICA, Independent Component Analysis) : 주성분을 이용한다는 점에서 PCA와 비슷하지만 데이터의 독립적인 축을 찾는다.

 

6) PCA

- 차원 축소의 기법 중 하나이다.

- 데이터를 일련의 구성 요소(데이터 내에서 표현되는 정보)로 분리해 데이터 셋의 밀도 문제를 개선할 수 있다.

 

6.1) PCA를 알아보기 전에 기초 통계개념 알아보기

a. 평균 : 단순히 모든 값을 더한 후 집합의 수로 나눈 값

b. 표준 편차 : 평균에 근접한 데이터의 양을 측정한것으로 데이터 집합에서 데이터 집합 약68%의 값들이 평균에서 양쪽 1 표준편차 범위에 존재한다. 또한 분산은 표준  편차의 제곱을 한 값이다.

c. 공분산 : 2개의 확률 변수의 상관정도를 나타내는 값이며, 확률 변수 X의 증감에 따른 확률 변수 Y의 증감의 경향에 대한 측도이다. 

   Cov(X, Y) = E[(X - E(X))(Y - E(Y))] = E(XY) - E(X)E(Y)

  * Cov(X,Y ) > 0 : X ↑⇒Y ↑          ex) X :height, Y :weight

  * Cov(X,Y ) < 0 : X ↑⇒Y ↓          ex) X :age, Y : eyesight

  * Cov(X,Y ) = 0 : no relationship    ex) X :age, Y : eye size

d. 공분산 행렬 : 각 데이터의 분산과 공분산을 이용해 만드는 행렬

 

 

 

 

 

Applied unsupervised learning with python 책을 기반으로 작성된 글입니다.

 

우리가 배우는 지도 학습 분야에서 특성 데이터는 제공 되지만 특성 변수가 무엇인지 설명하는 라벨은 제공되지 않는다. 대상 라벨이 구체적으로 무엇인지에 대해서는 정보를 얻을 수 없지만 비슷한 그룹을 함께 클러스터링함으로써 데이터의 구조를 얻을 수 있고 그룹 내에 어떤 유사성이 존재하는지 알아낼수 있다. 1장 2장에서 비슷한 데이터를 묶기 위해 처음으로 K- 평균을 사용하였다. 

하지만 K-평균은 연산 부담이 크지 않지만 차원 수가 많은 데이터 셋이면 다룰 때 문제가 생기기도 한다. 또한 찾고자 하는 클러스터의 수가 몇개인지 모르는 상황이면 K-평균은 이상적인 해답은 아니다.

그래서 2장에서 계층적 클러스터링을 배웠다. 여기서 집적 방식과 분산 방식으로 동작 할 수 있다.

 집적 방식은 상향식 접근 방식으로 동작하며, 각 데이터 지점을 자체 클러스터로 처리하고 링크 기준을 사용해 재귀적으로 그룹화 한다.

 분산 방식은 하향식으로 접근하며, 모든 데이터 지점을 하나의 대규모 클래스로 처리하고 이를 반복적으로 더 작은 클러스터로 분할하는 형태로 동작한다.

>> 위 방식은 전체 데이터 분포를 완전히 이해하는 장점이 있지만 복잡도가 올라가기 때문에 잘 사용하지 않는다. 그래서 계층적 클러스터링 방식은 데이터에 사전 정보가 부족한 경우 좋은 대안이 될 수 있다. 왜냐면 덴드로그램을 사용하면 데이터 분할을 시각적으로 확인할 수 있으며 이를 통해 몇개의 클러스터로 나누는 것이 합리적인지 결정할 수 있기 때문이다.

또 다른 접근 방식은 밀집된 데이터를 다룰 때 높은 성능을 보이는다고 알려져있는 DBSCAN 이다.

 

1. 이웃으로서의 클러스터 

1.1) 거리만 사용하는 클러스터링

- 서로 가까운 거리에 존재하는 데이터 지점일수록 유사성이 높고 멀수록 유사성이 낮다고 보는 개념을 사용한다.

- 특이한 데이터가 있는 경우 클러스터링이 별로 의미가 없다. 왜냐면 K-평균과 계층적 클러스터링 모두 남아 있는 데이터 지점이 하나도 없을 때까지 모든 데이터를 그룹에 포함시키기 때문이다.

 1.2) 거리 개념과 밀도 개념을 함께 사용하는 클러스터링

- 인접 밀도의 개념을 통합함으로써 런타임에  선택한 하이퍼파라미터에 기반해 특이한 데이터를 클러스터 밖에 둘 수 있고, 인접한 데이터 지접만 동일 클러스터의 구성원으로 간주하고 멀리 떨어진 데이터 지점은 클러스터에 포함하지 않고 외부에 둘 수 있다.

 

2. DBSCAN 소개

2.1) DBSCAN가 클러스터링을 하는 원리

- 이웃의 반경의 크기클러스터로 간주되는 인접 지역에서 발견된 최소 지점의 수를 종합적으로 고려해 밀도를 평가한다. 

 

2.2) DBSCAN가 고려해야하는 파라미터들

 a. 이웃반경 

 a.1) 극단적으로 이웃 반경이 크다면

- 아마도 경계를 넘어가 모든 지점이 결국 하나의 큰 클러스터에 포함되게 될것이다.

 a.2) 극단적으로 이웃 반경이 작다면

- 지점들이 모이지 못해 단일 지점만 포함하는 작은 클러스터만 잔뜩 생길 것이다.

 

b. 최소 지점의 수

- 이웃 반경의 크기를 보조하는 수단으로 볼수 있다.

 b.1) 데이터의 밀도가 희박하면

- 이웃 반경 못지 않게 최소 지점의 수도 중요해진다.

 b.2) 데이터의 밀도가 충분하면

- 최소 지점의 수는 별로 큰 영향을 주는 요소는 되지 않을 것이다.

 

>> 가장 좋은 옵션은 여전히 데이터 셋의 모양에 따라 달라진다. 그래서 하이퍼파라미터에가 너무 작지 않고 너무 크지않은 완벽한 골디락스 영역을 찾기를 원한다. 

                                                                                                                        * 골디락스 : 이상적인 값

 

3) DBSCAN 구현

 DBSCAN(eps = 0.5, min_samples = 10, metric = 'euclidean')

     * eps : 이웃(주변) 반경

     * min_samples : 최소 지점의 수(최소 포인트 수)

     * metric : 거리 측정 방식

 

3.1) 속성 - 이웃 반경(eps)

- DBSCAN에서 아주 중요한 파라미터이다. 왜냐하면 너무 작으면 모든 데이터가 클러스터 되지 않은 채로 남겨지는 문제가 생기며, 너무 크면 모든 데이터가 비슷하게 하나의 클러스터로 그룹화돼 어떠한 가치도 제공하지 않기 때문이다.

- eps는 엡실론의 약자로, 이웃을 검색할 때 알고리즘이 사용하는 거리이다.

- 엡실론 값은 특정 데이터 지점을 순환 할때 인점 여부를 판단하는 반지름으로 사용된다.

// 이웃 탐색에 의해 형성된 모양은 2차원에서는 원 3차원에서는 구라는 것이다. 이는 데이터의 구조에 따라 모델의 성능이 영향을 받을 수 있음을 의미한다. 

 

3.2) 속성 - 최소 지점 수( min_sample )

- 기능 공간에서 무작위로 놓인 소수의 지점들을 노이즈로 분류할 것인지 아니면 클러스터로 분류할것 인지를 따질 때 최소 지점의 수는 중요한 역할을 한다.

 

4) 활용 5: DBSCAN과 K-평균 그리고 계층적 클러스터링 비교

< 연습 문제 >

만약 당신은 상점 재고를 관리하며 많은 양의 와인을 받고 있다. 하지만 운송 중 브랜드 라벨이 병에서 떨어졌다. 다행히 공급업체가 각각의 일련 번호와 함께 각 병에 관한 화학적인 수치를 제공했다. 하지만 와인 병을 일일이 열고 그 차이를 시험할 수가 없다. 라벨이 부착되지 않은 병을 화학 물질 측정치에 따라 다시 묶을 수 있는 방법을 찾아야 한다. 주문 목록에서 3가지 유형의 와인을 주문했고, 와인 유형을 다시 그룹화하기 위해 2가지 와인 속성만(X_feature) 제공 받았다고 하자

//필요한 모듈 임포트

from sklearn.cluster import KMeans, AgglomerativeClustering, DBSCAN
from sklearn.metrics import silhouette_score
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

// 와인 데이터 셋 로드

wine_df = pd.read_csv("wine_data.csv")

 

//시각화

plt.scatter(wine_df.values[:,0], wine_df.values[:,1])
plt.title("Wine Dataset")
plt.xlabel("OD Reading")
plt.ylabel("Proline")
plt.show()

// 와인 데이터 셋의 지표를 산포도로 시각화

// K-평균 클러스터링

km = KMeans(3)
km_clusters = km.fit_predict(wine_df)

// 응집 계층적 클러스터링

ac = AgglomerativeClustering(3, linkage='average')
ac_clusters = ac.fit_predict(wine_df)

 

// DBSCAN 클러스터링 

db_param_options = [[20,5],[25,5],[30,5],[25,7],[35,7],[35,3]]   // 최적의 실루엣 점수 파라미터 찾기

for ep,min_sample in db_param_options:
    # Generate clusters using DBSCAN
    db = DBSCAN(eps=ep, min_samples = min_sample)
    db_clusters = db.fit_predict(wine_df)
    print("Eps: ", ep, "Min Samples: ", min_sample)
    print("DBSCAN Clustering: ", silhouette_score(wine_df, db_clusters))

// 가장 좋은 파라미터를 가진 DBSCAN으로 클러스터링

db = DBSCAN(eps=35, min_samples = 3)
db_clusters = db.fit_predict(wine_df)

// 모든 클러스터링 시각화

plt.title("Wine Clusters from K-Means")
plt.scatter(wine_df['OD_read'], wine_df['Proline'], c=km_clusters,s=50, cmap='tab20b')
plt.show()

plt.title("Wine Clusters from Agglomerative Clustering")
plt.scatter(wine_df['OD_read'], wine_df['Proline'], c=ac_clusters,s=50, cmap='tab20b')
plt.show()


plt.title("Wine Clusters from DBSCAN")
plt.scatter(wine_df['OD_read'], wine_df['Proline'], c=db_clusters,s=50, cmap='tab20b')
plt.show()

// 각각의 클러스터의 실루엣 점수

print("Silhouette Scores for Wine Dataset:\n")
print("K-Means Clustering: ", silhouette_score(wine_df, km_clusters))
print("Agg Clustering: ", silhouette_score(wine_df, ac_clusters))
print("DBSCAN Clustering: ", silhouette_score(wine_df, db_clusters))

// 보면 DBSCAN이 항상 최고의 선택이 될 수 없다. 하지만 다른 알고리즘과 구별되는 특징은 노이즈를 잠재적 클러스터링으로 사용한다는 사실이다. 어떤 경우에는 특이한 지점을 제거하기에 훌륭하지만 때로는 많은 지점을 노이즈로 분류하는 문제를 만들기도 한다. 그럼 하이퍼파라미터 튜닝을 통해 실루엣 점수를 높일 수 있을까?

wine_data.csv
0.00MB

Applied unsupervised learning with python 책을 기반으로 작성된 글입니다.

 

1. 클러스터링

1.1)클러스터링이란?

하나의 데이터를 여러개의 부분집합 (clusters) 으로 분할하는 것을 의미한다.

1.2) 클러스터링을 하는 이유?

데이터 셋에 존재하는 데이터의 유사성을 찾을 수 있다는 것은 근복적인 의미를 찾을려고 할때 상당히 유용해서

 

2. 계층적 클러스터링

-트리 기반의 데이터 구조이다.

 

 

2.1) 계층적 클러스터링의 접근 방식

a. 응집 계층적 클러스터링 방식(Agglomerative)

- 위에서 아래로 접근하는 방식

- 응집은 탐욕적인 특성 때문에 가끔은 잘못된 이웃을 선택해 잘못된 클러스터를 구성한다.

- 각 데이터 지점에서 시작해 유사한 지점들을 함께 결합해 클러스터를 형성한다.

 

b. 분산 계층적 클러스터링 방식(Divisive)

- 아래에서 위로 접근하는 방식

- 전체 데이터를 하나로 보고 출발하면서 최선의 방식을 찾아 클러스터를 나눈다는 장접을 가진다.

- 시간 복잡도가 높아서 응집에 비해 시간 소요가 크다. 그렇지만 정확도를 높일 수 있다.

 

// 두 방식의 성능은 서로 달라서, 전체 데이터셋이 무엇인지 아는 것은 좀더 정확하게 클러스터를 구분해내는 능력으로 이어진다. 그리고 일반적인 경우 응집 방식을 오히려 선호하는게 일반적이고 결과가 마음에 들지 않으면 분산 방식을 시도하는게 합리적인 선택이 된다.

 

2.2) 연결 기준

-연결은 클러스터 간의 거리를 계산할 수 있는 방법을 결정하는 개념이다.

a. 중심 연결

- K평균에서 사용햇던 중심점 탐색 방식과 같다.

- 데이터에 노이즈가 많고 중심점이 명확하지 않으면 잘 동작하지 않는다는 단점이 있다.

 

b. 단일 연결

- 연결기준으로 두 클러스터 사이의 점 쌍 사이의 최소 거리를 찾아낸다.

- 즉, 두 클러스터 사이의 가장 가까운 점에 기반해 클러스터를 결합한다

 

b.1) 단일 연결을 선택하는 이유?

- 기본적으로 데이터 간의 유사성이 높기 때문이며, 만일 이때 차이점이 존재한다면 데이터가 극도로 달라지기 때문에 가장 가까운 지점을 찾아 동작하기 때문에 먼 거리에 있는 이상한 데이터에 영향을 받지 않아서.

 

c. 완전 연결

- 연결 기준으로 두 클러스터 사이의 점 쌍 사이의 최대 거리를 찾아낸다.

- 즉, 두 클러스터 사이의 가장 먼 점을 기준으로 클러스터를 결합한다

 

c.1) 완전 연결을 선택하는 이유?

- 데이터가 클러스터 간에 멀리 떨어져 있고 클러스터 내부의 밀집도는 매우 높을때 좋은 결과를 보여줘서.

 

// 그래서  일반적으로 가장 좋은 접근법은 몇가지 연결 옵션을 시도해보고 목적에 가장 맞는 방법을 선택하는 것이다.

 

<예제 하기전 알아야 할것은 >

AgglomerativeClustering 함수의  파라미터(매개변수)

* n_clusters : 클러스터의 개수

* affinity : 거리 함수의 정의

* linkage : 연결기준 옵션

 

< 연습문제 >

만약 당신은 상점 재고를 관리하며 많은 양의 와인을 받고 있다. 하지만 운송 중 브랜드 라벨이 병에서 떨어졌다. 다행히 공급업체가 각각의 일련 번호와 함께 각 병에 관한 화학적인 수치를 제공했다. 하지만 와인 병을 일일이 열고 그 차이를 시험할 수가 없다. 라벨이 부착되지 않은 병을 화학 물질 측정치에 따라 다시 묶을 수 있는 방법을 찾아야 한다. 주문 목록에서 3가지 유형의 와인을 주문했고, 와인 유형을 다시 그룹화하기 위해 2가지 와인 속성만(X_feature) 제공 받았다고 하자

 

//필요한 모듈 임포트

from sklearn.cluster import KMeans
from sklearn.cluster import AgglomerativeClustering
from sklearn.metrics import silhouette_score
import pandas as pd
import matplotlib.pyplot as plt

// 와인 데이타 pandas로 로드

wine_df = pd.read_csv("wine_data.csv")

// 와인데이타 시각화

plt.scatter(wine_df.values[:,0], wine_df.values[:,1])
plt.title("Wine Dataset")
plt.xlabel("OD Reading")
plt.ylabel("Proline")
plt.show()

 

//K평균으로 클러스터링

km = KMeans(3)     // 클러스터링 할 갯수 3개 설정
km_clusters = km.fit_predict(wine_df)  // K평균으로 클러스터링 예측

 

//응집 계층적 클러스터링으로 클러스터링

ac = AgglomerativeClustering(3, linkage='average')   //클러스터링 할 갯수 3개 설정및 연결지점 중심연결로 설정
ac_clusters = ac.fit_predict(wine_df)      //응집 클러스터링으로 예측

 

//  k평균 클러스터링 그림 산포도로 시각화

plt.scatter(wine_df.values[:,0], wine_df.values[:,1], c=km_clusters)
plt.title("Wine Clusters from Agglomerative Clustering")
plt.xlabel("OD Reading")
plt.ylabel("Proline")
plt.show()

// 응집 계층적 클러스터링 그림으로 시각화

plt.scatter(wine_df.values[:,0], wine_df.values[:,1], c=ac_clusters)
plt.title("Wine Clusters from Agglomerative Clustering")
plt.xlabel("OD Reading")
plt.ylabel("Proline")
plt.show()

// 위에 예측된 클러스터링에 대한 평가를 실루엣 점수로

print("Silhouette Scores for Wine Dataset:\n")
print("K-Means Clustering: ", silhouette_score(wine_df, km_clusters))
print("Agg Clustering: ", silhouette_score(wine_df, ac_clusters))

 

3. 실루엣 점수

- 얼마나 클러스터에 잘 맞는지를 분석해주는 지표

- 1에서 -1까지 숫자로 나타낸다.

- 만약 1이면 완벽하게 클러스터가 구분돼 전혀 혼란이 없는 상태를 의미한다.

+ Recent posts