R에서 for문 안에 함수를 정의하면 생기는 문제
매우 쉬운 문제입니다. 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()
흑백으로 뜨는데 우리가 앞서 다루었던 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()