Machine Learning Example with Class

Page content

강의 홍보

I. 개요

  • 간단하게 클래스를 만들어보고 한다.
  • 지금까지 배운 내용을 바탕으로 Class를 활용한 머신러닝 예제를 작성한다.

II. Class와 Instance는 무엇인가?

  • 클래스는 결국 함수의 연장선이다.
  • 지금까지 함수가 얼마나 편한 것인지를 배웠다.
    • 그런데, 시스템이 복잡해지면 함수 하나로 충분하지 않음을 알게 된다.
  • 간단한 예시를 들어보자.
result = 0
def add(num):
  global result
  result += num
  return result

print(add(10))
print(add(20))
10
30

(1) 똑같은 기능을 가진 여러개의 함수

  • 그런데, 2대의 계산기가 필요한 상황이 되었다고 가정하자.
result1 = 0
result2 = 0

def add1(num):
  global result1
  result1 += num
  return result1

def add2(num):
  global result2
  result2 += num
  return result2

print(add1(10))
print(add1(20))
print(add2(10))
print(add2(10))
10
30
10
20
  • 똑같은 일을 하는데, 2개의 함수가 필요할까?
  • 이 때 필요한 개념이 Class라는 개념이다.

(2) 사람 클래스

  • 사람을 어떻게 정의할 수 있을까?
    • 기본적인 신상: 이름, 나이, 취미
    • 일상생활: 밥 먹기, 운동하기, 잠자기
  • 그런데, 현재 우리 클래스 안에 몇명의 사람이 있는가?
    • 이러한 신상을 파악하고, 일상생활을 파악하는 공통적인 설문지가 있으면 어떨까?
    • 설문지라는 이 일종의 클래스가 되는 것이다.
class Human:
  name = "Rain" # 필드
  age = 30 # 필드
  
  def exercise(self): # 메서드(Method), 객체가 할 수 있는 행동(=객체가 할 수 있는 함수)
    print("운동합시다")
  • 여기에서 self는 첫번째 매개변수를 의미하며, 자기 자신을 의미한다.

(3) 인스턴스

  • 인스턴스는 설문지를 받는 개개인의 사람을 떠올리자.
rain = Human()
print(rain.name)
print(rain.age)
rain.exercise()
Rain
30
운동합시다

III. How to define Class

  • 이제 지난 시간에 배운 함수의 정의들을 활용하여 Class를 만들어본다.

(1) 기본 함수 활용한 Class 예제

  • 기본 __init__ 메서드를 클래스안에 만든다.
  • 두명의 다른 사람을 만들어내자.
class Human:
  def __init__(self, name, age):
    self.name = name
    self.age = age

if __name__ == '__main__':
  evan     = Human("Evan", 9)
  minyoung = Human("SeoYoung", 8)
  print(evan.name)
  print(minyoung.name)
Evan
SeoYoung

(2) 인스턴스 메서드

  • 이번에는 그 사람의 특징을 만들어 낼 수 있는 인스턴스 메서드를 작성 해보자.
class Human:
  def __init__(self, name, age):
    self.name = name
    self.age = age
  
  def describe(self):
    return f"{self.name}의 나이는 {self.age}이다."

  def say(self, content):
    return f"{self.name}{content}에 대해 말하고 있다."

if __name__ == '__main__':
  evan     = Human("Evan", 9)
  print(evan.describe())
Evan의 나이는 9이다.

(3) 상속

  • 상속은 부모가 가진 재산을 자녀에게 물려줄 때는 쓰는 말
    • 여기에서 말하는 재산은 함수, 변수 등을 의미함.
  • Asian, European, African Class를 만들어본다.
    • 단, 이 때, skin color 함수를 부모인 Human 클래스에서 만든다.
class Human:
  def __init__(self, name, age):
    self.name = name
    self.age = age
  
  def describe(self):
    return f"{self.name}의 나이는 {self.age}이다."

  def say(self, content):
    return f"{self.name}{content}에 대해 말하고 있다."

  def skinColor(self, color):
    return f"{self.name}의 피부 색상은 {color}이다."

class Asian(Human):
  pass

class European(Human):
  pass

class African(Human):
  pass

if __name__ == '__main__':
  evan     = Asian("Jihoon", 9)
  rose     = European("Rose", 10)
  sam      = African("Sam", 11)

  print(evan.skinColor("Yellow"))
  print(rose.skinColor("white"))
  print(sam.skinColor("black"))
Jihoon의 피부 색상은 Yellow이다.
Rose의 피부 색상은 white이다.
Sam의 피부 색상은 black이다.

IV. 머신러닝 with Class

  • 본 장에서는 Class를 활용하는 머신러닝에 대해 배울 예정이다.
  • 이 때, 동일한 데이터를 사용하지만, Column명이 조금 상이한 경우 어떻게 대응하는지에 관해 작성한다.

(1) Colab + Drive 연동

  • 먼저 weather.csvweather2.csv 파일 데이터를 구글 드라이브에 올려 놓는다.
  • 그 후, 구글 드라이브와 구글 코랩을 연동한다.
# Mount Google Drive
from google.colab import drive # import drive from google colab

ROOT = "/content/drive"     # default location for the drive
print(ROOT)                 # print content of ROOT (Optional)
drive.mount(ROOT)           # we mount the google drive at /content/drive
/content/drive
Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).
  • 다음 데이터 파일이 있는 곳으로 경로를 이동한다.
# import join used to join ROOT path and MY_GOOGLE_DRIVE_PATH
from os.path import join  

