헷갈릴만한 개념

R에서 for문 안에 함수를 정의하면 생기는 문제

JSMATH 2024. 8. 1. 22:42

매우 쉬운 문제입니다. x의 범위를 [0,1]에서 점별수렴성을 본다면 n->inf일 때 0으로 수렴하겠죠.

하지만 괴랄한 수식의 수렴성을 판단 할 때도 있지 않을까해서 이 문제를 가지고 시각화 코드를 짜다가 발생한 문제입니다. 

func <- NULL
for(i in 0: 5){
  func <- c(func,function(x) x^(i+1))
}

위와 같이 코드를 짜게 된다면 다음과 같은 일이 발생합니다.

#func : list 
> func[[1]](3)
[1] 729
> func[[3]](3)
[1] 729
> 3^6
[1] 729

 

모두 x^6일 때 값으로 나타났습니다. 찾아보니까 클로저문제가 발생했다고 하는데요.

for문 내 함수정의를 하면 해당 함수가 반복문 변수를 직접 참조하는 방식이 문제입니다.

이에 대해서 간단히 설명하자면  x^i,x^i,x^i... 라는 함수들이 있을테고 for문이 끝나면 i=5가 되어버릴테니

모두 x^6으로만 나타난다는 것이죠. 함수에서는 i가 어떠한 값으로 지정이 안된다는 말입니다. 

그렇다면 이에 대해서 해결하려면 우리가 익숙한 방식대로 i에 특정값을 넣어주고 계속 쌓아가는 방식을 찾아야합니다.

func <- NULL
for(i in 0: 5){
  func <- c(func,local({
    val <- i
    function(x) x^(val+1)
  }))
}

local을 이용하여 로컬 안에 i를 새로운 변수로 지정하고 함수를 처리하면 

아래와 같이

1. i=0 , val <- 0 , x^0+1= x , func = c(x) 

2. i=1 , val <- 1 , x^1+1 =x^2 , func = c(x,x^2)

3. i=2 , val <- 2 , x^2+1 =x^3 , func = c(x,x^2,x^3)

마지막 결과는 func = c(x,x^2,x^3,..,x^6)

 

기존에 했던 방식은

1. i=i , x^i+1 =x^i+1 , func = c(x^i+1)

2. i=i , x^i+1 = x^i+1 , func = c(x^i+1,x^i+1)

3. i=i , x^i+1 = x^i+1 , func = c(x^i+1,x^i+1,x^i+1)

... 마지막 결과가 i=6이므로 func = c(x^6, x^6, x^6, x^6, x^6, x^6)

 

이제 이 함수들을 그려야하는데 ggplot으로 그린다면

x를 임의로 지정하고 함수값이 포함된 데이터 프레임이 있어야겠으며 각 함수가 6개를 나타내야하므로 한 컬럼은 함수이름을 적어두면 되겠습니다.

 

위에서 수렴성조사에 x의 범위를 [0,1]로 두고 6개를 함수를 만드는데 lapply를 이용합니다.

# x range
x <- seq(0, 1, length.out = 100)

# ggplot에 사용할 데이터프레임
df_list <- lapply(1:6, function(i) {
  data.frame(x = x, y = func[[i]](x), func = paste0("x^", i))
})

df <- do.call(rbind, df_list)

lapply는 리스트를 함수대로 처리하는데 1:6도 벡터이자 리스트도 가능하므로 데이터프레임을 만들어냅니다. 총 6개의 리스트가 나오겠습니다. 

do.call은 리스트에 대한 계산(rbind)을 한번에 시키는 방식입니다.

# ggplot으로 시각화
ggplot(df, aes(x = x, y = y, fill = func)) +
  geom_line() +
  labs(title = "Graph of x, x^2, x^3, ..., x^6",x = "x",y = "y") +
  theme_minimal()

fill=func으로 했을 때

흑백으로 뜨는데 우리가 앞서 다루었던 bar,histogram은 fill로 해도 컬러로 떴었습니다.

geom_line()은 여러 팩터를 컬러로 나타내고 싶으면 fill이 아닌 color를 사용해야합니다.

ggplot(df, aes(x = x, y = y, color = func)) +
  geom_line(stat = 'identity') +
  labs(title = "Graph of x, x^2, x^3, ..., x^6",x = "x",y = "y")+
  theme_minimal()

 

아래는 연습문제입니다.

func <- NULL
for(i in 0: 10){
  func <- c(func,local({
    val <- i
    function(x) ((x-val)*x^2)/val
  }))
}

x <- seq(0, 1, length.out = 100)


df_list <- lapply(1:11, function(i) {
  data.frame(x = x, y = func[[i]](x), func = paste0("x^", i))
})


df <- do.call(rbind, df_list)


library(ggplot2)
df %<>% as.data.frame()

ggplot(df, aes(x = x, y = y, color = func)) +
  geom_line(stat = 'identity') +
  labs(title = "Graph",x = "x",y = "y")+
  theme_minimal()