R 세션은 R을 시작하고 끝낼 때까지를 말한다. R 콘솔을 시작할 때도 세션에 적용될 디폴트 설정값들을 사용하게 되는데, 대표적인 경우가 options()와 그래픽 환경에 영향을 주는 par() 함수이다. 어떤 패키지를 로딩하는 것도 세션에 영향을 주는 주요 요인 중에 하나다.
현재 R 세션의 설정값들은 콘솔에서 options() 함수를 실행해보면 알 수 있다.
> options()
그래픽 환경에 대한 기본 설정은 다음과 같다.
> par()
패키지가 로딩된 상태들을 포함하여 세션 전반에 대한 정보는 sessionInfo() 함수로 알 수 있다.
> sessionInfo()
R version 3.6.0 (2019-04-26)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 18362)
Matrix products: default
locale:
[1] LC_COLLATE=Korean_Korea.949 LC_CTYPE=Korean_Korea.949
[3] LC_MONETARY=Korean_Korea.949 LC_NUMERIC=C
[5] LC_TIME=Korean_Korea.949
attached base packages:
[1] stats graphics grDevices utils datasets methods base
loaded via a namespace (and not attached):
[1] shiny_1.3.2 compiler_3.6.0 magrittr_1.5 R6_2.4.0
[5] promises_1.0.1 later_0.8.0 htmltools_0.3.6 Rcpp_1.0.1
[9] digest_0.6.19 xtable_1.8-4 httpuv_1.5.1 mime_0.6
어떤 R 패키지들은 이들 옵션 값을 바꾸어서 R이 실행되는 데 영향을 준다. 샤이니에도 여러가지 글로벌 옵션들이 정해져 있다. 이것은 다음과 같이 실행하면 알 수 있다. shiny - options 를 둘러싼 것은 백틱(`, 키보드 1앞에 있는 키) 임을 주의한다.
> ?`shiny-options`
starting httpd help server ... done
22-1. R 지식을 적극 활용하여 샤이니 앱 만들기
앞에서 설명한 내용들을 활용하여 샤이니 앱을 어떻게 작성해 나가는지 살펴보기로 하자. 다음 앱을 보자. 이 앱은 mtcars 데이터 셋에서 연비 mpg 와 무게 wt, 그리고 나머지 하나의 변수를 추가하여 그 관계들을 알아볼 수 있게 한 것이다.
> library(shiny)
> library(ggplot2)
Registered S3 methods overwritten by 'ggplot2':
method from
[.quosures rlang
c.quosures rlang
print.quosures rlang
> library(dplyr)
다음의 패키지를 부착합니다: ‘dplyr’
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
경고메시지(들):
패키지 ‘dplyr’는 R 버전 3.6.1에서 작성되었습니다
> df <-
+ mtcars%>%
+ select(wt,mpg,cyl,vs,am,gear,carb)%>%
+ mutate_at(3:7,as.factor)
> ui <- fluidPage(
+ selectInput("sel","그룹선택",choices = c("cyl","vs","am","gear","carb")),
+ plotOutput("carPlot"),
+ verbatimTextOutput("carAnova")
+ )
> server <- function(input,output){
+ df_sub<-reactive({
+ df[,c("wt","mpg",input$sel)]
+ })
+ output$carPlot <- renderPlot({
+ category <- input$sel
+ ggplot(df_sub(),aes(wt,mpg)) +
+ geom_point(aes_(color=as.name(category)),size=3) +
+ geom_smooth(method = "lm")
+ })
+ output$carAnova <- renderPrint({
+ formul <- as.formula(paste("mpg~wt","+",input$sel))
+ anova(lm(formul,data = df_sub()))
+ })
+ }
> shinyApp(ui,server)
코드를 잠깐 살펴보자. UI 함수와 서버 함수 밖에서 dyplr 패키지를 사용하고, mtcars 데이터셋의 일부를 취하여 변수 타입을 바꾼 다음, 이것을df 라는 데이터 프레임에 할당했다.
> df <-
+ mtcars%>%
+ select(wt,mpg,cyl,vs,am,gear,carb)%>%
+ mutate_at(3:7,as.factor)
UI 코드에서는 wt,mpg 이외의 레전드에서 사용할 변수를 선택하려고 selectInput() 이라는 입력 위젯 함수를 사용했다.
그리고 플롯과 텍스트 출력물이 있다. 서버 함수에서는 df를 읽어서 그 중 계산에 필요한 열들만 선별했다. 이 과정은 reactive() 안에서 이루어진다. 이것이 반응성 표현식 df_sub이다.
이 반응성 표현식을 기반으로 하여 ggplot2 패키지를 사용해서 플롯을 그리고 ANOVA 테이블을 만들었다. 이 과정에서 언더바가 있는 aes_() 함수를 사용했고, 문자열을 사용해 formula 객체를 만들기 위해서 as.formula() 함수를 사용했다.
22-2 스콥, 반응성 맥락과 비반응성 맥락
먼저 R의 스코핑 기능과 밀접하게 연관되어 있는 반응성 맥락과 비반응성 맥락을 알아보자. 앞의 앱에서 사용된 객체들을 스콥과 연결해보면 다음과 같다.
- 글로벌 환경 : 가장 밖에 있는 환경으로 , mtcars 라는 객체가 있고 이것을 약간 변형하여 사용자가 만든 df 라는 객체가 존재한다. 이런 객체는 그 안에 있는 함수 안에서 모두 접근이 가능하다.
- 샤이니 서버 함수에 의한 스콥 : 글로벌 환경에 존재하는 df라는 객체를 서브세팅해서 df_sub 라는 반응성 표현식을 만들었다. 서브세팅을 할 때 [ 를 사용한 점에 주의해야 하는데, 반응성 표현식의 값을 사용하여 서브세팅하기 때문에 그렇다.
샤이니에서는 R 함수와 관련된 스콥 이외에 고려해야 할 사항이 또 있다. 그것은 반응성(reactivity) 과 관련된 '반응성 맥락' 이라는 것이다. 반응성 맥락은 샤이니 서버 함수 안에서 reactive() 함수 또는 render*() 함수로 생성되는 또 하나의 특수한 스콥이다. UI 에서 selectInput() 입력 위젯에서 값을 선택하는 것은 이런 반응성 맥락으로 값을 입력하는 것이다. 이런 방법을 통해야만 반응성 맥락으로 값을 전달 할 수 있다.
입력 위젯에서 사용자가 입력한 값은 input$sel 이라는 객체로 서버 함수에서 사용되는데, 샤이니에서는 이것을 '반응성 값(reactive values)' 이라고 한다. reactive() 함수가 만드는 것은 '반응성 표현식(reactive expression)' 이라고 말한다. 그리고 render*() 함수는 반응성의 결과물을 내는 것을 '관찰자(observer)' 라고 한다. 각각에 대해서는 샤이니 반응성을 설명하는 부분에서 다시 정리할 것이다.
일반적인 R 함수의 스코핑 규칙과 같이 안에서는 밖에 접근할 수 있지만, 밖에서는 안에 있는 것을 그냥 접근 할 수 없다. 즉 반응성 맥락에 있는 객체를 반응성 맥락 밖에서 접근할 수 없다. 이것은 함수 안의 변수를 함수 밖에서 접근할 수 없는 것과 마찬가지다. 반면 반응성 맥락안에서는 반응성 밖의 객체를 사용할 수 있다. 함수 안에서는 함수 밖의 객체에 접근할 수 있는 것과 같다. 이 앱에서 df 라는 객체는 반응성 맥락 밖, 글로벌 환경에 존재하며 따라서 이것을 반응성 맥락에서 접근하여 사용하는 것은 아무 문제가 없다.
df_sub<-reactive({
df[,c("wt","mpg",input$sel)]
})
reactive()로 생성되는 것은 반응성 표현식으로, 이것은 장차 값으로 치환될 수 있는 것이지 아직 하나의 값을 가지고 있지 않다. 반응성 표현식의 값을 사용하고 싶을 때는 끝에 ()를 쓰면 된다. 함수를 호출한다고 생각하면 되는데, 표현식을 실행해서 값을 만든다고 생각하면 된다. 이 앱에서 보면 아래와 같이 renderPlot() 함수에서 df_sub()로 접근한 것을 확인 할 수 있다.
output$carPlot <- renderPlot({
category <- input$sel
ggplot(df_sub(),aes(wt,mpg)) +
geom_point(aes_(color=as.name(category)),size=3) +
geom_smooth(method = "lm")
})
selectInput()에 의해서 선택된 값은 input$sel 에 할당되고 이것은 반응성 맥락에 존재하게 된다. 따라서 input$set은 반응성 맥락이라면 어디에서든 사용 가능하다. input$sel은 반응성 맥락에 존재하는 반응성 값이기 때문에 반응성 맥락 밖에서 접근하면 앱이 실행되지 않는다. 이런 반응성 값은 reactive() 또는 render*(), 나중에 설명할 observe() 함수 등과 같이 반응성 맥락을 반드는 함수에서 사용되어야 한다.
22-3 비표준평가의 탈출구 사용 예
앞의 renderPlot() 안에서 다음과 같이 ggplot2 패키지를 사용한 플롯 작성 코드를 사용했다.
category <- input$sel
ggplot(df_sub(),aes(wt,mpg)) +
geom_point(aes_(color=as.name(category)),size=3) +
geom_smooth(method = "lm")
인터랙티브 환경에 익숙하고 프로그램을 잘 해보지 않은 경우라면 다음과 같이 코딩하면 된다고 생각할 수도 있다.
category <- input$sel
ggplot(df_sub(),aes(wt,mpg)) +
geom_point(aes(color=input$sel),size=3) +
geom_smooth(method="lm")
차이는 aes_() 라는 탈출구 역할을 하는 함수가 사용되었다는 것인데, 다음 코드도 앞에서 설명한 이유와 같이 비슷한 이유로 코딩을 하였다.
+ output$carAnova <- renderPrint({
+ formul <- as.formula(paste("mpg~wt","+",input$sel))
+ anova(lm(formul,data = df_sub())
'전공 > R프로그래밍' 카테고리의 다른 글
R 프로그래밍 24. 스콥과 시야(visibility) (0) | 2019.08.26 |
---|---|
R프로그래밍 23. 코드 실행 과정과 앱의 상태 (0) | 2019.08.20 |
R프로그래밍 21. 샤이니에서 유용한 함수들 (0) | 2019.08.16 |
R프로그래밍 20. R에서 파일 다루기 (0) | 2019.08.14 |
R프로그래밍19. 비표준 평가(non-standard evaluation)와 탈출구(escape hatch) (0) | 2019.08.08 |