지금은마라톤중

멋사 AI스쿨 TIL - (6) 본문

멋쟁이사자처럼/Python

멋사 AI스쿨 TIL - (6)

달리는중 2023. 1. 5. 16:48

2023.01.05


7. class

- 변수, 함수를 묶어서 코드를 작성하는 방법

- 객체지향 구현하는 문법

- 객체지향 : 실제세계를 모델링하여 프로그램을 개발하는 개발 방법론 : 협업을 용이하게 하기 위한

- 함수 사용법 : 함수선언(코드작성) > 함수호출(코드실행)

- 클래스 사용법

- 클래스 선언(코드작성) > 객체생성(메모리사용) > 메서드실행(코드실행)

                    - 클래스 선언(설계도작성) > 객체생성(제품생산) > 메서드실행(기능사용)

-식별자 컨벤션

                    - 변수, 함수 : snake_case

                    -  클래스 : PascalCase, UpperCamelCase

- class, self, 사용자 정의 데이터 타입, special methods(__int__(), __add__()…)

- 상속, super, getter-setter, mangling, 메서드의 종류들(인스턴스, 클래스, 스태틱)

# 클래스선언 : 코드작성
# 계산기 설계 : Calculator : number1, number2, plus(), minus()
class Calculator:

    number1, number2 = 1, 2

    def plus(self):
        return self.number1 + self.number2
    
    def minus(self):
        return self.number1 - self.number2
        
# 객체생성 : 메모리사용
calc1 = Calculator()
calc2 = Calculator()

calc1.number1, calc1.number2 # 출력 : 1, 2

# 메서드 실행 : 코드실행
calc1.plus(), calc1.minus() # 출력 : (3, -1)

# 객체의 변수 수정 : 데이터 선택 = 수정할 데이터
calc1.number1, calc1.number2, calc2.number1, calc2.number2 # 출력 : (1, 2, 1, 2)

calc1.number1 = 20 #객체의 변수 수정
calc1.number1, calc1.number2, calc2.number1, calc2.number2 # 출력 : (20, 2, 1, 2)
# self : 객체자신
# Calculator.plus() : self.number1 + self.number2
# calc1.plus() : self == calc1
# self.number1 +  self.number2 > calc1.number1 + calc1.number2

 1) 스페셜 메서드

- 특별한 기능을 하는 메서드 : 앞뒤로 __ 붙임

- 생성자 메서드 : __int__()

- 객체를 생성할  실행되는 메서드

- 변수의 초기값을 실행할  주로 사용

- 불량 객체(메서드 사용 X) 만들어질 확률을 줄여줌

# 클래스생성 : 설계도작성
class Account:

    def __init__(self, balance= 2000):
        self.balance = balance

    def insert(self, amount):
        self.balance += amount
    
    def withdraw(self, amount):
        if self.balance >= amount:
            self.balance -= amount
        else:
            print(f'잔액이 {amount - self.balance}원 부족합니다.')

# 객체생성 : 메모리 사용
account = Account()

# 메서드 실행 : 코드실행 : 기능사용
account.insert(200)

account.balance     # 출력 : 2200

- 클래스는 사용자 정의 데이터 타입이다.

# account의 데이터 타입은 Account
# account 객체가 만들어진 클래스는 Account
# 데이터 타입 == 클래스 > 클래스는 데이터 타입이다.
# Account 클래스는 우리가 만듦 > 사용자 정의
# > 클래스는 사용자 정의 데이터 타입이다.
type(account) # 출력 : __main__.Account
# data의 데이터 타입은 list
# data 객체가 만들어진 클래스는 list
# list 클래스는 우리가 만들지 X
data = [1, 2, 3]
type(data) # list : 사용자 정의가 아닌 데이터 타입
# account의 메서드는 Account 클래스에서 정의
# data의 메서드는 list 클래스에서 정의
[var for var in dir(account) if var[0] != '_']
# 출력 : ['balance', 'insert', 'withdraw']

