다중선형회귀

변수 Y를 X₁,....,Xp로 설명하는 다중선형회귀 모형

 

회귀계수의 추정

잔차

 

 

 

손실분량 

 

최소제곱법

data("stackloss")
m1 = lm(stack.loss ~ ., data = stackloss); m1

여기서 . 의 의미는 stack.loss를 제외한 모든 변수를 덧셈으로 연결한다는 뜻.

 

 

후버의 M-추정법

m2 = rlm(stack.loss ~ ., data = stackloss); m2

 

LMS

m3 = lqs(stack.loss ~ ., data = stackloss, method = "lms"); m3

 

LTS

m4 = lqs(stack.loss ~ ., data = stackloss, method = "lts"); m4

최소제곱 추정 방법 

  • 개체에서 발생하는 잔차에 제곱을 취하여 합을 구하는 방식 
  • 큰 절대값 잔차가 발생하지 않도록 회귀직선을 움직임. 
  • 한 개의 특이점이 회귀직선의 결정에 막중한 영향력을 가짐.

 

후버의 M-추정 

최소제곱 추정은 함수

으로 정의할 떄

를 최소화

그런데 이 추정치가 안정적이지 못한 이유는 함수가 z²에 비례하는 형태이기 때문 

 

따라서 다음의 변형을 고려한다.

|z| < c에서는 원래의 함수와 같지만 그 밖에서는 원래 함수보다 천천히 증가한다.

 

이를 반영한 후버의 M-추정량은 

로 얻어진다.

여기서 σ를 모르기 때문에 (다음 페이지의) MAD로 추정해 사용한다.

 

MAD (median of absolute deviations)

를 가정하고 σ에 대한 로버스트 추정량으로 IQR / 1.35 를 사용한다.

MAD는 또 다른 로버스트 추정량으로

라 정의한다.

 

 

목적함수  l   (z)  vs.   l (z)

ell.0 = function(z){z^2}
ell.1 = function(z){c = 1.345; ifelse(abs(z) < c, z^2, c*(2*abs(z) - c))}
z = seq(-6, 6, 0.1)
y.0 = ell.0(z)
y.1 = ell.1(z)
par(mfrow = c(1,2), pty = 's', mar = c(5, 3, 1, 3))
plot(y.0 ~ z, type = "l", lwd = 2, ylim = c(0, 30),
     ylab = expression(paste("\u2113")[0](z)))
plot(y.1 ~ z, type = "l", lwd = 2, ylim = c(0, 30),
     ylab = expression(paste("\u2113")[1](z)))
par(new = T)
plot(y.0 ~ z, type = "l", lwd = 2, lty = "dotted", ylim = c(0, 30), ylab = "")

 

코드해석: 

1. ell.0과 ell.1은 앞에서 봤던 l ₀, l ₁의 목적함수를 뜻한다. 

2. ell.1에서 ifelse는 첫 번째 조건을 만족하면 z² 을 하고 아니면 c * (2 * abs(z) - c)를 한다.

 

코드결과:

 

 

LMS/ LTS 추정 

> 자료점을

라 하고, 잔차를 

라 할 때, 최소제곱법은 

을 풀어 회귀직선을 얻는다.

 

 

LMS

> 반면에 LMS (Least Median of Squares) 회귀는 로버스트성의 관점에서 이 목적식을 

으로 개량한다.

 

> 최소제곱법은 Least Squares지만 Least Mean of Squares으로 간주 가능하다.

> LS는 선형대수적 풀이가 가능하지만 LMS는 몬테카를로 반복시행으로 해를 찾는다.

 

 

LTS

> LTS (Least Trimmed Squares; 최소절삭제곱) 회귀는

을 풀어서 회귀직선을 얻는다.

 

> q는 잔차제곱에 대한 순서통계량

에서의 순서

 

> default는 n의 50%정도에 해당하는 [n/2] + [(p+1)/2]

> n의 75% 정도에 맞추면 추정치의 정확도가 높아진다는 연구결과가 있다. 

 

비교1

