본문 바로가기
통계학/BITAmin

12주차 : 2학기 기말고사, 복습과제로 오답정리

by zzyunzz 2021. 1. 12.

우엑 우우우엑 나는 과제 한 번도 안빠트렸는데 진짜 ㅠㅠ 결국 죄수의 딜레마 열등한 내쉬균형 달성

그래도 문제는 진짜 전범위 복습하기 좋게 구성한듯 

3등안에 들어서 치킨 깊티 ㄹㅇ 개꿀이당


Q1. 수 범위를 전달받아 소수(prime number)만 반환하는 함수 만들기

def prime_number(number):   # number를 입력 받아 소수인지 아닌지 구분하는 함수
     # number가 1이 아니면, (1은 소수가 아님)
    if number != 1:                 
        # 2, 3, 4, ..., (number - 1)까지의 인수에 대해서
        for f in range(2, number):  
            # number가 위의 인수 중의 하나로 나누어지면, (나머지가 0이면)
            if number % f == 0:     
                return False    # 소수가 아님
    else:                       # number가 1이라면, 
        return False            # 소수가 아님
    
    # number가 1이 아니면서, 2부터 (number - 1)까지의 수로 나눠지지 않으므로
    # 소수로 판별됨 (소수는 1과 자신만을 인수로 갖는 수)
    return True                 

def prime(init, term):
    
    integer_list = (x for x in range(init, term + 1))
    prime_numbers = []
    for num in integer_list:
        if prime_number(num):
            prime_numbers.append(num)
    print(prime_numbers)
  prime(10, 19)
  
  [11, 13, 17, 19]

Q2. 영화의 컨텐츠 등급을 예측하는 모델 구축하고, 성능 평가하기

topic : 데이터전처리(결측치 처리 / 표준화 / 데이터프레임 병합), 시각화, 분류 모델, 앙상블 모델, 교차 검증

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
data = pd.read_csv(r'C:\Users\zhiyu\OneDrive - 한양대학교\[2020-2] BITAmin\정규 세션\12주차 - 기말고사/movie.csv')
data.head()

아직 표를 예쁘게 넣는 방법을 모르겠다 😕 html 로 넣으니까 데이터프레임 개못생김

- 데이터 프레임 전처리 과정 : 결측치(Null or NaN)는 평균값, 최빈값, 삭제 등의 과정을 거쳐서 정제하였음

import numpy as np
### column 날리기
data.drop(['actor_2_name','actor_2_facebook_likes', 'actor_3_name', 'actor_3_facebook_likes' ,'movie_imdb_link', 'plot_keywords'], axis = 1, inplace = True)

### 결측치 확인 
print(data.isnull().sum())

### 확인 후 'color','gross'는 결측치 날리기
data.dropna(subset= ['color'], inplace= True)
data.dropna(subset= ['gross'], inplace= True)

### budget의 결측치는 평균값으로 대치 
data['budget'] = data['budget'].fillna(data['budget'].mean())
color                         19
director_name                102
num_critic_for_reviews        49
duration                      15
director_facebook_likes      102
actor_1_facebook_likes         7
gross                        862
genres                         0
actor_1_name                   7
movie_title                    0
num_voted_users                0
cast_total_facebook_likes      0
facenumber_in_poster          13
num_user_for_reviews          21
language                      12
country                        5
content_rating               300
budget                       484
title_year                   106
imdb_score                     0
aspect_ratio                 326
movie_facebook_likes           0
dtype: int64
### content_rating 열에 대한 결측치 처리
sns.countplot(x = 'content_rating', data = data) ### 최빈값은 R임을 확인

data['content_rating'] = data['content_rating'].fillna('R')


### 최종 확인
print(data.isnull().sum())
color                          0
director_name                  2
num_critic_for_reviews         3
duration                       2
director_facebook_likes        2
actor_1_facebook_likes         4
gross                          0
genres                         0
actor_1_name                   4
movie_title                    0
num_voted_users                0
cast_total_facebook_likes      0
facenumber_in_poster           6
num_user_for_reviews           1
language                       3
country                        0
content_rating                 0
budget                         0
title_year                     2
imdb_score                     0
aspect_ratio                 104
movie_facebook_likes           0
dtype: int64

=> 그럼에도 아직 결측치가 남아있는 모습 ... 그래서 밑에서 계속 결측치와의 싸움을 하게 됨

 

- 정수형 데이터를 구간을 나누고 카테고리형 데이터로 변환하는 작업 (np.histogram, pd.cut 활용)

import numpy as np

#구간 나눌 bin_dividers 정하기
data2[data2['aspect_ratio'].isnull()] #NaN값이 있다

plt.xticks(rotation = - 45)
sns.countplot(x = 'aspect_ratio', data = data2) #그래프 그려보면 하한(1.18) ~ 1.85,1.85~ 2.35, 2.35 ~ 상한(2.76) 

### 범주 나누기
bin_names= ['norrow','standard','wide']
bin_dividers = [1.18, 1.85, 2.35, 2.76] #countplot을 보고 임의로 정함