# account.insert(), data.sort(), data.append()
# 데이터 타입의의 메서드를 암기할 필요 X
print([var for var in dir(data) if var[0] != '_'])
# 출력 : ['append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
# 객체의 데이터 타입에 따라서 사용할수 있는 변수, 메서드가 다르다.
# 숫자열과 튜퓰을 예시로 봤을 때 변수와 메서드가 다른 것을 확인 할 수 있다. 
data1, data2 = 234, (1, 2, 3)
print(type(data1), type(data2))
print([var for var in dir(data1) if var[0] != '_'])
print([var for var in dir(data2) if var[0] != '_'])
# 출력 : <class 'int'> <class 'tuple'>
#       ['as_integer_ratio', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
#       ['count', 'index']

 

 

- 파이썬으로 만든 데이터 타입은 첫글자가 대문자이고, c언어로 만든 데이터 타입(ex. list, str)은 소문자로 표시된다.

- 추가적인 스페셜 메서드

- __add__() : + 연산자 정의

             - 리스트 :  +연산은 리스트를 붙여줌, numpy : +연산은 가은 인덱스끼리의 합을 보여줌.

- __str__() : print() 함수 실행 정의

# 기본 원리
# d1 + d2 : + 연산자 == d1.__add__() 실행
d1 + d2 == d1.__add__(d2)
d1, d2, d3, d4 = 1, 2, '3', '4'

# d1 + d2 : + 연산자 == d1.__add__() 실행
d1 + d2 == d1.__add__(d2)

# d1 + d2 : d1.__add__(d2) : d1.__add__() : int 클래스의 __add__() 메서드
# d3 + d4 : d3.__add__(d4) : d3.__add__() : str 클래스의 __add__() 메서드
# > 데이터 타입에 따라서 수행되는  __add__() 메서드가 다르다.
# 덧셈연산을 하지만 뺄셈연산이 수행되는 객체를 생성
class Number:

    def __init__(self, data):
        self.data = data
    
    def __add__(self, obj):
        return self.data - obj.data

    def __str__(self):
        return str(self.data)

    def __repr__(self):
        return str(self.data)

num1 = Number(10)
num2 = Number(3)
num1.data,  num2.data  # 출력 : (10 , 3)
num1 + num2 # 출력 : 7

 

 

2) 상속

- 다른 클래스의 변수(메서드)를 가져와서 사용하는 방법

- 특정 메서드와 제외하고 상속하는 것은 안됨.

- 중간에 상속받은 변수를 바꿀 수 있음.

# 상속

# iPhone1 : call
# iPhone2 : call, send_msg
# iPhone3 : call, send_msg, internet

class iPhone1:
    def call(self):
        print('calling!')

class iPhone2(iPhone1):
    def send_msg(self):
        print('send_msg!')

class iPhone3(iPhone2):
    def internet(self):
        print('internet!')

iphone1 = iPhone1()
iphone2 = iPhone2()
iphone3 = iPhone3()

def show_vars(obj) :
    return [var for var in dir(obj) if var[0] != '_']

show_vars(iphone1), show_vars(iphone2), show_vars(iphone3)
# 출력 : (['call'], ['call', 'send_msg'], ['call', 'internet', 'send_msg'])

- 다중 상속

# 다중 상속은 python에서만
# 상속 순서 : Human > Korean > Jin
class Jin(Korean, Human):
    def skill(self):
        print('coding')

class Anchel(Indian, Human):
    def skill(self):
        print('speak english!')

jin = Jin()
show_vars(jin) # 출력 : ['eat', 'skill', 'walk']

anchel = Anchel()
jin.eat() # 출력 : eat kimchi!
anchel.eat() # 출력 : eat curry!

 

3) 데코레이터 : decoreator

-함수에서 중복되는 코드를 빼서 데코레이터 함수를 만들어 코드를 작성하는 방법

- 원래 있던 함수에 새로운 기능을 추가한 함수로 변경할 때 주로 사용

- 파이썬에만 있는 문법이다.

# code1, code3이 중복인 상태
def func1():
    print('code1')
    print('code2')
    print('code3')

def func2():
    print('code1')
    print('code4')
    print('code3')

def deco(func):
    def wrapper(*args, **kwargs):
        print('code1')
        func()
        print('code3')
    return wrapper

# deco 함수의 파라미터 func에 func1이 들어감
# func1 함수는 deco 함수의 return 함수인 wrapper 함수로 변경
@deco
def func1():
    print('code2')