library(MASS)
m0 = lm(y ~ x)  # 최소제곱추정 
m1 = rlm(y ~ x)  # 후버의 M-추정
m2 = lqs(y ~ x, method = "lms") # lms
m3 = lqs(y ~ x, method = "lts") # lts 
par(mfrow = c(1,1), mar = c(5, 3, 1, 3), pty = 's')
plot(y ~ x, ylim = c(-10, 10), cex = 2, pch = 19, col = 'darkgreen')
abline(m.truth$coefficients, lty = "dotted", lwd = 2)
abline(m0$coefficients, col = "darkcyan", lwd = 2)
abline(m1$coefficients, col = "darkblue", lwd = 2)
abline(m2$coefficients, col = "darkred", lwd = 2)
abline(m3$coefficients, col = "orange", lwd = 2)

여기서 보면 최소제곱추정 (lm)은 이상치에 민감해서 이상치쪽으로 방향이 따라간다는 걸 알 수 있다. 

lms, lts, 후버의 m-추정 모두 경향을 잘 따라가고 있다. 

 

다른 예를 통해서 조금 더 자세하게 살펴보자.

 

 

 

비교2 

1. X: 1,2,3,... , 10으로 고정

2. Y: Y = 2.5 + 0.5X + ε, ε ~ N(0,1)으로 생성 

3. 열번 째 자료점은 (100, -100)으로 수정 

  • x = 100은 '특이한' 설명변수 값
  • x = 100이 정상적인 값이라 했을 때도 y = -100은 특이값 ('회귀' 특이점)
set.seed(1234567)
x = seq(1:10)
y = 2.5 + 0.5*x + rnorm(10, 0, 1)
x[10] = 100
y[10] = -100

par(mar = C(5,3,1,3), pty = 's')
plot(y ~ x, ylim = c(-100, 10), cex = 1, pch = 19, col = 'darkgreen')
abline(m.truth$coefficients, lty = 'dotted', lwd = 2)

 

후버의 M-추정 vs. LMS

m1 = rlm(y ~ x)  # 후버의 M-추정
m2 = lqs(y ~ x, method = "lms") # lms
par(mar = c(5,3,1,3), pty = 's', mfrow = c(1,2))
plot(y ~ x, ylim = c(-100, 10), cex = 1, pch = 19, col = 'darkgreen')
abline(m.truth$coefficients, lty = 'dotted', lwd = 2)
abline(m1$coefficients, col = 'darkblue', lwd = 2)
abline(m2$coefficients, col = 'darkred', lwd = 2)

plot(y ~ x, ylim = c(-100, 10), cex = 1, pch = 19, col = 'darkgreen')
abline(m.truth$coefficients, lty = 'dotted', lwd = 2)
abline(m1$coefficients, col = 'darkblue', lwd = 5)
abline(m2$coefficients, col = 'darkred', lwd = 5)

LMS가 후버의 M-추정에 비해 더 경향을 잘 따라간다. 

 

 

LTS default vs. LTS quantile = 8

m2a = lqs(y ~ x, method = "lts")
m2b = lqs(y ~ x, method = "lts", quantile = 8)
par(mar = c(5,3,1,3), pty = 's')
plot(y ~ x, xlim = c(0, 10), ylim = c(0, 10), cex = 2, pch = 19, col = "darkgreen")
abline(m.truth$coefficients, lty = 'dotted', lwd = 2)
abline(m1$coefficients, col = 'darkcyan', lwd = 5)
abline(m2$coefficients, col = 'purple', lwd = 5)

누가 더 경향을 더 잘 따라간다고 할 수는 없다. 

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

EDA - 다중선형회귀  (2) 2024.05.22
EDA - 줄기와 잎 그림  (0) 2024.04.08
R프로그래밍 - simulation (2)  (1) 2023.12.05
R프로그래밍 - 중심극한정리 확인  (1) 2023.12.04
R프로그래밍 - simulation  (0) 2023.12.04
# 파일 불러오기 ====
Exam = read.table("/Users/user/OneDrive - 경북대학교/학과/2-1/탐색적자료분석 및 실험/실습파일/exam1.txt", head = T)
head(Exam$score)

# 줄기와 잎그림 확인 ====
stem(Exam$score)

# 줄기 수 줄이기와 늘이기 ====
# 이유는 여러가지 가능성을 열어두고 탐색하기 위함. 

