클래스 속성 사용하기

class Person:
    backpack = []

    def put_backpack(self, item):
        self.backpack.append(item)

james = Person()
james.put_backpack('노트북')

maria = Person()
maria.put_backpack('파이썬')

print(james.backpack) # james는 Person 클래스 이기에 출력가능
print(maria.backpack) # maria는 Person 클래스 이기에 출력가능

 

> Person 클래스에 바로 backpack 속성을 넣고 put_backpack 메서드를 만든다.

> 그리고 인스턴스 2개를 만들고 각각 put_backpack 메서드 사용 

> 클래스 속성은 클래스에 속해 있어서 모든 인스턴스에서 공유함. 

위의 코드를 출력하면 이렇게 나옴.

 

 

그런데 앞의 코드는 한 가지 아쉬운 점이 있다. 

put_backpack 메서드에서 클래스 속성 backpack에 접근할 때 self를 사용했는데

self는 현재 인스턴스를 뜻하므로 클래스 속성을 지칭하기에는 모호하다. 

따라서 클래스 속성에 접근할 때는 다음과 같이 클래스 이름으로 직접 접근하면 코드가 더 명확해진다. 

class Person:
    backpack = []

    def put_backpack(self, item):
        Person.backpack.append(item)

james = Person()
james.put_backpack('노트북')

maria = Person()
maria.put_backpack('파이썬')

print(james.backpack)
print(maria.backpack)

 

위와 같이 코드를 입력하니 클래스 Person에 속한 backpack 속성이라는 것을 바로 알 수 있다.

마찬가지로 클래스 바깥에서도 다음과 같이 클래스 이름으로 클래스 속성에 접근하면 된다.

print(Person.backpack)

 

파이썬에서는 속성, 메서드 이름을 찾을 때 인스턴스, 클래스 순으로 찾는다.

그래서 인스턴스 속성이 없으면 클래스 속성을 찾게 되므로 james.backpack, maria.backpack도 문제없이 동작한다.

겉보기에는 인스턴스 속성을 사용하는 것 같지만 실제로는 클래스 속성이라는 것이다. 

 

인스턴스와 클래스에서 __dict__ 속성을 출력해보면 현재 인스턴스와 클래스의 속성을 딕셔너리로 확인할 수 있다. 

 

 

 

 

여기서 중요한 것!

backpack을 그럼 여러 사람이 공유하지 않도록 하기 위해서는 어떻게 해야하나?

그냥 backpack을 인스턴스 속성으로 만들면 된다.

어떻게 만드냐 앞에 있는 Person 클래스 코드에 __init__를 추가하여 초기화가 되도록 만들어주면 된다.

class Person:                      # 클래스이름
    def __init__(self):            # constructor
        self.backpack = []
 
    def put_backpack(self, item):  # instance method
        self.backpack.append(item)

        
james = Person()                   # object instanciation
james.put_backpack('노트북')
 
maria = Person()                   # object instanciation
maria.put_backpack('파이썬')
 
print(james.backpack)              # 명확한 instance 변수 호출
print(maria.backpack)              # 명확한 instance 변수 호출

 

 

> 여기서 확인해보면 각각 넣은 물건만 출력된다는 것을 알 수 있다. 

> 즉, 인스턴스 속성은 인스턴스별로 독립되어 있으며 서로 영향을 주지 않는다.

 

 

정리

> 클래스 속성: 모든 인스턴스가 공유. 인스턴스 전체가 사용해야 하는 값을 저장할 때 사용

> 인스턴스 속성: 인스턴스 별로 독립되어 있음. 각 인스턴스가 값을 따로 저장해야할 때 사용

 

 

 

비공개 클래스 속성

> 클래스 속성을 만들 때 _속성과 같이 __(밑줄 2개)로 시작하면 비공개 속성이 된다.

> 클래스 안에서만 접근할 수 있고, 클래스 바깥에서는 접근할 수 없다.

class 클래스이름:
	__ 속성 = 값  # 비공개 클래스 속성

 

class Boxing:
    __item_limit = 10 # 비공개 클래스 속성

    def print_item_limit(self):
        print(Boxing.__item_limit)

peter = Boxing()
peter.print_item_limit()

print(Boxing.__item_limit) # 클래스 바깥에서는 접근할 수 없음.

 

클래스 바깥에서 print를 하려고 하니 에러가 뜬 것을 확인할 수 있다.

 

 

정적메서드 사용하기

> 인스턴스를 통하지 않고 클래스에 바로 호출 가능 

> 정적 메서드는 다음과 같이 메서드 위에 @staticmethod를 붙인다.

> 말 그대로 정적메서드이며 이때 정적메서드는 매개변수에 self를 지정하지 않는다.

class 클래스이름:
	@staticmethod
    def 메서드(매개변수1, 매개변수2):
    	코드

 

> @staticmethod처럼 앞에 @가 붙은 것을 데코레이터(장식자)라고 하며 메서드(함수)에 추가 기능을 구현할 때 사용

class Calculator:

    @staticmethod
    def add(x, y):
        print(x + y)

    @staticmethod
    def mul(x, y):
        print(x * y)

