* pregnancies : 임신횟수 * glucose : 2시간 동안의 경구 포도당 내성 검사에서 혈장 포도당 농도 * bloodPressure : 이완기 혈압 (mm Hg) * skinThickness : 삼두근 피부 주름 두께 (mm), 체지방을 추정하는데 사용되는 값 * insulin : 2시간 혈청 인슐린 (mu U / ml) * BMI : 체질량 지수 (체중kg / 키 (m)^2) * diabetesPedigreeFunction : 당뇨병 혈통 기능 * age : 나이 * outcome : 당뇨병인지 아닌지, 768개 중에 268개의 결과 클래스 변수 (0 / 1)는 1이고 나머지는 0이다.
2. 라이브러리 import
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
3. 데이터셋 로드
df = pd.read_csv("diabetes.csv") #주피터노트북에서 실행 -> 경로 간단
df.shape
9개의 feature가 존재하고, 768개의 데이터가 있다.
df.head()
결측치가 없고 다 숫자로 되어있기 때문에 이 데이터셋은 전처리를 하지 않아도 괜찮다.
4. 학습, 예측 데이터셋 나누기
# 8:2 비율로 구하기 위해 전체 데이터 행에서 80% 위치에 해당되는 값을 구해서 split_count 변수에 담기
split_count = int(df.shape[0] * 0.8)
split_count
# train, test로 슬라이싱을 통해 데이터 나눔
train = df[:split_count].copy()
train.shape
test = df[split_count:].copy()
test.shape
데이터셋 자체로 학습을 하고, 예측 후 정확도까지 알아보기 위해서 위에서부터 80%는 학습데이터, 나머지 20%는 예측데이터로 분리했다.
80% 지점이 614번째 데이터이기 때문에
학습데이터는 614개,
예측데이터는 154개이다.
5. 학습, 예측에 사용할 컬럼
# feature_names 라는 변수에 학습과 예측에 사용할 컬럼명을 가져옴
# 여러개를 가져왔기 때문에 list 형태로 가져옴
feature_names = train.columns[:-1].tolist()
feature_names
# label_name 에 예측할 컬럼의 이름 담음
label_name = train.columns[-1]
label_name
feature는 이렇게 9개가 있는데, 우리가 예측할 것은 마지막 컬럼인 outcome (당뇨병인지 아닌지) 이기 때문에 뒤에서 두번째 컬럼인 Age까지를 feature_names에 저장하고, 마지막 outcome을 label_name에 저장했다.
6. 학습, 예측 데이터셋 만들기
# 학습 세트 만들기
# 행렬
X_train = train[feature_names]
print(X_train.shape)
X_train.head()
앞에서 나눈 80%의 학습데이터셋 train에 feature_names 컬럼을 적용하여 학습데이터셋 X_train 을 만들었다.
# 정답 값
# 벡터
y_train = train[label_name]
print(y_train.shape)
y_train.head()
마찬가지로 앞에서 나눈 80%의 학습데이터셋에 label_name 컬럼을 적용하여 학습할 때 정답을 맞추는 데이터셋 y_train을 만들었다.
# 예측에 사용할 데이터셋
X_test = test[feature_names]
print(X_test.shape)
X_test.head()
다음은 앞에서 나눈 20%의 예측데이터셋에 feature_names를 적용하여 학습한 알고리즘에 적용할 예측데이터셋 X_test를 만들었다.
# 예측의 정답값
# 실전에는 없지만, 실전 적용 전 정답을 알고있기 때문에 내가 만든 모델의 성능을 측정해봐야 함
y_test = test[label_name]
print(y_test.shape)
y_test.head()
마지막으로, 예측 모델의 성능을 측정하기 위한 예측 정답 데이터셋을 만들었다.
20% 예측 데이터셋에 label_name을 적용한 데이터셋으로, 실전 예측 문제에는 없지만 이 예제에서는 알고있는 값이기 때문에 모델의 성능을 측정할 때 사용할 것이다.
7. 머신러닝 알고리즘 가져오기
from sklearn.tree import DecisionTreeClassifier
model = DecisionTreeClassifier()
model
decision tree classifier 알고리즘을 사용할 것이기 때문에 이 알고리즘을 model 변수에 저장해준다.
8. 학습 (훈련)
model.fit(X_train, y_train)
아주 간단하다.
머신러닝 알고리즘.fit(훈련데이터, 정답데이터) 형식이다.
9. 예측
y_predict = model.predict(X_test)
y_predict[:5]
학습이 기출문제와 정답으로 공부를 하는 과정이었다면, 예측은 실전 문제를 푸는 과정이라고 볼 수 있다.
위에서 5개 데이터의 예측 결과를 보자면 이와 같다. 1은 당뇨병, 0은 당뇨병이 아니라는 것이다.
# 피처의 중요도 시각화
sns.barplot(x = model.feature_importances_, y = feature_names)
seaborn을 활용해서 각 피처의 중요도를 시각화했다.
11. 정확도(Accuracy) 측정하기
# 실제값 - 예측값 -> 같은 값은 0으로 나옴
# 여기서 절대값을 씌운 값 = 1 인 값이 다르게 예측한 값임
diff_count = abs(y_test - y_predict).sum()
diff_count
# decision tree 예측할 때마다 다르게 예측할 수 있기 때문에 이 값은 다르게 나올 수 있음
# 항상 같게 하려면 model = DecisionTreeClassifier(random_state = 42)처럼 random_state 지정
우리는 예측 데이터셋의 정답도 알고있기 때문에 모델의 정확도를 측정할 수 있다.
outcome 값은 0 또는 1이기 때문에 실제값에서 예측값을 뺀 값의 절대값이 1인 값이 틀린 것이라고 볼 수 있다.
4. 예를 들어 5개의 폴더로 나누면 fold1부터 5까지 하나씩 test data로 놓고 나머지로 training 후 test data로 성능을 확인한다.
5. 각각의 fold에 있는 점수의 평균을 내서 가장 좋은 점수를 내는 모델과 파라미터를 찾는다.
clf = SVC(파라미터)
clf.fit(X_train, y_train)
3. grid searches
이러한 과정을 거쳐 알맞은 모델과 파라미터를 구한다.
4. 기본 예제
from sklearn imoprt tree
X = [[0, 0], [1, 1]]
y = [0, 1]
clf = tree.DecisionTreeClassifier()
clf.fit(X, y)
clf.predict([[2., 2.]])
clf.predict_proba([[2., 2.]])
결정 트리 분류 모델에 x = [0, 0] 일 때 y = 0이고, x = [1, 1] 일 때 y = 1인 훈련 데이터를 학습시켰다.
그리고 x = [2., 2.]일 때 y값을 예측했더니 1이 나왔다.
estimator.predict_proba 는 예측값을 비율로 출력하는 함수이다.
5. iris dataset 예제
from sklearn.datasets import load_iris
from sklearn import tree
import matplotlib.pyplot as plt
X, y = load_iris(return_X_y = True)
X, y # decisiontree 알고리즘이 숫자만 읽을 수 있기 때문에 카테고리 데이터 -> 숫자화
사이킷런 라이브러리에 내장되어 있는 아이리스 데이터셋을 불러왔다.
원래는 문자로 된 범주형 데이터지만, decision tree 알고리즘이 숫자만 읽을 수 있기 때문에 숫자로 변환한 것이다.
class Calculator {
Calculator() {
System.out.println("생성자 실행");
}
}
public class Helloworld {
public static void main(String[] args) {
Calculator calculator = new Calculator();
System.out.println("calculator 생성 완료");
}
}
이 예시는 Calculator 클래스에서 생성자가 호출될 때 "생성자 실행" 문구를 출력하도록 만들었다.
실행해보면 생성자 실행이 먼저 출력되고, calculator 생성 완료가 출력된다.
생성자는 보통 필드의 값을 초기화하기 위해 사용된다.
Calculator 클래스에 x, y라는 변수를 생성했다면 초기값을 설정해주어야 한다.
이렇게 초기값을 설정해 주는 것을 보통 생성자를 통해 한다.
class Calculator {
int x;
int y;
Calculator(int a, int b) {
this.x = a; // x에 a 대입
this.y = b;
}
}
이 예시의 경우 x, y 변수를 선언하고 생성자에서 int 자료형 데이터 2개를 받아 각각 x와 y에 저장한다.
메소드에서 입력 변수를 받는 방식과 비슷하다.
class Calculator {
int x;
int y;
Calculator (int x, int y) {
this.x = x;
this.y = y;
}
}
public class HelloWorld {
public static void main(String[] args) {
Calculator calculator = new Calculator(3, 5);
System.out.println(calculator.x);
System.out.println(calculator.y);
}
}
Calculator 클래스에서 Calculator 생성자를 만들고, calculator 객체를 만들면서 생성자를 이용해 x = 3, y = 5로 초기화 한 것이다.
이를 실행하면
3
5
이렇게 출력된다.
3. this 키워드
this는 인스턴스 (객체)를 가리키는 의미이다.
Calculato(int x, int y) {
this.x = x;
this.y = y;
위의 예제에서 this.x 는 인스턴스 내 필드를 가리키고, x는 입력받은 변수를 가리킨다.
- 문서들마다 길이가 다양한데, 길이가 긴 문서가 보통 더 많은 단어들을 가지고 있을 것이다.
- 그래서 긴 문서가 짧은 문서보다 더 중요하다거나 관련이 있다는 오해를 불러일으킬 수 있다.
- 각 TF는 다음과 같은 방식으로 정상화된다.
- 문서 안의 총 단어의 수 (document length) 로 나눈다.
- 혹은 corpus 안의 특정 단어의 빈도로 나눈다.
7. Inverse Document Frequency (IDF) 🌟
- TF는 하나의 문서에서 그 단어가 얼마나 많이 있는지를 측정한다.
- 우리는 또한 단어의 가중치를 결정할 때 전체 corpus에서 그것이 얼마나 만연한지를 고려할 수 있다.
- corpus에서 단어가 너무 희귀하거나 너무 많으면 클러스터링이나 분류를 할 때 도움이 되지 않는다. 무시하는 것이 낫다.
- 따라서 TF에 lower / upper limit을 둘 수 있다.
- 어떤 단어가 포함된 문서가 범위 내에서 적을수록 그 문서는 meaningful하다고 볼 수 있다.
- 이러한 단어 t의 희소성은 IDF에 의해 측정된다.
- IDF는 단어가 희귀할수록 크다.
- t를 포함한 문서가 많을수록 IDF는 1에 수렴한다.
8. Combining TF and IDF : TF-IDF 🌟
- 아주 대중적인 텍스트 표현이다.
- 문서 d에서 t에 대한 TF값과 전체 corpus에서 t에 대한 IDF값을 곱한 것이다.
- 따라서 TF-IDF는 하나의 문서에 한정되는 값이다.
- 각 문서가 feature vector가 된다.
- corpus는 feature vector의 집합이다.
- feature가 굉장히 많아지기 때문에 자주 선택을 해야하는데, 텍스트 표현에는 많은 잠재적 조건들이 있다.
- term count에 최대/최소 한계값을 걸거나 각 단어들을 중요도에 따라 순위를 매겨서 information gain을 측정하는 등의 방법이 있다.
9. (ex) Jazz musicians
- 위키피디아에서 15명의 유명한 재즈 음악가, 전문가들의 전기를 가져온 것이다.
- 문서가 15개로 작음에도 불구하고 corpus와 그에 담긴 단어들은 너무 많다.
- 접미사를 제거하고 stop-word까지 제거한 후에도 약 2,000개의 feature(단어)가 존재한다.
- 예시로 "Famous jazz saxophonist born in Kansas who palyed bebop and latin" 문장을 살펴보려고 한다.
- 우선 basic stemming 단계를 거친다.
- stemming 방법은 완벽하진 않다. 예를 들면 kansas와 famous를 명사의 복수형이라고 생각하여 kansa, famou 라고 저장할 수 있다.
- 하지만 이렇게 단어를 저장했다면 문서 전체에서 일관성있게 저장했을 것이기 때문에 stemming을 완벽하게 하는것은 그닥 중요하지 않다.
- stemming
- 샘플 문장의 단어들 (tokens)은 위와 같다.
- stop word (in, and)를 제거한 후 정상화된 TF는 위와 같다.
- 최종 TFIDF 값은 위와 같다.
- 이는 샘플 문서에 대한 feature vector이다.
- TFIDF가 클수록 (latin) 희귀한 단어이고, 작을수록 (jazz) 많이 나오는 단어이다.
- 단순한 검색 엔진을 실행하기 위해 이 TFIDF를 사용해보자.
- 사용자가 검색 쿼리에 "Famous jazz saxophonist born in Kansas who palyed bebop and latin" 이 문장을 입력했다고 하자.
- 그럼 우선 이 TF-IDF 표현으로 쿼리를 번역할 것이다.
- 그 다음, 각 음악가의 전기와 쿼리의 단어의 유사도를 각각 계산한 후 가장 가까운 전기를 고를 것이다.
- 이 때 텍스트 분류에서 두 문서 사이의 유사도를 측정할 때 가장 많이 사용되는 '코사인 유사도 cosine similarity'를 사용할 것이다.
- cosine similarity = x · y / ||x||₂ ||y||₂
- 유사도 결과를 보면 실제 예제에 해당하는 음악가인 'Charlie Parker'와의 유사도가 가장 큰 것을 볼 수 있다.
10. Beyond "Bag of Words"
- bag of words는 비교적 간단하지만 다양한 상황에서 놀랍게도 잘 수행된다.
- 보통 데이터 과학자가 새로운 텍스트 마이닝 문제를 볼 때 가장 먼저 선택하는 방법이다.
- 하지만, 더욱 정교한 기술이 필요한 애플리케이션에 사용하기엔 부족하다.
- 예를 들면 bag of words는 단어의 순서를 고려하지 않는다.
10-1. N-gram Sequences
- 단어의 순서가 중요하고 그에 대한 정보를 남기고 싶은 경우 사용한다.
- 인접한 단어의 순서를 항으로 포함하기 때문에 복잡도는 높아진다.
- ex) "The quick brown fox jumps"
- 문장을 구성하는 단어들 {quick, brown, fox, jumps} + {quick_brown, brown_fox, fox_jumps}
- 이 일반적인 표현 방법을 n-grams라고 부른다.
- 'Bag of n-grams up to three'
- 각 단어들, 인접한 단어쌍, 인접한 세 개의 단어쌍을 features로 하여 각 문서를 나타낸다.
- 장점 : easy to generate (언어학적 지식이나 복잡한 파싱 알고리즘을 알 필요가 없다.)
- 단점 : greatly increase the size of the feature set (각 단어를 저장할 때보다 더 많은 단어쌍이 포함되기 때문에 feature 집합의 크기가 매우 커진다.)
10-2. Named Entity Extraction
- 구절을 추출할 때 일반적으로 알려진 이름을 인식하길 바랄 수 있다.
- 예를 들면 Silicon Valley, Minnesota Twins, The Lord of the Rings 등과 같이 각 단어 별로 보면 아무 의미 없지만, 그 자체로 알려진 의미가 있는 구절들을 인식하고자 한다.
- basic bag of word나 n-grams 표현으로도 쉽지 않다. 왜냐하면 두 방법 모두 공백이나 구두점을 기반으로 텍스트를 분할하기 때문이다.
- 이 방법을 실행하기 위해서는 집약된 지식이 필요하다. 큰 corpus에 의해 학습되거나, 사람이 직접 개입해야 한다.
10-3. Topic Models
- 지금까지 살펴본 방법들은 문서에 있는 단어들로부터 직접적으로 모델을 만드는 방법이다.
- 이는 비교적 효율적이지만, 항상 최적의 방법인 것은 아니다.
- 단어와 문서가 복잡해지면 문서와 모델 사이에 추가적인 layer (topic layer) 를 만들 수 있다.
- 각 문장은 단어의 순서를 구성하고, 단어들은 적어도 하나의 토픽에 매핑된다.
- topic layer는 문서의 단어들의 클러스터들이라고 볼 수 있다.
- 장점) 검색엔진에서 입력된 쿼리가 문서의 특정 단어들과 완전히 똑같지 않을 수 있다. 이 때 그 단어를 알맞은 토픽에 매핑하고, 그와 관련된 문서를 보여준다.
11. (ex) Mining news stories to predict stock price movement
- 뉴스를 기반으로 주식 시장을 예측하고자 한다.
- 단순하게 하기 위해서 그 날 하루의 변화를 예측할 것이고, 정확한 값이 아닌 변화가 있는지 없는지만 예측할 것이다. 또한, 작은 변화는 예측이 어렵기 때문에 큰 변화가 있을 경우에 변화가 있다고 예측할 것이며, 주가는 그 기업의 이름이 명시되지 않은 뉴스에 의해서도 변화될 수 있지만, 이 예제의 경우 그것까지 고려하기 어렵기 때문에 기업의 이름이 명시된 뉴스에 한해서 마이닝을 할 것이다.
- -2.5% ~ 2.5% 의 변동이 있을 경우 '안정된 상태'라고 간주한다.
- -5% 이하, 5% 이상의 경우 변동이 있다고 간주한다. 그 사이는 고려하지 않는다.
- 지도학습을 위해 과거 데이터인 1999년 데이터를 사용한다.
- 샘플 뉴스이다.
- 1년 동안 주식회사 BEAM의 주가 그래프이다.
- 숫자로 표시된 각 지점에 주가가 오르고 내렸는데, 각 지점마다 회사 관련 뉴스가 있었다.
- 각 뉴스의 요약 주석이다.
- 데이터 전처리 : 각 뉴스를 TFIDF 표현으로 줄이기 위해 'bag of words' 단계를 적용한다.
- 각 단어는 소문자화 되었고, stopwords도 제거되었다.
- 'n-grams up to two'를 생성했다.
- 각 뉴스에는 관련 주가 움직임에 기반한 라벨이 붙어있다. (change or no change)
- 결과적으로 약 16000개의 태그된 뉴스가 나왔다.
- 예측 가능성을 보기 위해 ROC curve를 이용했다.
- 이 curves는 10-fold cross validation의 평균을 채택했다.
- 결과
- 뉴스 내용에는 예측가능한 신호가 있다.
- NB와 LR는 트리보다 더 성능이 좋다.
- 아래 그래프는 lift curves이다.
- 뉴스 기사를 점수를 매기고 정렬하기 위해 모델을 사용한다면 우리가 얻을 수 있는 Lift의 양을 정확히 보여준다.
- 결과
- x = 0.2인 경우에서 LR과 NB의 lift는 거의 2.0이다.
- 이는 만약 모든 뉴스 기사의 점수를 매기고 상위 20%만 선택했다면, positive 뉴스는 랜덤으로 예측된 것보다 2배의 정밀도를 보인다.
- 이전 장에서는 각 경우에 대한 결정을 expected value에 기반하여 어떻게 계산할 지 알아보았다.
- 이번에는 다른 전략으로 ranking에 대해 알아볼 것이다.
- 각 경우를 분리하여 결정하기보다는, 예측된 점수를 기반으로 사례들의 순위를 매긴 다음 상위 n개의 경우를 택하는 것이다.
- 많은 경우, 그저 가장 성능이 좋은 n개의 케이스를 원할 때가 있다. 예를 들어 캠페인을 위한 마케팅 예산이 이미 정해져 있는 경우가 그렇다.
- 이러한 경우 각 경우의 정확한 확률 추정치는 그닥 중요하지 않다.
- 정확한 확률값을 구하기보다 상대적인 순위를 통해서 가장 효율적인 몇가지 방법만 택하는 것이다.
3. Ranking Instances
- 개체에 점수를 매기는 classifier가 있다고 하자. 이때 점수는 확률값 (or distance)이다.
- ex) class probability(decision tree, k-NN classifier), distance from the separating boundary(support vector machine, logistic regression)
- 각 개체들을 점수에 따라 정렬한 후 특정한 값 T를 임계값으로 설정한다.
- 임계값을 높게 잡으면 정말 몇 개의 경우만 선택될 것이고, 임계값을 낮게 잡으면 가능한 많은 경우를 선택할 수 있을 것이다.
4. Thresholding Instances
- 임계값이 변할 때마다 true positive와 false positive의 수가 달라진다.
- 따라서, 각 임계값마다 특정한 confusion matrix가 형성된다.
- 임계값을 기준으로 높은 순위는 'YES', 낮은 순위는 'NO'라고 예측하기 때문이다.
- 임계값이 낮아질수록 개체들은 N에서 Y로 옮겨진다. (예측값이)
- (N, p) -> (Y, p), (N, n) -> (Y, n)
- 기술적으로, 각각의 임계값은 서로 다른 classifier를 생성한다.
- 그리고 각각의 confusion matrix를 통해 나타낸다.
- 그러면 다른 classifier에 의해 만들어진 순위는 서로 다른데 어떻게 비교해야 할까? 어떤 순위가 더 낫다고 볼 수 있을까?
- 또한, 적절한 임계값을 어떻게 찾을까?
- 이건 expected profit이 최대가 되는 임계값으로 결정할 수 있다.
5. Profit Curve
- 임계값에 따른 expected profit을 보여주는 곡선이다.
- 임계값이 낮아질수록 negative가 아니라 positive로 예측되는 개체들이 추가된다.
- 즉, 임계값이 낮아질수록 positive predict가 높아진다.
- 타겟 마케팅을 위한 3개의 classifier를 나타낸 profit curve이다.
- 각 곡선에 대해 고객들은 몇몇 모델에 기반하여 마케팅에 대해 응답할 확률에 따라 높은 확률부터 낮은 확률까지 정렬된다.
- 보통 고객의 비율에 대해 이야기할 것이다.
- x축은 임계값이고, y축은 그에 다른 이익이다.
- 곡선은 profit이 음수로 갈 수 있음을 보여준다. 항상 그런 것은 아니고 cost-benefit matrix에 따라 달라진다.
- 이윤이 작거나 응답자의 수가 작을 때 발생한다.
- 응답하지 않을 사람들에게 너무 많이 제공함으로써 비용을 너무 많이 지불하게 된다.
- 모든 곡선들은 같은 지점에서 시작해서 같은 지점에서 끝난다.
- 0%는 지출도 없고 이익도 없는 상태이다.
- 100%는 모든 사람들이 타겟이 된 상태이다. 따라서 모든 classifier가 같은 성능을 갖는다.
- 하지만, 그 사이에서는 classifier가 고객을 정렬한 방법에 따라 서로 다른 값을 갖는다.
- 직선인 경우는 random model을 적용한 경우로 최악의 성능을 갖는다.
- 위의 그래프에 따라 만약 마케팅에 예산이 정해져있어 8%의 고객에게만 제공할 수 있을 땐 x = 8 이내에서 가장 높은 값을 갖는 classifier 1을 선택하면 되고, 예산 상관없이 최고의 이익을 내고 싶다면 약 x = 50에서 가장 높은 값을 갖는 classifier 2를 선택하면 된다.
6. Two Limitation of Profit Curves
- 이전 장에서 본 조건부 확률을 이용하는 expected profit이다.
- 이 값을 이용하기 위해서는 사전확률인 p(p)와 p(n)을 알고 있어야 하고, 그 값은 안정적으로 고정되어 있어야 한다.
- 또한, cost와 benefit (b(h, a), c(h, a))도 알고 있어야 하고 안정적으로 고정되어 있어야 한다.
- 하지만, 많은 실제 경우에서는 이 값들은 정확하지 않고 불안정하다.
- ex) 사기 탐색의 경우 사기 금액이 정해져있지 않고 항상 변한다.
- churn 관리의 경우 고객에게 제공하는 상품의 금액이 항상 다를 것이다.
7. Receiver Operating Characteristic (ROC) Graph
- 전체 공간에 성능 가능성을 보여줌으로써 불확실성을 수용할 수 있는 방법이다.
- calssifier에 의해 만들어지는 benefits (true positives) 과 costs (false positives) 사이의 상대적인 성능값을 보여준다.