@deco
def func2():
    print('code4')

func1()
func2()

# 출력 :
# code1
# code2
# code3
# code1
# code4
# code3
# timer 데코레이터 함수 생성
import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time() # 현재시간 저장
        result = func(*args, **kwargs)
        end = time.time() # 현재시간 저장
        print(f'running time : {end - start} sec')
        return result
    return wrapper

@timer
def plus(n1, n2) :
    return n1 + n2 

def minus(n1, n2) :
    return n1 - n2 

plus(3,2)
# 출력 : running time : 1.1920928955078125e-06 sec

 

# 패스워드를 맞춰야 함수의 실행이 가능하도록 하는 데코레이터 작성
def admin(func):
    def wrapper(*args, **kwargs):
        pw = input('insert password : ')
        if pw == 'python': # 패스워드 맞음
            result = func(*args, **kwargs)
        else: # 패스워드 맞지 않음
            result = 'wrong password!'
        return result
    return wrapper

def plus(n1, n2) :
    return n1 + n2 

@timer # deco 2개 사용 가능
@admin
def minus(n1, n2) :
    return n1 - n2 

minus(1,2) 
# 출력 : 
# insert password : python
# running time : 4.556134223937988 sec
# -1

 


상관계수

 

1) 분산 (variance)

 

- 어떤 확률 변수의 분산(variance) 은 그 확률변수가 기댓값(expected value) 으로부터 얼마나 떨어진 곳에 분포하는지를 가늠하는 숫자

- 편차제곱의 평균

- 1개의 이산정도를 나타낸다.

import numpy as np

data1 = [80, 85, 100, 90, 95]
data2 = [70, 80, 100, 95, 95]
data3 = [100, 90, 70, 90, 80]

def variance(data):
    var = 0
    x_ = sum(data) / len(data)

    for xi in data:
        var += (xi - x_) ** 2

    return var / len(data)

variance(data1), variance(data2), variance(data3) # 분산

# variance(data1) ** 0.5, variance(data2) ** 0.5, variance(data3) ** 0.5 # 표준편차

# np.var(data1), np.var(data2), np.var(data3)
# 출력 : (50.0, 126.0, 104.0)

 

2) 공분산 (covariance)

 

공분산 (Covariance, Cov)는 2개의 확률변수의 상관 정도를 나타내는 값

- x와 y의 단위의 크기에 영향을 받는다.

- 평균 편차곱

- 방향성은 보여줄수 있으나 강도를 나타내는데 한계가 있습니다.

  • 표본데이터의 크기에 따라서 값의 차이가 큰 단점이 있습니다.

(a) :  Cov(X, Y) > 0    X가 증가 할 때 Y도 증가한다.
(b) :  Cov(X, Y) < 0    X가 증가 할 때 Y는 감소한다.
(c) :  Cov(X, Y) = 0    공분산이 0이라면 두 변수간에는 아무런 선형관계가 없으며 두 변수는 서로 독립적인 관계에 있음을 알 수 있다.
                                     그러나 두 변수가 독립적이라면 공분산은 0이 되지만, 공분산이 0이라고 해서 항상 독립적이라고 할 수 없다.
def covariance(x, y):
    cov = 0
    x_ = sum(x) / len(x)
    y_ = sum(y) / len(y)
    for xi, yi in zip(x, y): # zip으로 같은 인덱스끼리 꺼내온다.
        cov += (xi - x_) * (yi - y_)
    return cov / (len(x) - 1) # - 1 : 자유도

covariance(data1, data2), covariance(data1, data3)
# 출력 : (93.75, -87.5)
# 공분산의 한계 : 방향성은 보여줄수 있으나, 강도는 보여줄수 없음
data4 = [data * 10 for data in data1]
data5 = [data * 10 for data in data3]
data1, data3, data4, data5

covariance(data1, data3), covariance(data4, data5)
# 출력 : (-87.5, -8750.0)

 

3) 상관계수(correlation coefficient)

 

 

    * 피어슨 상관계수, 스피어만 상관계수, 켄달 상관계수가 있다. 

- 공분산의 한계를 극복하기 위해서 만들어진다.