Calculator.add(10, 20)
Calculator.mul(10, 20)

 

> 정적 매서드는 self를 받지 않으므로 인스턴스 속성에는 접근할 수 없음.

> 그래서 정적 메서드는 인스턴스 속성, 인스턴스 메서드가 필요없을 때 사용함.

> 정적 메서는 메서드의 실행이 외부 상태에 영향을 끼치지 않는 순수 함수(pure function)를 만들 때 사용함.

> 순수 함수는 부수 효과(side effect)가 없고 입력값이 같으면 언제나 같은 출력값을 반환함.

> 즉, 정적 메서드는 인스턴스의 상태를 변화시키지 않는 메서드를 사용할 때 사용함. 

 

 

 

 

클래스메서드 사용하기

> 클래스 메서드는 다음과 같이 메서드 위에 @classmethod를 붙임.

> 이때 클래스 메서드는 첫 번째 매개변수에 cls를 지정해야 한다.

class 클래스이름:
	@classmethod
    def 메서드(cls, 매개변수1, 매개변수2):
    	코드

 

class Car:
    count = 0

    def __init__(self):
        Car.count += 1

    @classmethod
    def print_count(cls):
        print(f"{cls.count}대가 생성되었습니다.") # cls로 클래스 속성에 접근

x = Car()
y = Car()
z = Car()

Car.print_count()

 

> 먼저 인스턴스가 만들어질 때마다 숫자를 세야하기에 __init__메서드에서 클래스 속성 count에 1을 더해줌.

> @classmethod를 붙여서 클래스 메서드를 만든다.

> 클래스 메서드는 첫 번째 매개변수가 cls인데 여기에는 현재 클래스가 들어온다.

> 따라서 cls.count처럼 cls로 클래스 속성 count에 접근할 수 있다.  (정적 메서드와의 차이점)

> 클래스 메서드는 정적 메서드처럼 인스턴스 없이 호출할 수 있다는 점은 같다.

> 그러나 클래스 메서드는 메서드 안에서 클래스 속성, 클래스 메서드에 접근해야할 때 사용.

 

class Car:
    count = 0

    def __init__(self):
        Car.count += 1

    @classmethod
    def print_count(cls):
        print(f"{cls.count}대가 생성되었습니다.")

    @classmethod
    def create(cls):
        instance = cls()
        return instance

x = Car()
y = Car()
z = Car() # x, y, z 객체 생성으로 count 증가 (Car.count += 1)
w = x.create() # w 객체에서 classmethod 호출로 count 증가 (Car.count += 1)
o = Car.create() # Car클래스에서 직접 classmethod 호출로 count 증가 (Car.count += 1)

Car.print_count()

 

'프로그래밍 > Python' 카테고리의 다른 글

제너레이터(Generator)  (0) 2024.08.12
Python - Closure 함수  (0) 2023.12.15
Python - 인스턴스 변수 vs 정적변수  (0) 2023.11.25
Python - 클래스 생성자  (2) 2023.11.25
Python - 클래스  (1) 2023.11.25

인스턴스 변수

> 일반적으로 인스턴스 변수는 생성자 안에 정의를 함. 

 

> 예시

class Car:

    def __init__(self, brand, price):
        self.brand = brand
        self.price = price

    def get_brand(self):
        return self.brand

    def get_price(self):
        return self.price
new_car = Car("KIA", 50_000_000)
old_car = Car("BMW", 30_000_000)

print(f"My old car was {old_car.get_brand()} and the price was {old_car.get_price():,} won.")
print(f"My new car was {new_car.get_brand()} and the price was {new_car.get_price():,} won.")

 

 

> 인스턴스 변수는 인스턴스 생성 후에도 속성 추가 가능 (해당 인스턴스에만 생성)

 

color라는 속성이 하나 추가된 모습
color라는 속성이 있는 해당 인스턴스에만 생성되는 모습

 

 

 

 

 

정적 변수

> 클래스 내부에 공간이 할당되어 여러 인스턴스들이 하나의 자료를 공유 가능

> 정적 변수는 클래스에 정의

 >> 사용법: 클래스이름.변수 or 인스턴스이름.변수

 >> 클래스 속성은 여러 객체가 공유한다는 것을 주의 

 

> 동일한 변수일 경우 이름 찾는 순서: 인스턴스 변수 > 클래스 변수 

 >> 위와 같은 예시일 경우 인스턴스 변수 count는 설정이 없으므로 클래스 변수 count값 사용

'프로그래밍 > Python' 카테고리의 다른 글

Python - Closure 함수  (0) 2023.12.15
Python - 클래스 속성과 메서드 사용  (2) 2023.11.25
Python - 클래스 생성자  (2) 2023.11.25
Python - 클래스  (1) 2023.11.25
Python - 텍스트 파일 출력(쓰기)  (0) 2023.10.21

생성자

> 인스턴스를 생성하면 최초에 호출되는 메서드

> 생성과 초기화를 동시에 할 수 있는 함수 

파란색 부분이 생성자

 

 

기본생성자

> 매개변수 self만 있는 기본 생성자

 

매개변수가 있는 생성자