## 줄기 수 줄이기 ====
stem(Exam$score, scale = 0.5)
# (0,1), (2,3).... 한 줄에 다 들어감.
# 이렇게하면 이전에 했던 줄기 그림이 쌍봉분포인데 비해 이것의 줄기 그림은 단봉분포의 형태를 취한다. 이것은 너무 단순하여 이 자료의 주요 특성을 잃은 것으로 볼 수도 있다. 즉 2개의 봉우리를 구분하지 못하고 1개만 본 것이다. 

## 줄기 수 늘이기 ====
stem(Exam$score, scale = 2)
# 원자료라면 하나였을 줄기가 각각이 줄기가 2개가 생김. 
# 일반적으로 줄기 수를 늘이면 늘일수록 많은 수의 봉우리를 보게 되고 반대로 줄기 수를 줄이면 줄일 수록 적은 수의 봉우리를 보게 된다. 

## hist ====
hist(Exam$score, nclass = 10, right = F)
# 대용량 크기 확인에 용이하다.

hist(Exam$score, nclass = 20, right = F)

 

 

줄기 그림과 히스토그램의 공통점과 차이점 

 

1. 공통점

 > 테두리가 동일: 각 구간의 관측빈도에 비례하는 길이의 막대 기둥을 가진다.

 

2. 차이점

 > 줄기 그림에서는 구간 내의 자료들이 숫자로 구별

   - 히스토그램에서는 보다 큰 정보의 손실이 발생함. 

 

 > 줄기 그림은 줄기의 크기를 줄이거나 늘이는데 작성된 줄기 그림 사용 가능 

   - 계획적인 시행착오를 수작으로 거듭할 필요가 있는 EDA에서는 효율성에서 차이가 있다.

 

 > 히스토그램은 임의로 구간의 폭을 지정할 수 있다. 

# 동전을 3번 던졌을 때 3번 연속 앞면이나 뒷면이 나오는 확률
n = 100000
count = 0

for(i in 1:n){
    u = runif(3, 0, 1)
    coin = as.numeric(u > 0.5)
    
    if(coin[1] == coin[2] & coin[2] == coin[3]){
        count = count + 1
    }
}

# 동전을 10번 던졌을 때 3번 연속 앞면이나 뒷면이 나오는 확률 
n = 10000
count = 0

for(i in 1:n){
    u = runif(10, 0, 1)
    coin = as.numeric(u > 0.5)
    
    for(j in 1:8){
        if(coin[j]==coin[j+1] & coin[j+1]==coin[j+2]){
            count = count + 1
            break
        }
    }
}
count/n


## 주사위 던지기 ====
### 주사위를 trial번 만큼 던져서 1/6에 근접하는지 확인 ====
trial = c(30, 50, 100, 500)

for (n in trial){
    u = runif(n, 0, 1)
    
    dot = numeric(n)
    case = numeric(n)
    
    for(i in 1:n){
        if(u[i] < 1/6){
            dot[i] = 1
        } else if(u[i] < 2/6){
            dot[i] = 2
        } else if(u[i] < 3/6){
            dot[i] = 3
        } else if(u[i] < 4/6){
            dot[i] = 4
        } else if(u[i] < 5/6){
            dot[i] = 5
        } else if(u[i] < 6/6){
            dot[i] = 6
        } 
    }
    
    ### 1 =====
    case = dot < 2 # 1인지 아닌지 구하는 것
    sum(case) # 1의 개수  = n*(1/6)
    sum(case)/n  # p = 1/6 = 0.167
    
    plot(table(dot), main = paste0("n = ",n),
         type = "h", col = "darkgreen", lwd = 5)
}


### 주사위 관련 나만의 코드 ====
### 반복문으로 만들수 있는걸 만들어봄. 
par(mfrow = c(2,2), mar = c(3, 5, 2, 2))
# mar 은 상하좌우의 마진(여백)을 나타낸 것임. 
trial = c(30, 50, 100, 500)

