# fb는 리스트deffibo(fb):
a = 0
b = 1
fb.append(a)
fb.append(b)
whileTrue:
a, b = b, a+b
if b < n: break
fb.append(b)
피보나치 수열을 구하는 함수이다.
리스트에 우선 0과 1을 넣고, b가 n이 되기 전까지 a = b, b = a+b로 대입하여 b, 즉 a+b를 리스트에 추가한다.
n = 100000
fb = []
fibo(fb)
print(fb)
print("# of fibos", len(fb))
5. Prime Numbers
- 소수: 1보다 큰 자연수 중 1과 자기자신 이외의 수로 나누어 떨어지지 않는 수
deffind_prime(num):for i inrange(2, num+1):
prime = 1for j inrange(2, i):
if i % j == 0:
prime = 0breakif prime: prime_list.append(i)
2부터 num까지의 수를 각각 i로 둘 때, i를 2부터 i까지의 수로 나누어 본다.
이 때, 나누어 떨어지면 소수가 아니기 때문에 prime = 0으로 둔다.
i까지 전부 나눈 후 prime이 여전히 1이면 소수이기 때문에 prime_list에 추가한다.
이 과정을 num까지 반복한다.
prime_list = []
max_num = 1000
find_prime(max_num)
for i inrange(2, max_num):
if i in prime_list: print('%3d' %i, end = '')
else: print('_', end = '')
if i % 50 == 0: print()
print()
print('# of prime numbers = ', len(prime_list))
- 객체의 속성(attributes, properties, member variables)과 행동(methods, operations, member funtions)을 추상화하는 자료형
- 사용자가 필요에 의해 자료형을 직접 정의하는 것
- 객체지향 프로그래밍에서는 공통적인 행위를 하는 Class를 정의한다.
- ex) bank account, student, fraction
8. Fraction 분수
- 분자와 분모로 이루어져 있다.
- 기본적으로 분수는 내장되어있지 않기 때문에 객체로 정의해주어야 한다.
- 약분까지 해야 함 -> gcd(x, y)
classFraction:def__init__(self, up, down):
self.num = up
self.den = down
def__str__(self):returnstr(self.num) + '/' + str(self.den)
def__add__(self, other):
new num = self.num * other.den + self.den * other.num
new_den = self.den * other.den
common = self.gcd(new_num, new_den)
return Fraction(new_num//common, new_den//common
defmultiply(self, other):
new num = self.num * other.num
new_den = self.den * other.den
common = self.gcd(new_num, new_den)
return Fraction(new_num//common, new_den//common)
defgcd(self, a, b):while a % b != 0:
a, b = b, a % b
return b
def __init__(self, up, down)은 Fraction 클래스를 호출했을 때 두번째 매개변수 up을 self.num에, 세번째 매개변수 down을 self.den에 대입하는 메서드이다. 이때 self.num은 분자, self.den은 분모이다.
def __str__(self)는 print(Fraction(up, down)을 실행했을 때 호출되는 메서드이다. 분수형태로 출력해준다.
def __add__(self, other)는 덧셈 메서드이다. + 로 두 변수를 연결했을 때 자동으로 호출된다.
분자는 self의 분자 x other의 분모 + self의 분모 x other의 분자이고,
분모는 self의 분모 x other의 분모이다.
common은 덧셈 결과의 분자와 분모의 최대공약수로, 이후에 나올 gcd 메서드를 통해 구할 수 있다.
* 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 알고리즘이 숫자만 읽을 수 있기 때문에 숫자로 변환한 것이다.
- 문서들마다 길이가 다양한데, 길이가 긴 문서가 보통 더 많은 단어들을 가지고 있을 것이다.
- 그래서 긴 문서가 짧은 문서보다 더 중요하다거나 관련이 있다는 오해를 불러일으킬 수 있다.
- 각 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배의 정밀도를 보인다.