> 인스턴스 생성 시 초기값을 매개변수로 넘겨줌.

빨간 부분을 보면 __init의 매개변수는 세 개여야 하는데 실행하는 코드에서 2개만 썼다는 걸 알 수 있다.

OOP(Object-Oriented Programming - 실행 순서가 아닌 단위 객체를 중심으로 프로그램을 작성.)

- 객체: 실생활에서의 모든 자료 (물건)

- 모든 객체는 속성행동을 가진다.

 

> 객체 지향 프로그래밍은 이러한 객체 개념을 프로그램으로 표현함.

예) 속성 > 변수, 행동 > 함수로 표현

 

클래스

> 하나의 새로운 데이터 타입을 만드는 것 

> 클래스를 사용하는 목적이 변수와 함수를 묶어서 하나의 새로운 객체(타입)로 만드는 것

> 실제 세계에 존재하는 실체(instance)를 객체(object)라고 하고, 객체들의 공통점을 간추려서 개념적으로 나타낸 것 

> 어떤 클래스를 만들기 위해서는 그 객체가 갖는 성질(상태, 속성, 변수)과 그 객체가 하는 행동(메소드, 함수)을 정의해주면 된다고 이해하기

 

잉어빵, 황금 붕어빵과 같은 차별화된 붕어빵을 만들기 위해 틀을 잘 정의하는 것이지요. 그러나 아무리 틀을 예쁘고 정교하게 만들었다고 해서 붕어빵이 나오는 것은 아닙니다. 실제로 먹을 수 있는 붕어빵을 만들려면 붕어빵 틀에 반죽을 넣고 붕어빵을 구워야 합니다. 이처럼 붕어빵 틀에 반죽을 넣어서 만들어진 붕어빵이 인스턴스에 해당합니다.

 

클래스(class)와 인스턴스(instance)의 관계

> 학교와 모범생 관계라고 생각하면 됨.

> 학교는 커리큘럼을 가지고 있는데 아무리 좋은 커리큘럼을 가지고 있다고 해도 모범생이 무조건 나오는 것은 아니다. 모범생이 나올려면 공부도 열심히 시키고 질 높은 수업, 환경을 만들어줘야 한다. 이처럼 학교라는 어떠한 틀에서 좋은 수업 환경을 받은 모범생이 인스턴스에 해당함. 

 

예시

class Concept:
    def __init__ (self,parameter):
        self.parameter = parameter
        pass

    def method(self):
        return self. parameter
        
instance = Concept("argument")
instance.method()

 

 

 

> 코드 해석 

 >> Concept이라는 하나의 타입을 만듦.

 >> type(instance) 타입 확인 

 >> 타입이 객체임. 

 >> 이전에 썼던 리스트, 문자열과 같은 것들도 다 타입에 해당.

list, 문자열 모두 class였다는 걸 알 수 있다.

 

 >> __init__ : 이건 어떤 객체가 실행되면 무조건적으로 실행해주는 파이썬에서 특별하게 정의한 함수 메서드

 

b라는 변수를 Book() 타입이라고 할당하자마자 바로 __init__의 함수가 실행됨.

 

 

 

자동차 클래스 생성 

class Car:
    color = ""
    speed = 0

    def up_speed(self, value):
        self.speed += value

    def down_speed(self, value):
        self.speed -= value

 

> self는 클래스 자기 자신을 가리킴.

> 즉, 6,9행 self.speed는 인스턴스 변수, 3행의 speed는 클래스 변수

> 클래스 내 모든 method의 첫 번째 매개변수는 반드시 self 포함되어야함.

> 클래스에서 정의된 변수, 함수 사용 시 클래스.변수, 클래스.함수로 접근.

car = Car()
car.color = "Yellow"
car.up_speed(100)
car.down_speed(51)
print(car.color, car.speed)

 

 + 자신의 클래스 안에서 함수 호출: self.함수명() 

 

# class 

class 자동차:
	# 자동차의 속성(attribute)
    	자동차 색상
        자동차 속도
	# 자동차의 기능
    	속도 올리기()
        속도 내리기()
# 자동차(인스턴스)
자동차1 = 자동차()
자동차2 = 자동차()
자동차3 = 자동차()

 

> 각각의 인스턴스에는 별도의 공간(메모리)이 존재하며, 각각에 별도의 값 할당이 가능함. 

> 정리

class Car:
    color = ""
    speed = 0

    def up_speed(self, value):
        self.speed += value

    def down_speed(self, value):
        self.speed -= value

my_car = Car()
her_car = Car()
his_car = Car()

my_car.color = "Red" ; her_car.color = "Black" ; his_car.color = "Blue"
my_car.up_speed(100) ; her_car.up_speed(50) ; his_car.up_speed(80)
my_car.down_speed(10) ; her_car.down_speed(5) ; his_car.down_speed(20)

print(f"my_car is {my_car.color} and current speed is {my_car.speed}km/h")
print(f"my_car is {her_car.color} and current speed is {her_car.speed}km/h")
print(f"my_car is {his_car.color} and current speed is {his_car.speed}km/h")

생성된 객체는 각각의 속성을 유지하고 있음.

 

 

 