for(n in trial){
    u = runif(n, 0, 1)
    
    dot = numeric(n)
    case = numeric(n)
    final = matrix(NA, nr = 6, nc = 2)
    
    for(i in 1:n){
        if(u[i] < 1/6){
            dot[i] = 1
        } else if(u[i] < 2/6){
            dot[i] = 2
        } else if(u[i] < 3/6){
            dot[i] = 3
        } else if(u[i] < 4/6){
            dot[i] = 4
        } else if(u[i] < 5/6){
            dot[i] = 5
        } else if(u[i] < 6/6){
            dot[i] = 6
        }    
    }
    
    for(k in 1:length(unique(dot))){
        for(y in 1:length(dot)){
            if(dot[y] == k){
                case[k] = case[k] + 1 
            }   
        }
    }
    
    cat("시행횟수는", n, "\n")
    for(x in 1:length(unique(dot))){
        cat("주사위",x,
            "의 눈의 경우의 수는", case[x], 
            "확률은",case[x]/n,"\n")
    }
    
    plot(table(dot), main = paste0("n = ",n),
         type = "h", col = "darkgreen", lwd = 5)
}

## 자유투 =====

### 자유투를 던졌을 때 연속 2번이상 성공할 확률 ====
n = 1000
k = 0

for(i in 1:n){
    u = runif(5, 0, 1)
    shoot = as.numeric(u <= 0.2)
    

    if(sum(shoot) >= 2){
        k = k + 1
    }
}
k/n

x1 = choose(5,0)*(0.2)^0*(0.8)^5
x2 = choose(5,1)*(0.2)^1*(0.8)^5
1 - (x1 + x2)



### 2 ====
n = 1000
gathering = c(NA) ; gathering2 = numeric(n) 
# gathering2는 잘못된 방식으로 구하는 걸 보여주는 변수

for(i in 1:n){
    u = runif(100, 0, 1)
    shoot = as.numeric(u <= 0.2)
    
    for(j in 1:98){
        if(shoot[j]*shoot[j+1]*shoot[j+2] == 1){
            break
        }
    }
    
    # 잘못된 코드
    for(k in 1:98){
        if(shoot[k] == shoot[k+1] 
           & shoot[k+1] == shoot[k+2]){
            break
        }
    }
    gathering[i] = j+2
    gathering2[i] = k+2
}
mean(gathering)
mean(gathering2)

## 뷔퐁의 바늘실험 ====
needle_experiment = function(n, l, d){
    set.seed(100)
    k = 0
    
    for(i in 1:n){
        x = (d/2)*runif(1) 
        # d/2 
        # 바늘 가운데에서 가장 가까운 거리의 평행선
        # d/2 보다 클수는 없어서 
        # runif(1)
        theta = runif(1, 0, pi)
        
        if(x <= (l/2)*sin(theta)){
            k = k + 1
        }
    }
    prob = k/n
    pi.hat = 2*l/(prob*d)
    return(c(prob = prob, pi.hat = pi.hat))
}

needle_experiment(50000, 10, 20)


### 연습 ====

needle_experiment = function(n, l, d){
    k = 0
    set.seed(100)
    
    for(i in 1:n){
         x = (d/2)*runif(1)
         theta = runif(1, 0, pi)
         
         if(x <= (l/2)*sin(theta)){
             k = k + 1
         }
    }
    prob = k/n
    pi.hat = 2*l/(prob*d)
    return(c(prob = prob, pi.hat = pi.hat))
}

needle_experiment(50000, 15, 20)

 

 

중심극한정리를 사용한 정규분포

CLT_norm = function(x_bar_n, sample_m, mu, sig){
    xbar = as.numeric(x_bar_n)
    
    for(i in 1:x_bar_n){
        no = rnorm(sample_m, mu, sig)
        xbar[i] = mean(no)
    }
    
    result_mean = mean(xbar)
    result_var = var(xbar)
    ori_var= sig^2/sample_m
    return(c(result_mean = result_mean,
             result_var = result_var,
             ori_var = ori_var))
    print(h)
}


CLT_norm(10000, 100, 5, 2)

이항분포

n0 = 30; p = 0.1; mu = n0*p; var = n0*p*(1-p)

m = 1000 # 자료 set의 개수(xbar의 개수)
n = 100 # 난수 개수 (표본의 개수)

xbar = c()
for(i in 1:m){
    x = rbinom(n, n0, p) #이항분포에서 추출
    xbar[i] = mean(x)
}