#print(bin_dividers)


###'aspect_ratio2' 열 만들기
data2['aspect_ratio2'] = pd.cut(x=data2['aspect_ratio'],
                            bins = bin_dividers,
                            labels=bin_names,
                            include_lowest=True)

features = pd.DataFrame(data2[['movie_title','director_name']])
#features


temp = pd.get_dummies(data2['aspect_ratio2'])
features = pd.concat([features, temp], axis = 1)
features

=> count, bin_dividers = np.histogram(~)의 과정으로 구간값을 뽑으려고 했는데 결측치가 있어서 안됐다.

똑같이 결측치 처리 과정을 거친 후에 돌리면 해결했을 문제이긴 한데,  의미없이 임의의 값 배정하는 것보단 그냥 countplot으로 구간값 내가 고르는게 낫겠다는 생각이 들어서 빈도그래프 보고 bin_dividers에 숫자는 임의로 정의함.

 

- 계속 전처리 중...

#code here..

director_mean_group = data2.groupby(['director_name']).mean()
df_g_by_name = director_mean_group[['gross','duration','budget','imdb_score']] 
															#감독별로 평균 구해진 데이터프레임

features = pd.merge(features, df_g_by_name, on='director_name', how='outer')
features.isnull().sum() #아직도 duration에 결측치가 있음.

features[features['duration'].isnull()] #2개의 결측치는 duration 평균값으로 채워줬음.
features['duration'] = features['duration'].fillna(features['duration'].mean())
features.rename(columns = {'gross': 'gross_mean', 'duration':'duration_mean',
					'budget':'budget_mean','imdb_score':'imdb_score_mean'}, inplace=True)
features.isnull().sum()

전처리가 거의 다 끝났다 !!! 이제는 모델 구축 뿐이다.

번외 )  상관계수 파악

correl = features.corr()
plt.figure(figsize=(8,7))
sns.heatmap(data = correl, annot=True, cmap='Reds')
plt.show()

- 전처리 방식에서 차이가 났기 때문인지 지문에서 제시된 히트맵과는 약간 다른 분포를 보였지만, 정답은 없으니.

- 데이터 표준화

temp = data2[['movie_title','content_rating']]

features = pd.merge(features, temp, on='movie_title', how='inner')
features

X = features[['norrow', 'standard', 'wide', 'duration_mean','gross_mean','budget_mean','imdb_score_mean']]
Y = features['content_rating']

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit_transform(X)

X.describe()

디자인시안_최종_진짜최종_진짜진짜마지막.jpg

- 데이터 학습 및 평가 (1) 개별 모델

import warnings
warnings.filterwarnings("ignore")

from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split

sv_clf = SVC()
dt_clf = DecisionTreeClassifier()
rt_clf = RandomForestClassifier()

X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size = 0.3, random_state = 10)

model_list = [rt_clf, sv_clf, dt_clf]

for model in model_list:
    model.fit(X_train, y_train)
    pred = model.predict(X_test)
    print("test set {} 분류기 정확도 : {:.4f}".format(model, accuracy_score(pred, y_test)))

첫 번째 : 개별적으로 모델 학습 후의 테스트셋으로 성능 평가한 결과

test set RandomForestClassifier() 분류기 정확도 : 0.5845
test set SVC() 분류기 정확도 : 0.5261
test set DecisionTreeClassifier() 분류기 정확도 : 0.5261

- 데이터 학습 및 평가 (2) 앙상블 모델 - VotingClassifier

from sklearn.ensemble import VotingClassifier

vo_clf = VotingClassifier(estimators=[('DT', dt_clf),('SVM', sv_clf),('RT', rt_clf)])

vo_clf.fit(X_train, y_train)
pred = vo_clf.predict(X_test)

print('Voting 분류기 정확도: {0:.4f}'.format(accuracy_score(y_test, pred)))
Voting 분류기 정확도: 0.5706

- 교차검증 with cross_val_score() API

from sklearn.model_selection import cross_val_score, StratifiedKFold

skf = StratifiedKFold(n_splits=5, shuffle=True, random_state = 777)

scores = cross_val_score(vo_clf, X, Y, scoring='accuracy', cv = skf)
print('교차 검증별 정확도 : ', np.round(scores, 4))
print('평균 검증 정확도 : ', np.round(np.mean(scores), 4))

출력 :

교차 검증별 정확도 :  [0.5431 0.5725 0.5686 0.566  0.5817]
평균 검증 정확도 :  0.5664

 

데이터 분석의 80%이상은 데이터 전처리가 차지한다던데, 역시 시험 치는 당시에도 복습과제로 못한 부분 마무리하던 상황까지도 데이터전처리에서 시간 다 썼다. 더 꼼꼼하게 공부하기 ! 모델은 사실 정해진 키워드대로, 공식대로 써버리면 그만이지만 전처리야 말로 내가 생각한대로 모델이 씹을 수 있도록 다져주는 작업이니 확인할 부분이 참 많다.

 

댓글