클래스 생성 단계 및 사용

 

1단계 클래스 정의

class 클래스_이름:
	// 멤버변수 선언
    // 메소드 선언
    
    
# 예시
class Car:
	def __init__ (self, c):
    	self.color = c
	
    def up_speed(self,value):
     ....

 

 

2단계 인스턴스 생성 

인스턴스 = 클래스_이름()

# 예시
my_car1 = Car("red")

 

3단계 변수 및 메소드 사용

인스턴스.멤버변수 = 값
인스턴스.메소드()

# 예시
my_car1.color = "yellow"
my_car1.up_speed(30)

 

 

 

 

 

 

 

동일한 이름의 클래스 변수가 존재할 경우 

 

1.

class Car:
    speed = 100
    
    def __init__(self, speed):
        print(f"{Car.speed = }")
        print(f"{self.speed = }")
        self.speed += speed
        
    def up(self, speed):
        self.speed += speed
        return self.speed
    
    def down(self, speed):
        self.speed -= speed
        return self.speed
    
car = Car(1)

print(f"{car.up(1) = }")
print(f"{car.down(1) = }")
print(f"{Car.speed = }")

 

 

VS

 

2.

class Car:
    speed = 100
    
    def __init__(self, speed):
        print(f"{speed = }")
        print(f"{Car.speed = }")
        print(f"{self.speed = }")
        self.speed = speed
        self.speed += speed
        
    def up(self, speed):
        self.speed += speed
        return self.speed
    
    def down(self, speed):
        self.speed -= speed
        return self.speed
    
car = Car(1)

print(f"{car.up(1) = }")
print(f"{car.down(1) = }")
print(f"{Car.speed = }")

 

 

> 이를 이해하기 위해서는 네임스페이스에 대한 이해가 필요하다. 

> 네임스페이스:  변수가 객체를 바인딩할 때 그 둘 사이의 관계를 저장하고 있는 공간 

 >> 바인딩: 자료형, 변수명, 변수값에 각각 int, num, 10 이라는 구체적인 값을 할당하는 각각의 과정

# 출처: 파이썬으로 배우는 알고리즘 트레이딩  

파이썬에서는 클래스가 정의되면 그림 6.11과 같이 하나의 독립적인 네임스페이스가 생성됩니다. 
그리고 클래스 내에 정의된 변수나 메서드는 해당 네임스페이스 안에 파이썬 딕셔너리 타입으로 저장됩니다.
Stock 클래스는 그림 6.11과 같이 Stock이라는 네임스페이스 안에 
'market':'kospi'라는 값을 가진 딕셔너리를 포함합니다.