xbar_mu = mean(xbar) ; mu
xbar_var = var(xbar) ; var/n

# histogram
hist(xbar, breaks = "fd", prob = T)

# theoretical curve ; N(mu, sqrt(var/n))
curve(dnorm(x, mu, sqrt(var/n)), add = T)

 

포아송분포

lamb = 5
var = lamb

m = 1000 # 자료 set의 개수 (xbar의 개수) 
n = 100 # 난수 개수 (표본개수)

xbar = c()
for(i in 1:m){
    x = rpois(n, lambda = lamb)
    xbar[i] = mean(x)
}
xbar_mu = mean(xbar) ; lamb
xbar_var = var(xbar) ; var/n

hist(xbar, breaks = "fd", prob = T)
curve(dnorm(x, lamb, sqrt(var/n)), add = T)

 

이항분포의 CLT를 n을 바꿔가며 확인

### n바꾸어서 CLT 확인 ====
p = 0.5 ; q = 1-p

par(mfrow = c(2,2))
for(n in c(10, 100, 1000, 10000)){
    
    p_hat = c()
    for(i in 1:1000){
        num = rbinom(n, 1, p)
        p_hat[i] = mean(num)
    } # for i
    
    CLT = (p_hat - p) / sqrt((p*q)/n)
    
    hist(CLT, probability = T,
         ylim = c(0, 0.5), xlim = c(-3, 3),
         main = paste0("n = ", n))
    
    curve(dnorm(x, 0, 1),
          xlim = c(-3, 3), ylim = c(0, 0.5),
          col = "tomato", lwd = 2,
          main = "X ~ N(0,1)", add = T)
} # for n

### 동전 던지기 ====
k = 0
n = 10000

for(i in 1:n){
    u = runif(3,0,1)
    coin = as.numeric(u > 0.5)
    
    if(coin[1] == coin[2] & coin[2] == coin[3]){
        k = k + 1
    }
}
k/n


### 동전 던지기 2 ====
x = 0
n = 10000

for(i in 1:n){
    u = runif(10, 0, 1)
    coin = as.numeric(u > 0.5)
    
    for(j in 1:(length(u)-2)){
        if(coin[j] == coin[j+1] & coin[j+1] == coin[j+2]){
            x = x + 1
            break # prevent double count
        }
    }
}
x/n

 

ascending_sorting = function(vec){
    sort.rank = matrix(NA, nr = length(vec), nc = 2)
    
    for(i in 1:length(vec)){
        val = vec[i]
        rank = 1
        for(j in 1:length(vec)){
            if(val > vec[j]){
                rank = rank + 1
            } else {
                rank = rank
            }
        }
        sort.rank[i,] = c(val,rank)
    }
    sort.i = c()
    
    for(k in 1:length(vec)){
        sort.i = c(sort.i, sort.rank[sort.rank[, 2] == k, 1])
    }
    return(sort.i)
}

set.seed(100)
vec = runif(3, 0, 30)
ascending_sorting(vec)

 

코드를 이해하는 흐름

> 오름차순 정렬을 위한 함수를 설정한다.

> 그러기 위해서는 매개변수가 필요하다.

> 그 매개변수는 vector의 형태로 와야한다. 

> 오름차순을 단순히 최댓값과 최솟값을 비교하는 것처럼 하기에는 무리가 있다. 따라서 우리는 matrix를 하나 설정해서 각 값에 대하여 ranking을 매길 것이다.

> ranking을 매기기 위해서는 반복문을 2번 사용해야한다.

 >> 즉, 하나의 값에 대하여 vector 안에 존재하는 모든 값들과 비교를 하는 방식으로 말이다.

> 그러고 난 다음에는 NA값으로 지정한 matrix에 값을 넣는다.

> 넣고 난 후의 matrix의 값들에 대해서 오름차순을 지정하기 위해서는 

 >> sort.i = c(sort.i, sort.rank[sort.rank[, 2] == k, 1]) 이런 식으로 코드를 짜야한다.

 >> 그 이유는 sort.rank[sort.rank[,2] == k, 1] 가 값이 여러개이기 때문에 그 값에 대해서 sort.i를 넣는 것이다.

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)))
}

 

반복문

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

 

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

 

 

 

+ Recent posts