- -1 ~ 1까지의 수를 가지며 0과 가까울수록 상관도가 적음을 의미

- x의 분산과 y의 분산을 곱한 결과의 제곱근을 나눠주면 x나 y의 변화량이 클수록 0에 가까워진다.

# 상관계수 구하는 수식
def cc(x, y):
    cov = covariance(x, y)
    var = (variance(x) * variance(y)) ** 0.5
    return cov / var
    
data1, data2, data3, data4, data5 # data4, data5 = data1*10, data3*10

# 1과 가까울수로 강한 양의 상관관계
# -1과 가까울수록 강한 음의 상관관계
# 0과 가까울수록 관계없음
cc(data1, data2), cc(data1, data3), cc(data4, data5)
# 출력 : (0.944911182523068, -0.970725343394151, -0.970725343394151)

 

4) 결정계수

- 일반적으로 선형회귀분석에서 많이 사용하는 용어

- x로부터 y를 예측할수 있는 정도

- 상관계수의 제곱 (상관계수를 양수화)

- 수치가 클수록 회기분석을 통해 예측할수 있는 수치의 정도가 더 정확

 

- 단순 회귀분석(독립변수가 하나)인 경우 상관계수의 제곱 = 결정계수의 제곱

- R^2으로 표기, 범위 0 ~ 1

- x와 y의 상관관계 클수록 R^2이 1에 가까워짐.

 

 

 


Quiz

- 어제 못 푼 퀴즈 풀이

# Quiz. map 함수 직접 구현
names1 = ['kim python(23)', 'lee notebook(32)', 'kim macbook(47)']
names2 = ['kim py(33)', 'lee note(52)', 'kim book(87)']

def ages1(data):
    return data[:-3] + str(int(data[-3:-1]) // 10 * 10) + ')'

def ages2(*args):
    return [data[:-3] + str(int(data[-3:-1]) // 10 * 10) + ')' for data in args]



# 1번째
def map_func(func, *args):
    return [func(value) for value in args[0]]

map_func(ages1, names1) # 출력 : ['kim python(20)', 'lee notebook(30)', 'kim macbook(40)']

# 2번째
def map_func(func, *args):
    # print(args)
    result = []
    for data in zip(*args): # zip(names1, names2)
        # print(data)
        result.append([func(value)[0] for value in data])
    return result

print(map_func(ages2, names1, names2))

# 1,2번 합친 것
def map_func(func, *args):
    if len(args) <= 1:
        result = [func(value) for value in args[0]]
    else:
        result = []
        for data in zip(*args):        
            result.append([func(value)[0] for value in data])
    return result

- 오늘의 퀴즈

# 과제 : 미팅 수와 판매, 미팅 시간과 판매  상관관계 비교 
import pickle

with open('sales.pkl', 'rb') as file :
    data = pickle.load(file)

data.keys()   

count = data['meeting_count']
time = data['meeting_time']
sales = data['sales']

# 분산
var_count, var_time, var_sales = variance(count), variance(time), variance(sales)

# 공분산
covar1 , covar2 = covariance(count, sales), covariance(time, sales)

# 상관계수
cc(count, sales), cc(time, sales)

# 출력 : (0.782224424861606, 0.22829902637616525)
# 미팅수와 판매의 상관계수가 더 크므로 미팅 수가 판매에 더 영향이 있다고 판단.

 


오늘 추가공부는 수업내용과는 조금 달라서 따로 포스팅하겠다.

 

 

출처:

- https://supermemi.tistory.com/71.  

- https://supermemi.tistory.com/70.  

- https://destrudo.tistory.com/15

- https://m.blog.naver.com/istech7/50153288534

- http://www.seoulpaper.com/seoul/board.php?bo_table=b05_02&wr_id=14&me_code=5020.  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

'멋쟁이사자처럼 > Python' 카테고리의 다른 글

멋사 AI스쿨 WIL - (8)  (0) 2023.01.12
멋사 AI스쿨 TIL - (7)  (0) 2023.01.06
멋사 AI스쿨 TIL - (5)  (0) 2023.01.04
멋사 AI스쿨 TIL - (4)  (1) 2023.01.03
멋사 AI스쿨 TIL - (3)  (0) 2023.01.02
Comments