![](https://wikidocs.net/images/page/1743/6.11.png)

**그림 6.11 파이썬 클래스 네임스페이스**

Stock 클래스의 네임스페이스를 파이썬 코드로 확인하려면 클래스의 `__dict__` 속성을 확인하면 됩니다.
딕셔너리 타입에 'market':'kospi'라는 키와 값 쌍이 존재하는 것을 확인할 수 있습니다.

```{.py}
Stock.__dict__
mappingproxy({
'market': 'kospi',
'__module__': '__main__', 
'__dict__': <attribute '__dict__' of 'Stock' objects>, 
'__doc__': None, 
'__weakref__': <attribute '__weakref__' of 'Stock' objects>})

 

> 클래스가 독립적인 네임스페이스를 가지고 클래스 내의 변수나 메서드를 네임스페이스에 저장하고 있으므로 다음과 같이 클래스 내의 변수에 접근이 가능한 것. 

 

 

> 정리

1번 코드는 speed라는 클래스 변수가 정의되고

반면에 인스턴스 변수 speed가 정의가 없다면 인스턴스 변수 sepeed는 클래스 변수 speed의 초기값을 공유

그런데 그 이후 클래스 변수 speed는 인스턴스 변수 speed가 변경되어도 클래스 변수의 값은 변경되지 않고

그냥 자기 갈 길 간다고 생각하면 된다. 

 

2번 코드는 1번 코드와 동일한 형식이지만 클래스 변수와 인스턴스 변수가 동일한 이름이라도 

별도로 코딩해줌으로써 헷갈리는 걸 방지했다고 볼 수 있다.

따라서 2번 코드로 코딩해주는 것이 더 정상적이다.  

Review - 반복문 복습 

n = 21
for(i in 1:100){
    cat("collatz : NOW =", n, "\n")
    if (n %% 2 == 0){
        n = n / 2 
    } else {
        n = n*3 + 1 
    }
    if(n == 1){
        cat("collatz : END =", n, "\n")
        break
    }
}

 

 

사용자 정의 함수 

function(<para1>, <para2>, ....){<expression>}

para1, 2 는 매개변수,

expression은 매개변수를 활용한 함수식 

 

 

 

예시1 

Ex0 = function(x) {7*x+5}
Ex0(3)

Ex1 = function(x){
    y = 7*x + 5 
    # 별도로 객체를 정의하여 값을 저장하면
    # 함수를 실행시키더라도 함수값을 출력해주지 않음. 
} 
Ex1(4) 
y 

# 함수 안에서 만들어진 변수는 함수가 종료되면 없어짐.

 

 

예시2 

Ex2 = function(x){
    x^2 + 3*x - 6
}
Ex2(10)

 

 

 

반환하고 싶을 때는 return(<object>)를 사용하여야 함. 

Ex1 = function(x){
    y = 7*x + 5
    return(y)
}

Ex1(4)

 

return을 쓰면 함수를 호출했을 때

함수 내에서 저장한 변수를 return(y)로 반환해줄 수 있음.  

 

return 예시 1 

Ex3 = function(x){
    a = x^2 + 3*x - 6
    b = 2*x^2 - exp(2)
    return(a+b)
}
Ex3(10)

 

return 예시 2 

Ex4 = function(x){
    return(x[2] + x[3])
}
Ex4(c(1:5))

 

매개변수는 단순한 숫자 뿐만 아니라 벡터도 들어갈 수 있음. 

 

 

 

다수의 매개변수와 기본값을 설정한 함수 

Ex5 = function(threshold = 0, vec){
    return(sum(vec > threshold))
}
Ex5(3, -3:10)
Ex5(vec = -3:10)

 

Ex5(3, -3:10) 코드는 순서대로 매개변수의 속성에 맞게 넣었기 때문에 오류가 없이 출력이 된다. 

그러나 Ex5(vec = -3:10) 은 현재 threshold의 값을 따로 설정해주지 않았기 때문에 매개변수의 순서에 맞게 넣는게 아니다.

따라서 -3:10이 어떤 매개변수에 해당하는지 적어줘야한다. 

 

 

다수의 매개변수, 기본값 예시 

Ex6 = function(n, mu, sig, value = 0){
    set.seed(100)
    tmp = rnorm(n, mu, sig)
    
    if(min(tmp) > value){
        result = max(tmp) - min(tmp)
    } else {
        result = value - min(tmp)
    }
    
    return(result)
}
Ex6(4, 6, 3)
Ex6(4, 6, 3, 6)

 

 

 

연습하기 

 

최솟값 찾기

# Find minimum by function ---- 
my.min = function(x){
    mini = x[1]
    for (i in 1:length(x)){
        if (mini > x[i]){
            mini = x[i] 
        } else {
            mini = mini
        }
    }
    return(mini)
}

set.seed(100)
x = runif(100, 0, 30)
my.min(x)

 

코드 설명 

1. 첫 번째 값을 초기값으로 지정

2. 다음 값과 비교 후 더 작으면 그대로 유지

3. 만약 다음 값이 더 작을 경우 그 값으로 대체

4. 반복문을 이용하여 가장 작은 값 찾기 

 

unif >>> 균등분포

 

 

팩토리얼 

# Find Factorial 
my.fac = function(n) {
    if (n == 0) {
        n = 1
    } else{
        n = n * my.fac(n - 1)
    }
    return(n)
}

my.fac(8) == factorial(8)

 

사용자 정의 함수는 함수 안에서 사용자 정의 함수를  사용할 수 있다. 

ex) 

ft1 = function(x){n = n*ft1(n-1)} 

파이썬의 재귀함수를 생각하면 쉽게 이해할 수 있다. 

 

 

연습문제 

 

Q1 > f(x,y) = x^2 + y^2 

Q2 > x값이 주어졌을 때 x값이 양수이면 x를 출력하고 양수가 아니면 x의 절댓값을 출력하는 함수 

Q3 > n값이 주어졌을 때 N(5,2)에서 n개의 값을 뽑은 벡터의 최솟값과 최댓값의 합을 산출하는 함수 

 

# practice subject ----
# 1 ----
Q1 = function(x, y){
    return(x^2 + y^2)
}

# 2 ----
Q2 = function(x){
    if(x > 0){
        print(x)
    } else {
        print(abs(x))
    }
}

# 3 ----
Q3 = function(n){
    return(max(rnorm(n, 5, 2)) + min(rnorm(n, 5, 2)))
}

 

출처 : 데이콘 

train.csv : 모델을 학습하기 위해 사용하는 데이터

test.csv : 모델을 통해 정답을 예측하기 위해 사용하는 데이터

sample_submission.csv : 예측한 정답 값을 기록하여 제출하기 위한 샘플 정답 파일 

 

 

순서 (출처: 데이콘, 영화 관객 수 예측 프로젝트)

1. 데이터 불러오기

2. 데이터 확인

3. 데이터 이해

4. 결측치 이해

5. 결측치 처리 

6. 모델 구조의 이해 

7. 모델링 

 

 

 

반복문

- 문장을 반복 실행하는 경우에 사용 

 

FOR문

# for 문 (for loop/statement) 형식
for (<var> in <interval>) { <repeated_work> }

# 설정한 변수 <var>가 지정된 구간 <interval>에서 변하면서 
# 문장 <repeated_work>을 반복실행

 

 

# 반복문; for loop ----
for (i in 1:3) {
    print(i)
}

for (i in c("a", "b", "c")){
    print(i)
}

for(i in 5:3){
    print(i)
}

# 반복문 : 1~1000합 구하기 ----
sss = 0 
for(i in 1:100){
    sss = sss + i
}


## exercise ----
x = 3
for(i in 1:5){
    x = x*2
}

sss = 0
for(i in 100:200){
    sss = sss + i
}

kk = 1
for(i in 1:10){
    kk = kk*i
}
kk == factorial(10)

# 반복문: 정규분포 ----
vec = rnorm(100,7,3)

sum1 = 0 
for(i in 1:length(vec)){
    sum1 = sum1 + vec[i]
}
m = sum1/length(vec)


## exercise ----
vec2 = rnorm(100, 5, 2)

sum2 = 0
for(i in 1:length(vec2)){
    sum2 = sum2 + vec2[i]
}
m2 = sum2/length(vec2)

sum3 = 0
for(i in 1:length(vec2)){
    sum3 = sum3 + vec2[i]^2                    
}
var1 = (sum3 - length(vec2)*m2^2)/(length(vec2)-1)
var1

 

R에서의 반복문은 파이썬에서의 반복문과 조금 다를 뿐 원리는 비슷함. 

 

 

WHILE문

# while문(while loop/statement) 
while(<condition>) { <repeated_work> }

# 반복할 조건 <condition>의 참 거짓을 판별하여
# 참인 경우 문장 <repeated_work>을 반복 실행
# 주어진 조건을 만족하는 동안 무한 반복하기 때문에 예상과 달리 루프에 갇히게 되면 break해야함.
# 반복문: while문 ----
x = 3
while(x<1000){
    x = x*2
}
print(x)

# 결과가 다르다는 걸 느끼기 
# 1
i = 0 
sss = 0
while(i <= 100){
    i = i + 1
    sss = sss + i
}
sss  # 5151

# 2 
i = 0; sss = 0
while(i <= 99){
    i = i + 1
    sss = sss + i
}
sss # 5050

# 3
i = 0; sss = 0
while(i <= 100){
    sss = sss + i
    i = i + 1
}
sss  # 5050

# 100~200합 구하기
i = 100
sss = 0
while(i <= 200){
    sss = sss + i
    i = i + 1
}
sss


# 1부터 10까지의 곱과 factorial 비교
i = 1
sss = 1
while(i <= 10){
    sss = sss*i
    i = i + 1
}
sss == factorial(10)


# example
# 처음으로 합이 100을 넘기는 n값 찾기
n = 0 ; n.sum = 0
while(n.sum <= 100){
    n = n + 1
    n.sum = n.sum + n
}

## practice ----
n = 0
while(n.sum <= 100000){
    n = n + 1
    n.sum = n.sum + n
}

n = 0
n.fac = 1
while(n.fac <= 1000000){
    n = n + 1
    n.fac = n.fac * n
}

 

repeat문

# repeat문 
repeat{<repeated_work>}

# 작업 <repeated_work>을 무한 반복하다가 break 조건을 만족하면 stop
# 반복문: repeat ----
n = 0
sss = 0
repeat{
    n = n + 1
    sss = sss + n
    if (n >= 100) break
}

이산확률분포 

# 이산확률분포 - random number 활용
x = 0:n
y = dbinom(x, n, p)
plot(x,y,
     type = "h", xlim = c(0,n), lwd = 3, col = "tomato")

 

# 추출하는 난수의 개수 조정 
n = 25
p = 0.2
random.x10 = rbinom(10, n, p)

plot(table(random.x10), xlim = c(0,n),
     lwd = 3, col = "red")

mean(random.x10) ; var(random.x10)


random.x100 = rbinom(100, n, p)
plot(table(random.x100), xlim = c(0,n),
     lwd = 3, col = "red")
mean(random.x100) ; var(random.x100)

random.x1000 = rbinom(1000, n, p)
plot(table(random.x1000), xlim = c(0,n),
     lwd = 3, col = "red")
mean(random.x1000) ; var(random.x1000)

result = data.frame(n = c(10, 100, 1000),
                    mean = c(NA),
                    var = c(NA))

result[1,2:3] = c(mean(random.x10), var(random.x10))  
result[2,2:3] = c(mean(random.x100), var(random.x100))  
result[3,2:3] = c(mean(random.x1000), var(random.x1000))  

result

 

 

추출하는 개수가 높아질수록 이론적인 평균값에 가까워진다는 것을 확인할 수 있음.

 

 

 

연속확률분포

## 연속확률분포 ----
### 정규분포 ----
rnorm(10, mean = 0, sd = 1)
random.x = rnorm(100)
mean(random.x) ; var(random.x)

# random number로 hist/curve 그리기 
?hist
hist(random.x, probability = T, main = "Normal(0,1)")

 

# random number로 hist/curve 그리기 
hist(random.x, probability = T, main = "Normal(0,1)")
# probability = T에 대한 의미 ----
# probability = T >> 상대도수
# probability = F >> 빈도수

curve(dnorm(x), add = T, col ="tomato", lwd = 3)

 

 

t-분포

### t-분포 ----
set.seed(123)

random.x = rt(100, 2.5)
hist(random.x, probability = T, main = "t-dist")

result = data.frame(
    n = c(30, 50, 100, 2000),
    mean = c(NA),
    variance = c(NA)
)

x30 = rt(result[1,1], 2.5)
x50 = rt(result[2,1], 2.5)
x100 = rt(result[3,1], 2.5)
x2000 = rt(result[4,1], 2.5)

result

set.seed(123)

result[1,2:3] = c(mean(x30), var(x30))
result[2,2:3] = c(mean(x50), var(x50))
result[3,2:3] = c(mean(x100), var(x100))
result[4,2:3] = c(mean(x2000), var(x2000))

result = rbind(c(NA, 0, 2.5/(2.5-2)), result)

result

 

 

 

R에서 제공하는 분포 관련 함수

density function of dist.

- d### (x,  ...<parameters>...)

 

distribution function of dist. 

- p###(q, ...<parameters>...)   # = P(X <= q)

- q###(p, ...<parameters>...)   # p = P(X <= x) >>> {P(X <= x)}^(-1)

 

 

 

이산확률분포 

 

이항분포

## 이항분포 - pmf 활용 ----
n = 15
p = 0.2
x = 0:10

y1 = dbinom(x, n, p) ; y1
plot(x, y1, type = "h", lwd = 3, col = "blue4")

## 이항분포 - cdf 활용 ----
y2 = pbinom(x, n, p) ; y2
plot(x, y2, type = "h", lwd = 3, col = "tomato")
plot(x, y2, type = "s", lwd = 3, col = "tomato")

## 이항분포 - check qbinom value ----
x; y2
qbinom(y2[2], n, p) == x[2]

 

 

포아송분포

## 포아송 분포 - pmf 활용 ----
lam = 2.5
x = 0:10
y1 = dpois(x, lam)

plot(x, y1, type = "h", lwd = 3, col = "blue4")


## 포아송 분포 - cdf 활용 ----
y2 = ppois(x, lam)
plot(x, y2, type = "h", lwd = 3, col = "tomato")
plot(x, y2, type = "s", lwd = 3, col = "tomato")

## 포아송 분포 - 값 찾기 ----
qpois(0.3456, lam)

 

 

 

연속확률분포

 

정규분포

## 정규분포 - pdf 활용 ----
mu = 0
sig = 1
x = seq(-5, 5, length = 20)

y2 = dnorm(x, mu, sig)
plot(x, y2, type = "h", lwd = 3, col = "blue4")

## 정규분포 - cdf 활용 ----
y3 = pnorm(x, mu, sig)
plot(x, y3, type = "s", lwd = 3, col = "tomato")

## 정규분포 - 값 찾기 ----
qnorm(y3, mu, sig) < qnorm(0.7, mu, sig)

 

 

t-분포

## t-분포 - pdf 활용 ----
df1 = 5
x = seq(-5, 5, length = 20)

y1 = dt(x, df1)
plot(x, y1, type = "h", lwd = 3, col = "blue4")

## t-분포 - cdf 활용 ----
y2 = pt(x, df1)
plot(x, y3, type = 's', lwd = 3, col = "tomato")

## t=분포 - 값 찾기 ----
qt(0.2, df1)

 

 

카이제곱분포

## 카이제곱분포 - pdf 활용 ----
df2 = 7
x = seq(0,30, length = 20)

y1 = dchisq(x, df2)
plot(x, y1, type = "h", lwd = 3, col = "blue4")

## 카이제곱분포 - cdf 활용 ----
y2 = pchisq(x, df2)
plot(x, y2, type = "s", lwd = 3, col = "tomato")


## 카이제곱분포 - 값 찾기 ----
qchisq(0.65, df1) + qchisq(0.65, df2)

이산확률분포

 

이산균등분포

> n개의 불연속적인 값을 가지는 확률변수 X가 아래와 같은 pmf를 가질 때 이산균등분포를 따른다고 하고, 

> X~U(a,b) 혹은 X~unif(a,b)로 표기함.

 

p(x) = 1/n , x = a, a+1, .... ,b 

## 이산균등분포 (Discrete uniform distribution) ----
n = 10
p = 1/n
x = 1:n
p.x = rep(p, n)
plot(x, p.x, xlim = c(1,n), ylim = c(0,1))

 

 

 

베르누이 시행

> 결과가 오직 두 가지 결과만을 가지고 성공할 확률이 일정한 실험

 

이항분포 

> 이항실험에 대해서 n번 시행 중 꼭 x번의 성공할 확률

> 베르누이 시행을 n회 시행했을 때 나오는 총 성공 횟수를 확률변수 X라고 하면, x는 이항분포를 따르며,

> X~B(n,p) 혹은 X~bin(n,p)로 표기함. 

## 이항분포 (Binomial distribution) ----
n = 10
p = 1/5
x = 1:n
p.x = choose(n,x)*p^x*(1-p)^(n-x)  # nCx
plot(x, p.x,
     xlim = c(1,n),
     ylim = c(0,1),
     main = "Binomial Dist.",
     col = "red")

 

 

포아송분포

> 일정한 구간에서 특정 사건이 일어나는 건수에 대한 분포 

> 조건

1. 주어진 구간에서 사건의 평균 발생횟수는 구간의 시작점과 관계가 없고 구간의 길이에만 영향을 받음.

2. 랜덤 발생: 한 순간에 2회 이상의 사건이 발생할 확률은 거의 0에 가까움.

3. 독립적으로 발생: 한 구간에서 사건의 횟수는 겹치지 않는 다른 구간에서 발생하는 사건의 횟수에 영향을 받지 않음. 

> 예) 일주일 동안(구간) 어느 고속도로에서 발생하는 교통사고 건수(특정 사건이 일어나는 건수) 

 

## 포아송 분포 (Poisson distribution) ----
n = 100
mu = 15
x = 0:n 
p.x = (exp(1)^(-mu)*mu^x)/factorial(x)
plot(x, p.x, xlim = c(1,n), ylim = c(0,1),
     main = "Poisson dist.", col = "blue",
     pch = 20)

 

기하분포

1.

> 특정 사건이 발생할 확률이 p로 일정할 때 해당 사건이 발생할 때까지 시행한 횟수를 확률변수 X라고 하자.

> 이때 x번째에 사건이 발생할 확률은 

> p(x) = (1-p)^(x-1) * p     x = 0, 1, .....

 

2. 

> 특정 사건이 발생할 확률이 p로 일정할 때 해당 사건이 발생할 때까지 실패한 횟수를 확률변수 X라고 하자.

> 이때 x번 실패 후 사건이 발생할 확률은 

> p(x) = (1-p)^x*p        x = 0, 1, .........

 

## 기하분포 (Geometric distribution)
n = 100
p = 1/3
x = 0:n
p.x = (1-p)^(x-1)*p
plot(x, p.x, xlim = c(0,n), ylim = c(0,1),
     main = "Geometric Dist.", col = "grey", pch = 20)

 

 

 

연속확률분포

 

연속균등분포 

> 구간 (a,b)에 있는 값을 가지는 확률변수 X가 아래와 같은 pdf(probability density function)를 가질 때 연속 균등 분포를 따른다고 하고, X~U(a,b) 혹은 X~unif(a,b)로 표기함.

p(x) = 1/(b-a) # x는 a,b 구간에 속해있다.

 

+ 연속형 분포의 그래프 그리기 

이산형과 달리 연속형은 'continuous'한 직선 혹은 곡선으로 표현 

 - 이산형 분포 그리기에서는 정의역 값을 vector로 묶어 지정하는 식으로 구현 가능

 - 이산형과 달리 연속형의 변수 값은 '구간' 형태

 

정의역 x의 구간과 x가 포함된 함수/표현식(expression)을 설정해주면 직/곡선을 그려주는 함수 활용

 - curve(expr, from = Null, to = Null, ...)

 -- expr에 x가 포함된 함수의 표현식을 설정 

 -- from,to에 각각 구간의 시작점과 끝점을 설정

 -- 기타 plot, hist에서 쓰는 옵션 지정 가능 

 

# X ~ U (0, 10)

n = 10
curve(1/n, from = 0, to = n, col = 2, lwd = 3)

 

그런데 이런 식으로 하면은 안됨. 위에서 curve의 expr에서 x가 포함된 함수의 표현식을 설정해서 나타내라고 했는데 그렇게 되지 않음. 이렇게 실행하면 다음과 같은 에러가 나옴.

 

 

따라서 이런 식으로 코드를 짜야함. 

curve(x/x/n, from = 0, to = n, col = 2, lwd = 3)

 

# X ~ U(2.3, 7.6)
n = 100
a = 2.3 
b = 7.6

curve(x/x/(b-a), a, b, col = 4, lwd = 3)

 

 

정규분포

> 대표적인 연속확률분포로 평균을 중심으로 좌우대칭이며 bell-shape을 가진 분포

## 정규분포 (normal distribution) ----
mu = 0 
var = 1^2

expr = (1/sqrt(2*pi*var))*exp(-(x-mu)^2/(2*var))
curve((1/sqrt(2*pi*var))*exp(-(x-mu)^2/(2*var)), -50, 50, col = 4, lwd = 3)

 

 

t - 분포 (Student's t - distribution)

> 평균 0 중심으로 좌우대칭인 bell-shape이며, 자유도 v에 의해 결정됨.

> 자유도가 커질수록 정규분포에 가까워지는 특징을 가짐. 

## t-분포 (Student's t - distribution) ----
nu = 3
curve((gamma((nu+1)/2))/sqrt(nu*pi)*gamma(nu/2)*(1+x^2/nu)^(-(nu+1)/2), -10, 10, col = 4, lwd = 3)

 

카이제곱분포 (Chi-square distribution)

> k개의 서로 독립인 (표준)정규확률변수를 제곱하여 합하여 얻은 변수의 분포

> 분포곡선은 수직축의 오른쪽에 위치하며, 모양은 자유도가 작은 경우에는 비대칭이고, 자유도가 증가함에 따라 대칭 모양에 가까워짐. 

## 카이제곱분포 (Chi-square distribution) ----
curve(1/(2^(nu/2)*gamma(nu/2))*x^((mu/2)-1)*exp(-(x/2)), 0, 10, col = 4, lwd = 3)

+ Recent posts