가중치 업데이트 →wj:=wj+Δwj →가중치 업데이트 값인 Δwj=η(y(i)−ˆy(i))x(i)j →η는 학습률로 0.0~0.1 사이의 값 →y(i)와 ˆy(i)는 각각 i번째 훈련 샘플의 정답 레이블, 예측 레이블
- 가중치 벡터의 모든 가중치는 동시에 업데이트
- 모든 가중치가 각자의 업데이트 값 Δwj에 의해 업데이트되기 전에 예측 레이블 ˆy(i)를 다시 계산하지 않음 → Δw0=η(y(i)−output(i)) → Δw1=η(y(i)−output(i))x(i)1 → Δw2=η(y(i)−output(i))x(i)2
- 퍼셉트론이 클래스 레이블을 정확히 예측하면 가중치 유지(업데이트 값은 0) → y(i)=−1,ˆy(i)=−1,Δwj=η(−1−(−1))x(i)j=0 → y(i)=1,ˆy(i)=1,Δwj=η(1−1)x(i)j=0 - 퍼셉트론이 클래스 레이블을 잘못 예측하면 가중치를 양성 또는 음성 타겟 클래스 방향으로 이동시킴 → y(i)=1,ˆy(i)=−1,Δwj=η(1−(−1))x(i)j=η(2)x(i)j → y(i)=−1,ˆy(i)=1,Δwj=η(−1−1)x(i)j=η(−2)x(i)j
- 가중치 업데이트는 x(i)j값에 비례하여, 이 값을 조절해 결정경계를 더 크게 움직이거나 더 작게 움직일 수 있음
- 퍼셉트론은 두 클래스가 선형적으로 구분되고 학습률이 충분히 작을 때만 수렴이 보장됨
- 선형 결정 경계로 나눌 수 없다면 훈련 데이터셋을 반복할 최대 횟수(epoch)를 지정해 분류 허용 오차 지정, 그렇지 않으면 퍼셉트론은 가중치 업데이트를 멈추지 않음
퍼셉트론 알고리즘
4. 파이썬으로 퍼셉트론 학습 알고리즘 구현
- 퍼셉트론 클래스 정의
import numpy as np
classPerceptron(object):def__init__(self, eta = 0.01, n_iter = 50, random_state = 1):
self.eta = eta
self.n_iter = n_iter
self.random_state = random_state
deffit(self, X, y):
rgen = np.random.RandomState(self.random_state) # 난수 생성기 객체 생성(격리된 시드 부여 가능, 이전과 동일한 랜덤 시드 재현 가능)
self.w_ = rgen.normal(loc = 0.0, scale = 0.01,
size = 1 + X.shape[1]) # 평균 0, 표준편차 0.01의 정규분포에서 훈련 데이터 개수(X.shape[1]) + 절편(1)만큼의 난수 생성
self.errors_ = [] # 훈련 중 error의 감소 확인을 위한 객체for _ inrange(self.n_iter):
errors = 0for xi, target inzip(X, y):
update = self.eta * (target - self.predict(xi)) # 가중치 w_j의 변화량
self.w_[1:] += update * xi # 각 훈련 데이터에 가중치값 곱하기
self.w_[0] += update # 가중치값 업데이트
errors += int(update != 0.0) # 업데이트 된 값이 0이 아니면(실제값과 예측값이 다르면) errors에 1 더함
self.errors_.append(errors) # 전체 훈련 데이터에서 예측값이 실제값과 다르게 나온 횟수 추가return self
# 최종입력인 Z 계산defnet_input(self, X):return np.dot(X, self.w_[1:]) + self.w_[0]
# 결정함수를 임계값인 0과 비교, 크거나 같으면 1, 작으면 -1로 반환defpredict(self, X):return np.where(self.net_input(X) >= 0, 1, -1)
- fit 메서드 내의 w_객체에 가중치를 초기화하여 선언 - 가중치가 0이 아니어야 학습률(eta)가 분류 결과에 영향을 줄 수 있어 0이 아닌 랜덤 값으로 초기화 - 가중치가 0이면 eta는 가중치 벡터의 방향이 아니라 크기에만 영향을 미침
- 붓꽃 데이터셋에서 퍼셉트론 훈련 - Perceptron은 이진분류이므로 setosa와 versicolor에 대해서만 분류 진행 - 또한, 특성은 첫번째 특성(꽃받침 길이)와 세번째 특성(꽃잎 길이)을 사용
import pandas as pd
import matplotlib.pyplot as plt
s = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
df = pd.read_csv(s, header = None, encoding = 'utf-8')
# 처음 100개의 데이터(setosa 50개와 versicolor 50개)의 다섯번째 열인 예측 대상을 y로 선언
y = df.iloc[0:100, 4].values
# setosa이면 -1, versicolor이면 1로 변경
y = np.where(y == 'Iris-setosa', -1, 1)
# 처음 100개의 데이터에서 예측에 사용하고자 하는 특성인 첫번재 열과 세번째 열만 추출
X = df.iloc[0:100, [0, 2]].values
# 산점도로 시각화
plt.scatter(X[:50, 0], X[:50, 1], color = 'red', marker = 'o', label = 'setose')
plt.scatter(X[50:100, 0], X[50:100, 1], color = 'blue', marker = 'x', label = 'versicolor')
plt.xlabel('sepal length [cm]')
plt.ylabel('petal length [cm]')
plt.legend(loc = 'upper left')
plt.show()
# Perceptron 알고리즘 훈련
ppn = Perceptron(eta = 0.1, n_iter = 10)
ppn.fit(X, y)
# 훈련 과정에서 각 반복에서 나온 오차의 개수 시각화
plt.plot(range(1, len(ppn.errors_) + 1), ppn.errors_, marker = 'o')
plt.xlabel('Epochs')
plt.ylabel('Number of updates')
plt.show()
from matplotlib.colors import ListedColormap
# 결정경계 시각화 함수defplot_decision_regions(X, y, classifier, resolution = 0.02):
markers = ('s', 'x', 'o', '^', 'v')
colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
cmap = ListedColormap(colors[:len(np.unique(y))])
# 두 특성의 최소값과 최대값에 각각 -1, +1을 한 값을 정의
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1# 위에서 구한 최소값과 최대값을 시작으로 하는 meshgrid 생성(최소값과 최대값 사이에 0.02의 간격으로 데이터 생성)
xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
np.arange(x2_min, x2_max, resolution))
# ravel 함수로 meshgrid를 1차원으로 평평하게 펴고, xx1, xx2를 각각 X, y로 Perceptron에 넣어 예측
Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
# 예측된 값을 다시 meshgrid 형태로 변경
Z = Z.reshape(xx1.shape)
# contourf 함수로 등고선 그래프 그리기(등고선이 두 집단의 경계로 그려짐)# 분류된 값이 -1인 것과 1인 것을 각각 빨간색과 파란색으로 구분
plt.contourf(xx1, xx2, Z, alpha = 0.3, cmap = cmap)
plt.xlim(xx1.min(), xx1.max())
plt.ylim(xx2.min(), xx2.max())
# 훈련 데이터를 빨간색 네모 모양와 파란색 x모양으로 구분for idx, cl inenumerate(np.unique(y)):
plt.scatter(x = X[y == cl, 0], y = X[y == cl, 1],
alpha = 0.8, c = colors[idx], marker = markers[idx], label = cl, edgecolor = 'black')
plot_decision_regions(X, y, classifier = ppn)
plt.xlabel('sepal length [cm]')
plt.ylabel('petal length [cm]')
plt.legend(loc = 'upper left')
plt.show()
- OvR(One-versus-Resr)기법을 사용하면 이진 분류기로 다중 클래스 문제 해결 가능 →클래스마다 하나의 분류기를 훈련(각 클래스를 양성으로 분류하고 나머지는 음성으로 분류) →레이블이 없는 새로운 데이터 샘플 분류 시에는 클래스 레이블의 개수와 같은 n개의 분류기 사용 → 신뢰도가 가장 높은 클래스 레이블(최종 입력의 절댓값이 가장 큰 클래스)을 분류하려는 샘플의 레이블로 선택
- 퍼셉트론의 가장 큰 문제는 수렴 → 구 클래스가 선형적인 초평면으로 구분될 수 있을 때 수렴하지만, 선형 결정 경계로 완벽하게 구분되지 않으면 최대 epoch를 지정하지 않는한 가중치 업데이트가 멈추지 않음
● 예시로 '월간 데이콘 쇼츠 - 초전도체 임계온도 예측 AI 헤커톤'의 데이터 사용(train, test, submission 파일 3개 존재)
1. 모듈 임포트
import os
# Seed 고정defseed_everything(seed):
random.seed(seed)
os.environ['PYTHONHASHSEED'] = str(seed)
np.random.seed(seed)
seed_everything(42)
# warning 무시import warnings
warnings.filterwarnings("ignore")
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor
from sklearn.tree import DecisionTreeClassifier, DicisionTreeRegressor
from sklearn.linear_model import LogisticRegression, LinearRegression
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import accuracy_score, mean_squared_error, mean_absolute_error, r2_score
2. 데이터 불러오기
train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')
submission = pd.read_csv('sample_submission.csv')
3. 데이터 탐색
train.head() # 처음 5개의 데이터 (전체적인 데이터 구조 확인)
train.info() # 데이터에 대한 개략적인 정보 (행과 열 개수, non-null값 개수, 데이터 타입)
train.describe() # 숫자형 데이터 요약 (개수, 평균, 표준편차, 최소값, 25%, 50%, 75%, 최대값)
train.isna().sum() # 각 데이터의 결측값 개수# 이외에도 이해가 가지 않는 행이나 열만 따로 뽑아서 탐색, 데이터 도메인 지식 등을 찾아보며 데이터에 대한 이해 필요
train = train.drop('ID', axis = 1) # train 데이터 탐색 결과 단순 식별자 변수인 ID는 필요 없는 것으로 판단, 삭제
feature = train.copy() # 밑에서 target변수를 제거하고 feature 변수만 남긴 데이터
target = feature.pop('critical_temp') # target 데이터 추출, train에는 feature 데이터만 남음
- train.head(): 처음 5개의 데이터 (전체적인 데이터 구조 확인)
- train.info(): 데이터에 대한 개략적인 정보 (행과 열 개수, non-null값 개수, 데이터 타입)
scaler = StandardScaler() # 박스플롯 출력 전 하나의 박스플롯에서 데이터를 한눈에 보기 위해 같은 범위로 임시 스케일링
plt.figure(figsize = (15, 10))
sns.boxplot(scaler.fit_transform(feature))
- 각 feature 데이터의 바이오린 플롯과 히스토그램 출력하여 데이터 분포 확인
for col in train.columns:
fig, axs = plt.subplots(nrows = 1, ncols = 2, figsize = (10, 4))
sns.violinplot(x = col, data = train, kde = True, ax = axs[0])
sns.histplot(x = col, data = train, kde = True, ax = axs[1])
# 방법 1. 결측값이 있는 행 제거
feature = feature.dropna(axis = 0, how = 'any') # 각 행에서 하나의 값이라도 NaN이면 해당 행 제거
feature = feature.dropna(axis = 0, how = 'all') # 각 행의 모든 값이 NaN이면 해당 행 제거# 방법 2. 결측값 채우기(특정 값으로 채우기)
feature = feature.fillna(0) # 0으로 채우기
feature = feature.fillna(method = 'pad') # 바로 앞의 값으로 채우기
feature = feature.fillna(method = 'bfill') # 바로 뒤의 값으로 채우기
feature = feature.fillna(feature.mean()) # 해당 열의 평균값으로 채우기# 방법 3. 결측값 채우기(보간법)
feature = feature.interpolate(method = 'time') # 인덱스가 날짜/시간일 때 날짜나 시간에 따라 보간
feature = feature.interpolate(method = 'nearest', limit_direction = 'forward') # 가장 가까운 값으로 보간
feature = feature.interpolate(method = 'linear', limit_direction = 'forward') # 양 끝값에 따라 선형식에 적용하여 보간
feature = feature.interpolate(method = 'polynomial', order = 2) # 양 끝값에 따라 다항식에 적용하여 보간 (order은 다항식 차수)# 방법 4. 결측값이 있는 열을 해당 열의 결측값이 아닌 행과 다른 feature 변수들로 예측하여 채우기
feature_target = feature.pop('결측값 열') # 다른 행들로부터 결측값을 예측할 목표열 분리
target_index = feature_target[feature_target['결측값 열'] == np.nan].index # 목표열 중 결측값인 행의 인덱스 추출
feature_train = feature.iloc[~target_index] # 목표열이 아닌 다른 열에서 결측값이 있는 행의 인덱스가 아닌 행 추축(train 용)
feature_test = feature.iloc[target_index] # 목표열이 아닌 다른 열에서 결측값이 있는 행의 인덱스인 행 추출(test 용)
feature_target_train = feature_target[~target_index] # 목표열 중 결측값이 아닌 행 추출(train 용)
rf = RandomForestRegressor() # 랜덤포레스트로 예측
rf.fit(feature_train, feature_target_train) # 랜덤포레스트에 목표열 중 결측값이 아닌 행을 target 변수, 다른 열의 해당 행들을 feature 변수로 모델 피팅
pred = rf.predict(feature_test) # 피팅된 모델로 목표열에서 결측값인 행 예측
feature.iloc[target_index]['결측값 열'] = pred # 원래 데이터프레임에서 목표열의 결측값인 값을 위에서 예측한 값으로 대체
# 방법 1. 문자형 변수 라벨 인코딩
encoder = LabelEncoder()
feature[[feature.select_dtypes(object).columns]] = encoder.fit_transform(feature.select_dtypes(object))
test[[test.select_dtypes(object).columns]] = encoder.transform(test.select_dtypes(object))
# 방법 2. 문자형 변수 원핫 인코딩
encoder = OneHotEncoder()
feature[[feature.select_dtypes(object).columns]] = encoder.fit_transform(feature.select_dtypes(object).toarray())
test[[test.select_dtypes(object).columns]] = encoder.transform(test.select_dtypes(object).toarray())
- 라벨 인코딩은 문자형 변수 고윳값의 개수에 따라 0부터 n-1까지의 숫자로 변환되어 ML에서 왜곡된 결과를 불러올 수 있음
- 원핫 인코딩은 이런 문제를 해결하기 위해 고윳값의 개수만큼 새로운 feature 변수를 생성하여 각 행에서 고윳값에 해당하는 feature만 1, 나머지는 0으로 표시
9. 모델 피팅 및 예측
# feature 변수와 target 변수 분리
X = feature
y = target
# 학습용 데이터(X_train, y_train)와 검증용 데이터(X_test, y_test)로 분리
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2)
# 모델 선언(사용할 모델로 선정, 예시로는 RandomForestRegressor 선정)
model = RandomForestRegressor()
# 모델 학습
model.fit(X_train, y_train)
# 학습된 모델로 검증용 데이터 예측
y_pred = rf.predict(X_test)
# 실제 검증용 데이터와 예측한 검증용 데이터 비교하여 점수 출력print(f'mse: {mean_squared_error(y_test, y_pred)}\nmae: {mean_absolute_error(y_test. y_pred)}\naccuracy: {accuracy_score(y_test, y_pred)}')
- KFold와 cross_val_score에서 각각 평균 정확도가 다른 이유는 cross_val_score가 StratifiedKFold를 이용해 폴드 세트를 분할하기 때문
# 방법 3. GridSearchCV
params = {'max_depth': [2, 3, 5, 10], 'min_samples_split': [2, 3, 5], 'min_samples_leaf': [1, 5, 8]} # 사용할 모델에 맞는 하이퍼 파라미터 중 탐색하고 싶은 범위 지정
grid_model = GridSearchCV(model, param_grid = params, scoring = 'accuracy', cv = 5, verbose = 3) # GridSearchCV에 model, 하이퍼 파라미터, 점수, 교차검증 횟수 등을 파라미터로 지정
grid_model.fit(X_train, y_train) # GridSearchCV 모델에 train 데이터 피팅print(f'GridSearchCV 최적 하이퍼 파라미터: {grid_model.best_params_}') # 최적 하이퍼 파라미터print(f'GridSearchCV 최고 정확도: {grid_model.best_score_:.4f}') # 최적 하이퍼 파라미터일 때 나온 최고 점수
best_model = grid_model.best_estimator_ # 최적 하이퍼 파라미터로 최고 점수가 나온 모델을 best_model로 저장
y_pred = best_model.predict(X_test) # best_model로 test 데이터 예측
accuracy = accuracy_score(y_test, y_pred) # 점수 계산print(f'테스트 세트에서의 model 정확도: {accuracy:.4f}')
11. 기본 분석 이후
- pycaret, autogluon 등 auto ML을 사용해 최적의 모델 선택
- 데이터에 대한 깊은 이해를 통해 더 최적의 변수 선택 및 전처리, 차원 축소 및 군집화 등으로 파생변수 생성
조건을 넣어 True인 값만 출력하도록 하면 조건에 맞지 않는 값은 삭제된 것과 같은 상태
import pandas as pd
df = pd.read_csv('titanic.csv')
# 데이터프레임에서 Sex열의 값이 male이 아닌 것 즉, female인 것만 출력, male은 삭제되고 female인 것만 출력됨
df[df['Sex'] != 'male'].head(2)
# 행의 인덱스를 사용해 하나의 행을 삭제할 수 있음# 인덱스가 0인 행만 제외하고 나머지 출력
df[df.index != 0].head(2)
12. 중복된 행 삭제하기
drop_duplicates 사용(매개변수 사용에 주의)
# drop_duplicates를 매개변수 없이 사용하면 완벽하게 같은 행만 삭제되어 예시로 사용하는 타이타닉 데이터에서는 삭제되는 열이 없음print('원본 데이터프레임 행의 수: {}'.format(len(df)))
print('drop_duplicates 사용한 데이터프레임 행의 수: {}'.format(len(df.drop_duplicates())))
# 출력 결과
원본 데이터프레임 행의 수: 891
drop_duplicates 사용한 데이터프레임 행의 수: 891
# 따라서 중복을 비교할 열을 subset 매개변수에 전달하여야 함# Sex 변수에서 중복되는 값이 전부 제거되고 제일 처음 male값을 가지는 행과 female 값을 가지는 행만 남아 출력됨
df.drop_duplicates(subset = ['Sex'])
# keep 매개변수에 last를 전달하면 가장 마지막에 남은 male값과 female값만 하나씩 출력됨
df.drop_duplicates(subset = ['Sex'], keep = 'last')
13. 값에 따라 행을 그룹핑하기
groupby('그루핑할 열')['통계 계산을 할 열'].통계계산(mean, sum, count 등)
# 성별로 그루핑하여 각 성별의 나이 평균 계산
df.groupby('Sex')['Age'].mean()
# 출력 결과
Sex
female 27.915709
male 30.726645
Name: Age, dtype: float64
첫 번째 열로 그루핑한 다음 두 번째 열로 다시 그룹핑하기
# 성별로 구루핑 하고 각 성별 중 생존 여부에 따라 다시 그루핑# 이후 총 4개의 그룹 각각의 나이 평균 계산
df.groupby(['Sex', 'Survived'])['Age'].mean()
# 출력 결과
Sex Survived
female 0 25.046875
1 28.847716
male 0 31.618056
1 27.276022
Name: Age, dtype: float64
14. 시간에 따라 행을 그루핑하기
시간을 인덱스로 하는 예시 데이터프레임 생성
import pandas as pd
import numpy as np
# 2023/06/26부터 30초 간격으로 100,000개의 시간 데이터를 인덱스로 생성
time_index = pd.date_range('06/26/2023', periods = 100000, freq = '30s')
# 위에서 생성한 시간 인덱스를 인덱스로하고, 1~10사이의 숫자 중 랜덤하게 100,000개를 뽑은 것을 각 시간의 값으로 생성
df = pd.DataFrame(index = time_index)
df['Sale_Amount'] = np.random.randint(1, 10, 100000)
df
# 일주일 단위로 행을 그루핑
df.resample('W').sum()
시간 단위
'W': 1주 단위
'2W': 2주 단위
'M': 1달 단위
'MS': 1달 단위, 그루핑된 인덱스를 월의 시작 날짜로
label = 'left' 옵션: 인덱스를 그루핑된 그룹의 마지막 레이블이 아닌 그 전 그룹의 마지막 레이블로 변환
# 데이터프레임의 ['Name']열에 속한 값들을 하나씩 차례대로 name으로 지정하여 출력(상위 2개의 열에만 예시로 적용)for name in df['Name'][0:2]:
print(name.upper())
16. 모든 열 원소에 함수 적용하기
데이터프레임의 특정 열의 모든 값에 동시에 함수를 적용
# 문자를 대문자로 출력하는 함수 생성
def uppercase(x):
return x.upper()
# 위에서 생성한 함수를 데이터프레임의 'Name'열에 한번에 적용(상위 2개의 열에만 예시로 적용)
df['Name'].apply(uppercase)[0:2]
map 함수도 apply 함수와 비슷하지만 map 메서드는 딕셔너리를 입력으로 넣을 수 있고 apply 메서드는 매개변수를 지정할 수 있음
# 딕셔너리 형태로 Survived 열의 1값은 Live, 0값은 Dead로 변경
df['Survived'].map({1 : 'Live', 0 : 'Dead'})[:5]
apply 메서드에서 age라는 매개변수 전달
# age = 30이라는 매개변수 전달, Age열의 값이 전달받은 age보다 작은지에 대한 boolean 값 return
df['Age'].apply(lambda x, age: x < age, age = 30)[:5]
applymap 메서드로 전체 데이터프레임에 함수 적용 가능
# 문자값으로 이루어진 열에 대해 최대 길이를 20자로 제한하는 함수
def truncate_string(x):
iftype(x) == str:
return x[:20]
else:
return x
전체 데이터프레임에 적용
df.applymap(truncate_string)[:5]
17. 그룹에 함수 적용하기
# Sex열로 그루핑하여 male 그룹과 female 그룹의 다른 열들 각각에 lambda 함수 적용
df.groupby('Sex').apply(lambda x: x.count())
# 방법 2(numpy 배열을 dataframe으로)import numpy as np
data = [['Jacky Jackson', 38, True], ['Steven Stevencon', 25, False]]
matrix = np.array(data)
pd.DataFrame(matrix, columns = ['Name', 'Age', 'Driver'])
# or
pd.DataFrame(data, columns = ['Name', 'Age', 'Driver'])
# 방법 3(dictionary를 dataframe으로)
data = {'Name': ['Jacky Jackson', 'Steven Stevenson'],
'Age': [38, 25],
'Driver': [True, False]}
pd.DataFrame(data)
# 방법 4(각각의 데이터를 dictionary로, 각 dictionary를 병합)
data = [{'Name': 'Jacky Jackson', 'Age': 25, 'Driver': True},
{'Name': 'Steven Stevenson', 'Age': 38, 'Driver': False}]
# 인덱스 따로 지정 가능
pd.DataFrame(data, index = ['row1', 'row2'])
2. 데이터 설명하기
데이터를 적재한 후 확인하는 가장 간단한 방법은 head()를 통해 상위 몇 개의 데이터만 출력해서 확인해보는 것
tail()을 사용하면 하위 데이터 출력
df = pd.read_csv('titanic.csv')
# 데이터의 상위 2행만 출력
df.head(2)
데이터의 열과 행의 개수 확인
df.shape
# 출력 결과
(891, 12)
describe()를 사용하여 숫자데이터 열의 통계값 확인
df.describe()
3. 데이터프레임 탐색하기
loc 또는 iloc를 사용해 하나 이상의 행이나 값을 선택
loc와 iloc 슬라이싱은 numpy와 달리 마지막 인덱스를 포함
# 첫번째 행 출력
df.iloc[0]
# 출력 결과
PassengerId 1
Survived 0
Pclass 3
Name Braund, Mr. Owen Harris
Sex male
Age 22.0
SibSp 1
Parch 0
Ticket A/521171
Fare 7.25
Cabin NaN
Embarked S
Name: 0, dtype: object
# 콜론(:)을 사용하여 행 슬라이싱# 첫번째 행부터 네번째 행까지 출력
df.iloc[1:4]
# 슬라이싱의 첫 부분을 공백으로 두면 처음부터 선택# 슬라이싱의 마지막 부분을 공백으로 두면 마지막까지 선택
df.iloc[:4]
# 데이터프레임에서 행마다 고유한 값을 갖는 특정 열을 인덱스로 설정# loc를 사용해 고유값으로 해당 행을 슬라이싱 가능
df_name_index = df.set_index(df['Name'])
df_name_index.loc['Braund, Mr. Owen Harris']
# 출력 결과
PassengerId 1
Survived 0
Pclass 3
Name Braund, Mr. Owen Harris
Sex male
Age 22.0
SibSp 1
Parch 0
Ticket A/521171
Fare 7.25
Cabin NaN
Embarked S
Name: Braund, Mr. Owen Harris, dtype: object
# 열을 선택하여 선택한 열만 출력하기도 가능
df[['Age', 'Sex']].head(2)
4. 조건에 따라 행 선택하기
# 데이터프레임 df[] 안에 조건문인 df['Sex'] == female을 넣어서 True인 행만 출력
df[df['Sex'] == 'female'].head(2)
# &를 사용해 조건 두 개이상도 검색 가능
df[(df['Sex'] == 'female') & (df['Age'] >= 60)].head(2)
5. 값 치환하기
df['Sex'].replace('female', 'woman').head(2)
# 출력 결과0 male
1 woman
Name: Sex, dtype: object# 두 개 이상도 한번에 치환 가능
df['Sex'].replace(['female', 'male'], ['woman', 'man']).head(5)
# 출력 결과0 man
1 woman
2 woman
3 woman
4 man
Name: Sex, dtype: object# 한번에 여러 값은 하나의 값으로 치환 가능
df['Sex'].replace(['female', 'male'], 'person').head(5)
# 출력 결과0 person
1 person
2 person
3 person
4 person
Name: Sex, dtype: object# 치환할 여러 값을 딕셔너리 형태로 전달 가능
df['Sex'].replace({'female' : 1, 'male' : 0}).head(5)
# 출력 결과0011213140
Name: Sex, dtype: int64
# 위에서 하나의 열뿐 아니라 데이터프레임 전체의 모든 값을 한번에 치환 가능
df.replace(1, 'one').head(2)
df.count()
# 출력 결과
PassengerId 891
Survived 891
Pclass 891
Name 891
Sex 891
Age 714
SibSp 891
Parch 891
Ticket 891
Fare 891
Cabin 204
Embarked 889
dtype: int64
8. 고유값 찾기
unique 메서드를 사용해 열에서 고유한 값을 모두 찾음
df['Sex'].unique()
# 출력 결과
array(['male', 'female'], dtype=object)
nunique 메서드는 unique 값의 개수를 출력
df['Sex'].nunique()
# 출력 결과2# nunique는 데이터프레임 전체에 적용 가능
df.nunique()
# 출력 결과
PassengerId 891
Survived 2
Pclass 3
Name 891
Sex 2
Age 88
SibSp 7
Parch 7
Ticket 681
Fare 248
Cabin 147
Embarked 3
dtype: int64
value_counts() 메서드를 사용해 열에서 고유한 값 각각의 개수 출력
df['Sex'].value_counts()
# 출력 결과
Sex
male 577
female 314
Name: count, dtype: int64
9. 누락된 값 다루기
isnull()과 notnull() 메서드는 null인지 아닌지에 대한 답을 boolean값(True나 False)으로 나타냄
# 조건으로 isnull()을 주어 True나 False의 값이 나오므로 True인 행만 찾아 출력 가능
df[df['Age'].isnull()].head()
read_csv() 메서드에서 na_values = [] 옵션을 사용해 null 값으로 선언할 값들은 지정
read_csv() 메서드에서 keep_default_na 옵션을 False로 하여 pandas에서 기본적으로 null 값으로 인식하는 값을을 null값이 아니게 만들 수 있음
read_csv() 메서드에서 na_filter 옵션을 False로 하면 NaN 변환을 하지 않음
10. 열 삭제하기
drop() 메서드 사용
# 축은 열을 나타내는 1로 지정
df.drop('Age', axis = 1)
한 번에 여러개의 열 삭제 가능
df.drop(['Age', 'Sex'], axis = 1)
열 이름이 없다면 열의 인덱스 번호를 사용해 삭제 가능
# 인덱스가 1인 열(두번째 열) 삭제
df.drop(df.columns[1], axis = 1)
del df['Age']를 사용해 열을 삭제할 수 있지만 이는 원보 데이터프레임을 바꿔 원본 데이터의 손상을 유발할 수 있어 추천 X
digits.keys()
# 출력 결과
dict_keys(['data', 'target', 'frame', 'feature_names', 'target_names', 'images', 'DESCR'])
# DESCR 키는 데이터셋에 대한 설명print(digits['DESCR'])
# 출력 결과
.. _digits_dataset:
Optical recognition of handwritten digits dataset
--------------------------------------------------
**Data Set Characteristics:**
:Number of Instances: 1797
:Number of Attributes: 64
:Attribute Information: 8x8 image of integer pixels in the range0..16.
:Missing Attribute Values: None
:Creator: E. Alpaydin (alpaydin '@' boun.edu.tr)
:Date: July; 1998
This is a copy of the test set of the UCI ML hand-written digits datasets
https://archive.ics.uci.edu/ml/datasets/Optical+Recognition+of+Handwritten+Digits
The data set contains images of hand-written digits: 10 classes where
each classreferstoadigit.
PreprocessingprogramsmadeavailablebyNISTwereusedtoextractnormalizedbitmapsofhandwrittendigitsfromapreprintedform. Fromatotalof 43 people, 30 contributedtothetrainingsetanddifferent 13
tothetestset. 32x32bitmapsaredividedintononoverlappingblocksof
4x4andthenumberofonpixelsarecountedineachblock. Thisgenerates
...
2005.
- ClaudioGentile. ANewApproximateMaximalMarginClassificationAlgorithm. NIPS. 2000.
load_데이터셋의 유일한 매개변수인 return_X_y를 True로 하면 특성 X와 타깃 y배열을 반환
import numpy as np
# digits 함수는 특별히 n_class 매개변수를 사용하여 필요한 숫자 개수 지정가능# 0~4까지 5개의 숫자만 y값에 넣도록 매개변수 설정
X, y = datasets.load_digits(n_class = 5, return_X_y = True)
np.unique(y)
# 출력 결과
array([0, 1, 2, 3, 4])
2. 모의 데이터셋 만들기
선형 회귀 알고리즘에 사용하려면 make_regression 추천
make_regression은 실수 특성 행렬과 실수 타깃 벡터 반환
from sklearn.datasets import make_regression
# n_features는 전체 특성# n_informative는 타깃 벡터 생성에 사용할 특성
features, target, coefiicients = make_regression(n_samples = 100,
n_features = 3,
n_informative = 3,
n_targets = 1,
noise = 0.0,
coef = True,
random_state = 1)
from sklearn.datasets import make_regression
features, target, coefiicients = make_regression(n_samples = 100,
n_features = 3,
n_informative = 3,
n_targets = 1,
noise = 0.0,
coef = True,
random_state = 1)
print('특성 행렬\n', features[:3])
print('타깃 벡터\n', target[:3])
# 출력 결과
특성 행렬
[[ 1.29322588 -0.61736206 -0.11044703]
[-2.7930850.366332011.93752881]
[ 0.80186103 -0.186569770.0465673 ]]
타깃 벡터
[-10.3786598625.512450319.67705609]
분류 알고리즘에 사용하려면 make_classification 추천
make_classification은 실수 특성 행렬과 정수 타깃 벡터 반환
from sklearn.datasets import make_classification
# n_redundant는 필요없는 특성의 수, n_informative 특성의 랜덤 선형 결합으로 생성됨# weights는 차례대로 각각 첫번째 ,두번째 클래스의 비율
features, target = make_classification(n_samples = 100,
n_features = 3,
n_informative = 3,
n_redundant = 0,
n_classes = 2,
weights = [.25, .75],
random_state = 1)
print('특성 행렬\n', features[:3])
print('타깃 벡터\n', target[:3])
# 출력 결과
특성 행렬
[[ 1.06354768 -1.426322191.02163151]
[ 0.231569771.495352610.33251578]
[ 0.159729510.83533515 -0.40869554]]
타깃 벡터
[100]
군집 알고리즘에 사용하려면 make_blobs 추천
make_blobs은 실수 특성 행렬과 정수 타깃 벡터 반환
from sklearn.datasets import make_blobs
features, target = make_blobs(n_samples = 100,
n_features = 2,
centers = 3,
cluster_std = 0.5,
shuffle = True,
random_state = 1)
print('특성 행렬\n', features[:3])
print('타깃 벡터\n', target[:3])
# 출력 결과
특성 행렬
[[ -1.226856093.25572052]
[ -9.57463218 -4.38310652]
[-10.71976941 -4.20558148]]
타깃 벡터
[011]
# 만들어진 군집 데이터 시각화# pip install matplotlibimport matplotlib.pyplot as plt
plt.scatter(features[:, 0], features[:, 1], c = target)
plt.show()
3. CSV 파일 적재하기
pandas 라이브러리의 read_csv() 사용
매개변수
sep = ',': 파일이 사용하는 구분자를 ','로 지정
skiprows = range(1, 11): 1행부터 12행까지 건너뛴 후 출력
nrows = 1: 한 행 출력
import pandas as pd
dataframe = pd.read_csv('csv 경로')
4. 엑셀 파일 적재하기
pandas 라이브러리의 read_excel() 사용
read_excel()을 사용하려면 xlrd 패키지 설치 필요
매개변수
sheet_name: 시트 이름 문자열 또는 시트의 위치를 나타내는 정수(0부터 시작되는 인덱스)
na_filter: 결측값 탐지, 결측값이 없는 데이터라면 해당 옵션을 제외하는 것이 성능 향상에 도움
먼저, SQLite 데이터베이스 엔진으로 연결하기 위해 create_engine 함수 사용
이후, read_sql_query 함수로 SQL을 사용하여 데이터베이스에 질의, 그 결과를 데이터프레임으로 가져옴
# pip install sqlalchemyimport pandas as pd
from sqlalchemy import create_engine
# sample.db라는 데이터베이스에 연결
database_connection = create_engine('sqlite:///sample.db')
# sample.db에서 data라는 이름의 테이블의 모든 열을 반환하라고 요청
dataframe = pd.read_sql_query('SELECT * FROM data', database_connection)
# 모든 행을 가져올 때는 질의문 없이 read_sql_table() 함수도 사용 가능
dataframe = pd.read_sql_table('data', database_connection)
from tensorflow.keras.datasets import imdb
(x_train, y_train), (x_test, y_test) = imdb.load_data()
단어 번호와 단어의 관계를 사전으로 만듦
1번은 문장의 시작, 2번은 사전에 없는 단어(OOV)로 미리 지정
word_index = imdb.get_word_index()
index_word = {idx + 3 : word for word, idx in word_index.items()}
index_word[1] = '<START>'
index_word[2] = '<UNKNOWN>'' '.join(index_word[i] for i in x_train[0])
# 출력 결과"<START> this film was just brilliant casting location scenery story direction everyone's really
suited the part they played and you could just imagine being there robert redford's is an
amazing actor and now the same being director norman's father came from the same scottish
island as myself so i loved the fact there was a real connection with this film the witty
remarks throughout the film were great it was just brilliant so much that i bought the film
as soon as it was released for retail and would recommend it to everyone to watch and the fly
fishing was amazing really cried at the end it was so sad and you know what they say if you
cry at a film it must have been good and this definitely was also congratulations to the two
little boy's that played the part's of norman and paul they were just brilliant children are
often left out of the praising list i think because the stars that play them all grown up are
such a big profile for the whole film but these children are amazing and should be praised for
what they have done don't you think the whole story was so lovely because it was true and was
someone's life after all that was shared with us all"
num_words = max(index_word) + 1
- 텍스트를 단어 번호로 바꾸기
texts = []
for data in x_train:
text = ' '.join(index_word[i] for i in data)
texts.append(text)
len(texts) # 25000
Tokenizer를 사용해 텍스트를 단어로 바꿈
from keras.preprocessing.text import Tokenizer
tok = Tokenizer()
tok.fit_on_texts(texts)
new_data = tok.texts_to_sequences(texts)
new_data[0][:10]
# 출력 결과
[28, 11, 19, 13, 41, 526, 968, 1618, 1381, 63]
# 모든 데이터 문장을 토큰화하고 위의 문장을 그 토큰으로 바꾼뒤 10개만 출력
import wget
import os
import zipfile
wget.download("http://mng.bz/0tIo")
local_zip = '0tIo'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall()
zip_ref.close()
imdb_dir = "aclImdb"
train_dir = os.path.join(imdb_dir, 'train')
labels = []
texts = []
for label_type in ['neg', 'pos']:
dir_name = os.path.join(train_dir, label_type)
for fname in os.listdir(dir_name):
if fname[-4:] == '.txt':
f = open(os.path.join(dir_name, fname), encoding = 'utf-8')
texts.append(f.read())
f.close()
if label_type == 'neg':
labels.append(0)
else:
labels.append(1)
texts[0]
# 출력 결과"Story of a man who has unnatural feelings for a pig. Starts out with a opening scene that is
a terrific example of absurd comedy. A formal orchestra audience is turned into an insane,
violent mob by the crazy chantings of it's singers. Unfortunately it stays absurd the WHOLE
time with no general narrative eventually making it just too off putting. Even those from the
era should be turned off. The cryptic dialogue would make Shakespeare seem easy to a third grader.
On a technical level it's better than you might think with some good cinematography by future
great Vilmos Zsigmond. Future stars Sally Kirkland and Frederic Forrest can be seen briefly."
labels[0] # 0(부정적인 리뷰)
from tensorflow.keras.preprocessing.text import Tokenizer
samples = ['The cat sat on the mat.',
'The dog ate my homeworks.']
tokenizer = Tokenizer(num_words = 1000)
tokenizer.fit_on_texts(samples)
sequences = tokenizer.texts_to_sequences(samples)
ohe_results = tokenizer.texts_to_matrix(samples, mode = 'binary')
word_index = tokenizer.word_index
print(len(word_index))
# 출력 결과9# 9개의 토큰을 가지고 있음
# 단어의 순서
sequences
# 출력 결과
[[1, 2, 3, 4, 1, 5], [1, 6, 7, 8, 9]]
# 원-핫 인코딩 결과print(ohe_results.shape)
print(ohe_results)
# 출력 결과
(2, 1000)
[[0.1.1. ... 0.0.0.]
[0.1.0. ... 0.0.0.]]
word_index
# 출력 결과
{'the': 1,
'cat': 2,
'sat': 3,
'on': 4,
'mat': 5,
'dog': 6,
'ate': 7,
'my': 8,
'homeworks': 9}
# 단어 인덱스에 따라 sequences의 값이 정해짐
- 토큰화 예제
OOV: Out Of Vocabulary
새로운 문장에서 기존에 토큰화한 문장에 존재하지 않으면 OOV로 대체됨
from tensorflow.keras.preprocessing.text import Tokenizer
samples = ["I'm the smartest student.",
"I'm the best student."]
tokenizer = Tokenizer(num_words = 10, oov_token = '<OOV>')
tokenizer.fit_on_texts(samples)
sequences = tokenizer.texts_to_sequences(samples)
binary_results = tokenizer.texts_to_matrix(samples, mode = 'binary')
print(tokenizer.word_index)
# 출력 결과# 현재 tokenizer에 대한 word_index
{'<OOV>': 1, "i'm": 2, 'the': 3, 'student': 4, 'smartest': 5, 'best': 6}
특정 단어를 나타내는 정수 인덱스를 밀집 벡터(dense vector)로 매핑하는 딕셔너리 레이어
입력: (samples, sqquence_length)
출력: (samples, sequences_length, dim)
from tensorflow.keras.layers import Embedding
embedding_layer = Embedding(1000, 64)
embedding_layer
# 출력 결과
<keras.layers.core.embedding.Embedding at 0x265f5b12fa0>
# embedding 객체가 출력됨
6. 예제: IMDB 데이터
인터넷 영화 데이터베이스(Internet Movie Database)
양극단의 리뷰 5만개로 이루어진 데이터셋
훈련 데이터: 25,000개
테스트 데이터: 25,000개
- modules import
from tensorflow.keras.datasets import imdb
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, Dense, Flatten
# sg인자에 0을 넘겨주면 CBOW, 1을 넘겨주면 Skip-gram# 최소 3번은 등장한 단어, 동시 처리의 수는 4개
model = Word2Vec(data, sg = 1, vector_size = 100, window = 3, min_count = 3, workers = 4)
- 모델 저장 및 로드
# 저장
model.save('word2vec.model')
# 로드
pretrained_model = Word2Vec.load('word2vec.model')