# path to your project on Google Drive
MY_GOOGLE_DRIVE_PATH = 'My Drive/Colab Notebooks/your/folder'
PROJECT_PATH = join(ROOT, MY_GOOGLE_DRIVE_PATH)
%cd "{PROJECT_PATH}"
!ls
/content/drive/My Drive/Colab Notebooks/your/folder
weather2.csv  weather.csv

(2) 두개의 서로 다른 데이터 확인

  • 각각의 데이터의 컬럼명이 어떻게 다른지 확인해본다.
data = pd.read_csv("weather.csv")
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 96453 entries, 0 to 96452
Data columns (total 12 columns):
 #   Column                    Non-Null Count  Dtype  
---  ------                    --------------  -----  
 0   Formatted Date            96453 non-null  object 
 1   Summary                   96453 non-null  object 
 2   Precip Type               95936 non-null  object 
 3   Temperature (C)           96453 non-null  float64
 4   Apparent Temperature (C)  96453 non-null  float64
 5   Humidity                  96453 non-null  float64
 6   Wind Speed (km/h)         96453 non-null  float64
 7   Wind Bearing (degrees)    96453 non-null  float64
 8   Visibility (km)           96453 non-null  float64
 9   Loud Cover                96453 non-null  float64
 10  Pressure (millibars)      96453 non-null  float64
 11  Daily Summary             96453 non-null  object 
dtypes: float64(8), object(4)
memory usage: 8.8+ MB
data_columns = data.columns.tolist()
data_columns
['Formatted Date',
 'Summary',
 'Precip Type',
 'Temperature (C)',
 'Apparent Temperature (C)',
 'Humidity',
 'Wind Speed (km/h)',
 'Wind Bearing (degrees)',
 'Visibility (km)',
 'Loud Cover',
 'Pressure (millibars)',
 'Daily Summary']
data2 = pd.read_csv("weather2.csv")
data2.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10000 entries, 0 to 9999
Data columns (total 12 columns):
 #   Column                    Non-Null Count  Dtype  
---  ------                    --------------  -----  
 0   Formatted.Date            10000 non-null  object 
 1   Summary                   10000 non-null  object 
 2   Precip.Type               10000 non-null  object 
 3   Temperature..C.           10000 non-null  float64
 4   Apparent.Temperature..C.  10000 non-null  float64
 5   Humidity                  10000 non-null  float64
 6   Wind.Speed..km.h.         10000 non-null  float64
 7   Wind.Bearing..degrees.    10000 non-null  int64  
 8   Visibility..km.           10000 non-null  float64
 9   Loud.Cover                10000 non-null  int64  
 10  Pressure..millibars.      10000 non-null  float64
 11  Daily.Summary             10000 non-null  object 
dtypes: float64(6), int64(2), object(4)
memory usage: 937.6+ KB

(3) Class 작성

from sklearn.ensemble import RandomForestRegressor
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
import numpy as np
import pandas as pd


class Model:
    def __init__(self, datafile, model_type = None):
       self.datafile = datafile
       self.df = pd.read_csv(datafile)
       data_columns = ['Formatted Date', 'Summary', 'Precip Type', 
                       'Temperature (C)', 'Apparent Temperature (C)', 
                       'Humidity', 'Wind Speed (km/h)', 'Wind Bearing (degrees)',
                       'Visibility (km)', 'Loud Cover', 'Pressure (millibars)','Daily Summary']
       self.df.columns = data_columns

       if model_type == 'rf':
            self.user_defined_model = RandomForestRegressor() 
       else:
            self.user_defined_model = LinearRegression()
            
    def split(self, test_size):
        X = np.array(self.df[['Humidity', 'Pressure (millibars)']])
        y = np.array(self.df['Temperature (C)'])
        self.X_train, self.X_test, self.y_train, self.y_test = train_test_split(X, y, test_size = test_size, random_state = 42)
    
    def fit(self):
        self.model = self.user_defined_model.fit(self.X_train, self.y_train)
    
    def predict(self, input_value):
        if input_value == None:
            result = self.user_defined_model.predict(self.X_test)
        else: 
            result = self.user_defined_model.predict(np.array([input_value]))
        return result
  • 위 클래스는 4개의 함수로 구성되어 있다.
    • __init__: 데이터를 불러오고 간단한 Column명 처리를 진행했다.
    • split: 데이터 셋을 나누는 함수이다.
    • fit: 모형을 적합하는 함수이다.
    • predict: 예측 후 결과를 보여준다.

(4) 클래스 재사용성 확인

  • 이렇게 작성된 클래스를 a_modelb_model을 확인해서 클래스 내의 함수를 재 사용해본다.
if __name__ == '__main__':
    a_model = Model(datafile="weather.csv", model_type=None)
    a_model.split(0.2)
    a_model.fit()    
    print(a_model.predict([.9, 1000]))
    print("Accuracy: ", a_model.model.score(a_model.X_test, a_model.y_test))
[6.83625473]
Accuracy:  0.39578560465686424
if __name__ == '__main__':
    b_model = Model(datafile="weather2.csv", model_type=None)
    b_model.split(0.3)
    b_model.fit()
    print(b_model.predict([.9, 1000]))
    print("Accuracy: ", b_model.model.score(b_model.X_test, b_model.y_test))
[7.15581866]
Accuracy:  0.35698882811391797
  • 위와 같이 클래스를 활용한다면, 앞으로는 위 6줄만 추가하면, 추가적인 weather 데이터가 들어와도, 훨씬 간결하게 소스코드를 작성할 수 있다.

V. 추가 공부