정보

    • 업무명     : R를 이용한 고급 기상 통계학 실습 : R 기초, 자료의 특성, 자료의 상관성, 통계적 유의수준, 조화 분석, 주성분 분석, 기계 학습

    • 작성자     : 이상호

    • 작성일     : 2020-03-16

    • 설   명      :

    • 수정이력 :

     

     내용

    [개요]

    • 안녕하세요? 기상 연구 및 웹 개발을 담당하고 있는 해솔입니다.

    • 대학원 석사 1학기에 배운 고급 기상 통계학에 대한 실습 내용을 다루고자 합니다.

    • 그에 따른 주제는 "R 기초, 자료의 특성, 자료의 상관성, 통계적 유의수준, 조화 분석, 주성분 분석, 기계 학습" 순으로 소개해 드리고자 합니다.

    • 추가로 각 주제에 대한 이론적 배경을 소개한 링크를 보내드립니다.

     

    [강릉원주대 대기환경과학과] 2015년 2학기 전필 고급기상통계학 소개 및 과제물

    정보 업무명 : 고급기상통계학 작성자 : 이상호 작성일 : 2019-12-20 설 명 : 수정이력 : 내용 [특징] 고급기상통계학 수업에 대한 이해를 돕기위해 작성 [기능] 소개 주제별 과제물 자료의 특성 자료의 상관성..

    shlee1990.tistory.com

     

    [특징]

    • 대기과학에 사용하는 기상 통계학을 이해하기 위해서 실습이 요구되며 이 프로그램은 이러한 목적을 달성하기 위한 소프트웨어

     

    [기능]

    • R 기초

    • 자료의 특성

    • 자료의 상관성

    • 통계적 유의수준

    • 조화 분석

    • 주성분 분석

    • 인공 신경망 및 딥러닝

     

    [활용 자료]

    • 소스 코드 및 활용 자료 첨부

     

    202. [Advanced Meteorological Statistics] R-project Practice_Ver 2.0 (MS. Sang-Ho Lee)_20171218.7z

     

    drive.google.com

     

    [자료 처리 방안 및 활용 분석 기법]

    • 없음

     

    [사용법]

    • 라이브러리 읽기 : source("Library.R")

    • 소스 코드 참조

     

    [사용 OS]

    • Windows 10

     

    [사용 언어]

    • R v3.6.3

    • R Studio v1.2.5033

     

     주제

    [R 기초]

    • 1993년 뉴질랜드 오클랜드 대학의 통계학과 교수 2명 (Ross Ihaka, Robert Gentleman) 개발

    • 특징

      • 빠른 처리 속도 (H/W 메모리 크기에 영향 받음)

      • 데이터, 함수, 차트 등 모든 것이 object로 관리

      • 최신의 알고리즘 및 방법론이 패키지 (Package)로 제공됨  (Neural Networks, Deeplearning et al)

      • 분석에 통찰을 부여할 수 있는 그래픽에 대한 강력한 지원

     

     

     

    • Rstudio 4가지 패널 창 기능

      • 코딩 영역, 콘솔(실행결과), 작업내역/ 환경, 탐색시/그래프/도움말/패키지 구성

     

    • version와 패키지 및 session 보기

      • sessionInfo()  # 64 bit 권장 !

      • ?sessionInfo

    > sessionInfo()  # 64 bit 권장 ! 
    
    R version 3.6.3 (2020-02-29)
    Platform: x86_64-w64-mingw32/x64 (64-bit)
    Running under: Windows 10 x64 (build 18362)
    
    Matrix products: default
    
    Random number generation:
     RNG:     Mersenne-Twister 
     Normal:  Inversion 
     Sample:  Rounding 
     
    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     
    
    other attached packages:
     [1] devtools_2.2.2     usethis_1.5.1      reshape2_1.4.3     h2o_3.28.0.4      
     [5] neuralnet_1.44.2   MASS_7.3-51.5      mapdata_2.3.0      maps_3.3.0        
     [9] rgeos_0.5-2        colorRamps_2.3     leaflet_2.0.3      RNetCDF_2.1-1     
    [13] maptools_0.9-9     sp_1.4-1           gstat_2.0-4        zoo_1.8-7         
    [17] RColorBrewer_1.1-2 moments_0.14       MAT_2.2            ggcorrplot_0.1.3  
    [21] gridExtra_2.3      factoextra_1.0.6   forcats_0.4.0      stringr_1.4.0     
    [25] dplyr_0.8.3        purrr_0.3.3        readr_1.3.1        tidyr_1.0.2       
    [29] tibble_2.1.3       tidyverse_1.3.0    GGally_1.4.0       ggplot2_3.2.1     
    [33] akima_0.6-2       
    
    loaded via a namespace (and not attached):
     [1] nlme_3.1-144      bitops_1.0-6      fs_1.3.1          xts_0.12-0       
     [5] lubridate_1.7.4   httr_1.4.1        rprojroot_1.3-2   tools_3.6.3      
     [9] backports_1.1.5   R6_2.4.1          DBI_1.1.0         lazyeval_0.2.2   
    [13] colorspace_1.4-1  withr_2.1.2       prettyunits_1.1.1 tidyselect_0.2.5 
    [17] processx_3.4.1    compiler_3.6.3    cli_2.0.2         rvest_0.3.5      
    [21] xml2_1.2.2        desc_1.2.0        scales_1.1.0      callr_3.4.2      
    [25] digest_0.6.24     foreign_0.8-75    pkgconfig_2.0.3   htmltools_0.4.0  
    [29] sessioninfo_1.1.1 dbplyr_1.4.2      htmlwidgets_1.5.1 rlang_0.4.4      
    [33] readxl_1.3.1      rstudioapi_0.11   FNN_1.1.3         generics_0.0.2   
    [37] jsonlite_1.6.1    crosstalk_1.1.0.1 RCurl_1.98-1.1    magrittr_1.5     
    [41] Rcpp_1.0.3        munsell_0.5.0     fansi_0.4.1       lifecycle_0.2.0  
    [45] stringi_1.4.6     pkgbuild_1.0.6    plyr_1.8.5        grid_3.6.3       
    [49] ggrepel_0.8.1     crayon_1.3.4      lattice_0.20-38   haven_2.2.0      
    [53] hms_0.5.3         ps_1.3.0          zeallot_0.1.0     pillar_1.4.3     
    [57] spacetime_1.2-3   pkgload_1.0.2     reprex_0.3.0      glue_1.3.1       
    [61] remotes_2.1.1     modelr_0.1.6      vctrs_0.2.1       testthat_2.3.1   
    [65] cellranger_1.1.0  gtable_0.3.0      reshape_0.8.8     assertthat_0.2.1 
    [69] broom_0.5.5       intervals_0.15.1  memoise_1.1.0     ellipsis_0.3.0   

     

     

    • 단축키

      • <Ctrl + Enter> or <Ctrl + r> : script 실행 

      • <Ctrl + s> : 저장

     

    • 변수명 작성 규칙

      • 첫자는 영문자, 두번째는 숫자,특수문자(_ .)

      • 대소문자 구분(num, NUM)

      • 명령어, 함수명 사용 불가

      • 가장 최근값 저장

      • R의 모든 변수 = 객체 

     

    • 패키지

      • install.packages("moments")  #  패키지 설치

      • library(moments)  # 패키지 사용

      • source("Library.R") # 패키지 사용 및 설치

    #=================================================================================================
    # Routine  : Main R-project program
    #
    # Purpose  : Package install, load, and function 
    #            source("Library.R")
    #
    # Author   : MS. Sang-Ho Lee
    #
    # Revisions: V1.0 August   21, 2017 First release (MS. Sang-Ho Lee)
    #            V2.0 Decebmer 01, 2017 Change to ifelse when using package (MS. Sang-Ho Lee)
    #=================================================================================================
    
          # install.packages("moments")
          # install.packages("RColorBrewer")
          # install.packages("dplyr")
          # install.packages("zoo")
          # install.packages("ggplot2")
          # install.packages("gstat")
          # install.packages("sp")
          # install.packages("maptools")
          # install.packages("RNetCDF")
          # install.packages("leaflet")
          # install.packages("colorRamps")
          # install.packages("gpclib")
          # install.packages("rgeos")
          # install.packages("mapdata")
          # install.packages("MASS")
          # install.packages("neuralnet")
          # install.packages("h2o")
          # install.packages("reshape2")
          # install.packages("devtools")
          # install.packages("sinkr")
          # install.packages("MASS")
          # install.packages("MAT")
          # install.packages("ggcorrplot")
          # install.packages("gridExtra")
          # install.packages("factoextra")
          # install.packages("tidyverse")
          # install.packages("GGally")
    
    
          library(akima)
          library(GGally)
          library(tidyverse)
          library(factoextra)
          library(gridExtra)
          library(ggcorrplot)
          library(MAT)
          library(moments)
          library(RColorBrewer)
          library(dplyr)
          library(zoo)
          library(ggplot2)
          library(gstat)
          library(sp)
          library(maptools)
          library(RNetCDF)
          library(leaflet)
          library(colorRamps)
          library(gpclib)
          library(rgeos)
          library(mapdata)
          library(MASS)
          library(neuralnet)
          library(h2o)
          library(reshape2)
          library(devtools)
          library(sinkr)
          library(MASS)
    
    
    ggplot_windrose = function(data, spd, dir, spdres = 2, dirres = 30, spdmin = 2, spdmax = 20, spdseq = NULL,
                              palette = "YlGnBu", countmax = NA, debug = 0){
       
       # Look to see what data was passed in to the function
       if (is.numeric(spd) & is.numeric(dir)){
          # assume that we've been given vectors of the speed and direction vectors
          data <- data.frame(spd = spd, dir = dir)
          spd = "spd"
          dir = "dir"
       } else if (exists("data")){
          # Assume that we've been given a data frame, and the name of the speed 
          # and direction columns. This is the format we want for later use.    
       }  
       
       # Tidy up input data ----
       n.in <- NROW(data)
       dnu <- (is.na(data[[spd]]) | is.na(data[[dir]]))
       data[[spd]][dnu] <- NA
       data[[dir]][dnu] <- NA
       
       # figure out the wind speed bins ----
       if (missing(spdseq)){
          spdseq <- seq(spdmin, spdmax, spdres)
       } else {
          if (debug >0){
             cat("Using custom speed bins \n")
          }
       }
       # get some information about the number of bins, etc.
       n.spd.seq <- length(spdseq)
       n.colors.in.range <- n.spd.seq - 1
       
       # create the color map
       spd.colors <- colorRampPalette(brewer.pal(min(max(3,n.colors.in.range), min(9,n.colors.in.range)), palette))(n.colors.in.range)
       
       if (max(data[[spd]],na.rm = TRUE) > spdmax){    
          spd.breaks <- c(spdseq, max(data[[spd]],na.rm = TRUE))
          spd.labels <- c(paste(c(spdseq[1:n.spd.seq-1]), '-', c(spdseq[2:n.spd.seq])),
                          paste(spdmax, "-", max(data[[spd]],na.rm = TRUE)))
          spd.colors <- c(spd.colors, "grey50")
       } else{
          spd.breaks <- spdseq
          spd.labels <- paste(c(spdseq[1:n.spd.seq-1]), '-', c(spdseq[2:n.spd.seq]))    
       }
       data$spd.binned <- cut(x = data[[spd]], breaks = spd.breaks, labels = spd.labels, ordered_result = TRUE)
       # clean up the data
       data. <- na.omit(data)
       
       # figure out the wind direction bins
       dir.breaks <- c(-dirres/2, seq(dirres/2, 360-dirres/2, by = dirres), 360+dirres/2)  
       dir.labels <- c(paste(360-dirres/2,"-",dirres/2), paste(seq(dirres/2, 360-3*dirres/2, by = dirres),
                             "-", seq(3*dirres/2, 360-dirres/2, by = dirres)), paste(360-dirres/2,"-",dirres/2))
       # assign each wind direction to a bin
       dir.binned <- cut(data[[dir]], breaks = dir.breaks, ordered_result = TRUE)
       levels(dir.binned) <- dir.labels
       data$dir.binned <- dir.binned
       
       # Run debug if required ----
       if (debug>0){    
          cat(dir.breaks,"\n")
          cat(dir.labels,"\n")
          cat(levels(dir.binned),"\n")       
       }  
       
       # deal with change in ordering introduced somewhere around version 2.2
       if(packageVersion("ggplot2") > "2.2"){    
          # cat("Hadley broke my code\n")
          data$spd.binned = with(data, factor(spd.binned, levels = rev(levels(spd.binned))))
          spd.colors = rev(spd.colors)
       }
       
       # create the plot ----
       p.windrose <- ggplot(data = data, aes(x = dir.binned, fill = spd.binned)) +
          geom_bar() + 
          scale_x_discrete(drop = FALSE, labels = waiver()) +
          coord_polar(start = -((dirres/2)/360) * 2*pi) +
          scale_fill_manual(name = "Wind  Speed  [m/s]", values = spd.colors, drop = FALSE) +
          #theme_bw() +
          theme(axis.title.x = element_blank(),
                #panel.border = element_rect(colour = "blank"),
                panel.grid.major = element_line(colour="grey65")) +
          theme_bw() +
          theme(plot.title=element_text(face="bold", size=20)) +
          theme(axis.title.x = element_text(face="bold", size=15)) +
          theme(axis.title.y = element_text(face="bold", size=15, angle=90)) +
          theme(axis.text.x  = element_text(face="bold", size=15)) +
          theme(axis.text.y  = element_text(face="bold", size=15)) +
          theme(legend.text=element_text(size=15)) +
          theme(legend.title=element_text(size=15)) +
          labs(x = "") +
          labs(y = "Frequency  of  Counts  by  Wind  Direction") 
       
       # adjust axes if required
       if (!is.na(countmax)){
          p.windrose <- p.windrose +
             ylim(c(0,countmax))
       }
       
       # print the plot
       # print(p.windrose)  
       
       # return the handle to the wind rose
       return(p.windrose)
    }

     

    [자료의 특성]

    • 기본 통계량 계산

      • 자료의 개수 : length

      • 평균 : mean

      • 중간값 : median

      • 최빈값 : which.max

      • 분산 : var

      • 표준편차 : sd

      • 최대값 : max

      • 최소값 : min

      • 왜도 : skewness

      • 첨도 : kurtosis

      • 요약 통계량 : summary

      • cat를 통해 자료 출력

      • cat에서 file 옵션을 통해 자료 저장

    X = c(1, 2, 3, 4, 5)
    Y = c(3, 6, 1, 2, 3)
    
    length(Y)    # 자료의 개수
    mean(Y)      # 평균 = sum(Y)/length(Y)
    
    median(Y)    # 중간값
    names(which.max(table(Y)))  #  최빈값
    var(Y)       # 분산 = sum((Y-mean(Y))^2)/(length(Y)-1)
    sd(Y)        # 표준편차 = sqrt(sum((Y-mean(Y))^2)/(length(Y)-1))
    max(Y)       # 최대값
    min(Y)       # 최소값 
    skewness(Y)  # 왜도 = sum((Y-mean(Y))^3)/(length(Y)*(sqrt(sum((Y-mean(Y))^2)/length(Y))^3))
    kurtosis(Y)  # 첨도 = sum((Y-mean(Y))^4)/(length(Y)*(sqrt(sum((Y-mean(Y))^2)/length(Y))^4))
    
    summary(Y)   # 요약 통계량 = Min./1st Qu./Median/Mean/3rd Qu./Max.
    
    Number = length(Y)
    Mean = mean(Y)
    Median = median(Y)
    Mode = names(which.max(table(Y)))
    Var = var(Y)
    Sd = sd(Y)
    Max = max(Y)
    Min = min(Y)
    Skew = skewness(Y)
    Kurt = kurtosis(Y)
    
    ## 자료 출력
    cat(Number, Mean, Median, Mode, Var, Sd, Max, Min, Skew, Kurt, "\n")
    
    ## 자료 저장
    cat(Number, Mean, Median, Mode, Var, Sd, Max, Min, Skew, Kurt, "\n", file='1.dat')

     

     

     

    [자료의 상관성]

    • 선형 회귀 모형 : lm

    • 상관 계수 : cor.test에서 estimate 또는 cor

    • 결정 계수 : cor.test에서 estimate의 거듭제곱

    • 유의성 검정 (P-Value) : cor.test에서 p.value

    X = c(1, 2, 3, 4, 5)
    Y = c(3, 6, 4, 3, 2)
    
    Number = length(Y)
    
    ## 선형 회귀모형
    lm.fit = lm(Y ~ X)  #  Y : 종속변수, X : 독립변수
    summary(lm.fit) 
    
    ## (Yfit) = a(X) + b -> coef.
    a = coef(lm.fit)[2] 
    b = coef(lm.fit)[1]
    # a = ( sum(X*Y)-(sum(X)*sum(Y)/length(X)) ) / ( sum(X^2)-((sum(X)^2)/length(X)) )
    # b = mean(Y) - (a*mean(X))
    
    Yfit = (a*X) + b
    
    Cor = cor.test(X, Y)$estimate  # 상관계수 (correlation coefficient)
    Cor = cor(X, Y)
    ## Cor = ( sum(X*Y)-(sum(X)*sum(Y)/length(X)) ) / ( sqrt(sum(X^2)-((sum(X)^2)/length(X)))*sqrt(sum(Y^2)-((sum(Y)^2)/length(Y))) )
    
    Rsq = (cor.test(X, Y)$estimate)^2  # 결정계수 (R-squared)
    ## Rsq = var(Yfit)/var(Y)
    
    Pvalue = cor.test(X, Y)$p.value  # 유의성 검정(p-value)
    
    cat(a, b, Cor, Rsq, Pvalue, "\n", file='2.dat')
    
    ## FIG
    dev.off()      # Initialization
    par(cex.main=1.2, cex.lab=1.2, cex.axis=1.2, cex=1.2, font=1)
    plot(X, Y, pch=21, bg="white", col='black', main="Relationship between X and Y", 
         xlim=c(0, 10), ylim=c(0, 10), xlab="X lab", ylab="Y lab", xaxs="i", yaxs="i", cex=1.5)
    lines(X, Yfit, col="red")  
    abline(a=0, b=1, lty=2, col="black")
    text(1, 9, paste0("Y = ", round(a,2), " X + ", round(b,2)), adj=0, col="red")
    text(1, 8, paste0("R = ", round(cor(X, Yfit), 2), " (p-value < ", round(Pvalue, 3), ")"), adj=0, col="red")
    text(1, 7, paste0("N = ", round(Number,2)), adj=0)
    
    
    ## 비선형 회귀모형
    X2 = X^2
    lm.fit = lm(Y ~ X + X2)
    summary(lm.fit)
    
    # (Yfit) = a(X2) + b(X) + c -> coeff.
    a = coef(lm.fit)[3] 
    b = coef(lm.fit)[2]
    c = coef(lm.fit)[1]
    Yfit = (a*X2) + (b*X) + c
    Cor = cor(Yfit, Y)
    Pvalue = cor.test(Yfit, Y)$p.value  # 유의성 검정(p-value)
    
    # FIG
    dev.off()      # Initialization
    par(cex.main=1.2, cex.lab=1.2, cex.axis=1.2, cex=1.2, font=1)
    plot(X, Y, pch=21, bg="white", col='black', main="Relationship between X and Y", 
         xlim=c(0, 10), ylim=c(0, 10), xlab="X lab", ylab="Y lab", xaxs="i", yaxs="i", cex=1.5)
    lines(X, Yfit, col="red")  
    abline(a=0, b=1, lty=2, col="black")
    text(1, 9, paste0("Y = ", round(a,2), " X2 + ", round(b,2), " X +", round(c, 2)), adj=0, col="red")
    text(1, 8, paste0("R = ", round(Cor, 2), " (p-value < ", round(Pvalue, 3), ")"), adj=0, col="red")
    text(1, 7, paste0("N = ", round(Number,2)), adj=0)

     

    • 선형 회귀 분석에 대한 산점도

     

    • 비선형 회귀 분석에 대한 산점도

     

    [통계적 유의수준]

    • 모집단 및 표본집단의 평균/분산/표준편차 비교

      • 중심극한정리 : 동일한 확률분포를 가진 독립확률 변수 n개의 평균값은 n이 클수록 정규분포에 가까워짐

      • 표본집단을 통하여 모집단의 정보를 알고싶음

      • 즉 표본평균집단의 평균/분산/표준편차를 이용하여 모집단의 평균/분산/표준편차를 유추할 수 있음

        • 모집단의 평균 = 표본평균집단의 평균

        • 모집단의 분산/자료수 = 표본평균집단의 분산                  

        • 모집단의 표준편차/루트(자료수) = 표본평균집단의 표준편차

        • 표본 개수가 많을수록 모집단을 더 잘 유추할 수 있음 > 정규분포에 가까워짐

     

    ######################################## 모집단 및 표본집단의 평균/분산/표준편차 비교 ##############################
    ##  - 중심극한정리 : 동일한 확률분포를 가진 독립확률 변수 n개의 평균값은 n이 클수록 정규분포에 가까워짐
    ##  - 표본집단을 통하여 모집단의 정보를 알고싶음
    ##  - 즉 표본평균집단의 평균/분산/표준편차를 이용하여 모집단의 평균/분산/표준편차를 유추할 수 있음
    ##    -- 모집단의 평균                  = 표본평균집단의 평균
    ##    -- 모집단의 분산/자료수           = 표본평균집단의 분산                  
    ##    -- 모집단의 표준편차/루트(자료수) = 표본평균집단의 표준편차
    ##  -> 표본 개수가 많을수록 모집단을 더 잘 유추할 수 있음  -> 정규분포에 가까워짐
    ####################################################################################################################
    
    set.seed(1)                   # 난수로 생성된 수열을 고정시킴
    X = runif(10000, min=0, max=1)  # 난수 생성 (모집단 생성)
    
    hist(X)  # 모집단의 빈도분포 
    cat(mean(X), var(X), sd(X), "\n")  # 모집단의 평균/분산/표준편차
    
    
    ################################################### 표본평균집단에 대해서 ###########################################################
    for (i in c(10, 50, 100, 250)) {
    
       DO = 100000    # Number of repetition 
       N = i          # Number of sample
       # N = 30       
       
       ## 비복원 추출(무작위 정렬) : 한번 뽑은 것을 다시 뽑을 수 없는 추출
       Sort = lapply(1:DO, function(i) sample(X, N, replace=F))  
       Sort_mean <- mapply(mean, Sort)
    
       ## FIG
       # nf <- layout(matrix(c(1,1),1,byrow=T), c(1,1), c(1,1)) ; layout.show(nf) ; par(mar=c(5,5,5,5)) ; par(cex=1.0)
       hist(Sort_sd, breaks=50, xlab="Sample Distribution Mean", xlim=c(0.20, 0.35), col = "light grey", border = "grey", xaxs="i", yaxs="i",
            main=paste0("Central Limit Theorem : number of sample = ", N, ", number of repetition = ", sprintf("%d", Do)))
    
       XX1 = mean(Sort_mean)+sd(Sort_mean)
       XX2 = mean(Sort_mean)-sd(Sort_mean)
       XX3 = mean(Sort_mean)+2*sd(Sort_mean)
       XX4 = mean(Sort_mean)-2*sd(Sort_mean)
       XX5 = mean(Sort_mean)+3*sd(Sort_mean)
       XX6 = mean(Sort_mean)-3*sd(Sort_mean)
       YY = max(hist(Sort_mean, breaks=50, plot=F)$counts)
       lines( c(mean(Sort_mean), mean(Sort_mean)), c(0, YY), lty=1, col=4) ; text(mean(Sort_mean), YY/2, "Mean")
       lines( c(XX1, XX1), c(0, YY), lty=1, col=2 ) ; text( XX1, YY/2, "+1σ")
       lines( c(XX2, XX2), c(0, YY), lty=1, col=2 ) ; text( XX2, YY/2, "-1σ")
       lines( c(XX3, XX3), c(0, YY), lty=1, col=2 ) ; text( XX3, YY/2, "+2σ")
       lines( c(XX4, XX4), c(0, YY), lty=1, col=2 ) ; text( XX4, YY/2, "-2σ")
       lines( c(XX5, XX5), c(0, YY), lty=1, col=2 ) ; text( XX5, YY/2, "+3σ")
       lines( c(XX6, XX6), c(0, YY), lty=1, col=2 ) ; text( XX6, YY/2, "-3σ")
       lines( c(max(Sort_mean), max(Sort_mean)), c(0, YY), lty=1, col=3 ) ; text(max(Sort_mean), YY/2, "Max")
       lines( c(min(Sort_mean), min(Sort_mean)), c(0, YY), lty=1, col=3 ) ; text(min(Sort_mean), YY/2, "Min")
       
       
       ## 자료수, 표본평균집단의 평균, 표본평균집단의 분산, 표본평균집단의 표준편차
       ## (표본평균집단의 평균-모집단의 평균), (표본평균집단의 분산 - 모집단의 분산/자료수), (표본평균집단의 표준편차 - 모집단의 표준편차/루트(자료수))
       # cat(N, mean(Sort_mean), var(Sort_mean), sd(Sort_mean),
           # mean(Sort_mean)-mean(X), var(Sort_mean)-(var(X)/N), sd(Sort_mean)-(sd(X)/sqrt(N)), "\n")
       
       # 모집단의 평균, 분산/자료수, 표준편차/루트(자료수)
       # cat(mean(X), var(X)/length(X), sd(X)/sqrt(length(X)), "\n")
    }
    
    
    ################################################### 표본표준편차집단에 대해서 ###########################################################
    
    X = runif(10000, min=0, max=1)  # 난수 생성 (모집단 생성)
    hist(X)  # 모집단의 빈도분포 
    cat(mean(X), var(X), sd(X), "\n")  # 모집단의 평균/분산/표준편차
    
    for (i in c(5, 10, 25, 50, 100, 250)) {
       
       DO = 100000    # Number of repetition 
       N = i          # Number of sample
       # N = 30   
       
       Sort = lapply(1:DO, function(i) sample(X, N, replace=F))  # 비복원 추출(무작위 정렬) : 한번 뽑은 것을 다시 뽑을 수 없는 추출
       Sort_mean <- mapply(mean, Sort)
       Sort_sd <- mapply(sd, Sort)
       
       ## FIG
       hist(Sort_sd, breaks=50, xlab="Sample Distribution Stdev", xlim=c(0.2, 0.4), col = "light grey", border = "grey", xaxs="i", yaxs="i",
       main=paste0("Central Limit Theorem : number of sample = ", N, ", number of repetition = ", sprintf("%d", DO)))
       
       XX1 = mean(Sort_sd)+sd(Sort_sd)
       XX2 = mean(Sort_sd)-sd(Sort_sd)
       XX3 = mean(Sort_sd)+2*sd(Sort_sd)
       XX4 = mean(Sort_sd)-2*sd(Sort_sd)
       XX5 = mean(Sort_sd)+3*sd(Sort_sd)
       XX6 = mean(Sort_sd)-3*sd(Sort_sd)
       YY = max(hist(Sort_sd, breaks=50, plot=F)$counts)
       lines( c(mean(Sort_sd), mean(Sort_sd)), c(0, YY), lty=1, col=4) ; text(mean(Sort_mean), YY/2, "Mean")
       lines( c(XX1, XX1), c(0, YY), lty=1, col=2 ) ; text( XX1, YY/2, "+1σ")
       lines( c(XX2, XX2), c(0, YY), lty=1, col=2 ) ; text( XX2, YY/2, "-1σ")
       lines( c(XX3, XX3), c(0, YY), lty=1, col=2 ) ; text( XX3, YY/2, "+2σ")
       lines( c(XX4, XX4), c(0, YY), lty=1, col=2 ) ; text( XX4, YY/2, "-2σ")
       lines( c(XX5, XX5), c(0, YY), lty=1, col=2 ) ; text( XX5, YY/2, "+3σ")
       lines( c(XX6, XX6), c(0, YY), lty=1, col=2 ) ; text( XX6, YY/2, "-3σ")
       lines( c(max(Sort_sd), max(Sort_sd)), c(0, YY), lty=1, col=3 ) ; text(max(Sort_mean), YY/2, "Max")
       lines( c(min(Sort_sd), min(Sort_sd)), c(0, YY), lty=1, col=3 ) ; text(min(Sort_mean), YY/2, "Min")
       
    
       ## 샘플개수, 표본평균의 표준편차, 표본표준편차의 평균/sqrt(N),  (표본평균의 표준편차-표본표준편차의 평균/sqrt(N)
       cat(N, sd(Sort_mean), mean(Sort_sd)/sqrt(N), sd(Sort_mean)-(mean(Sort_sd)/sqrt(N)), "\n")
       
       ## 중심극한정리는 샘플 개수에 작으면 약해짐.  즉 샘플 개수가 작을수록 표준편차가 증가함.
    }
    
    
    
    
    ################################################### 상관계수에 대한 유의성 검정 ###########################################################      
    data = read.csv("INPUT/KMA/1904-2016_Yearly_Mean_Groud_Obs.KMA", sep="", header=TRUE)   
    head(data)  # 파일의 첫 행
    tail(data)  # 파일을 마지막 행
    
    ## 시간: 1904-2016년 연평균 자료 (지상관측)
    
    ## 변수: 지점,  년,  기온,  기압,  상대습도,  풍속
    ##        id   year  temp   pre       rh       ws
    
    ## 지점: 강릉,  광주,  대구,  대전,  부산,  서울,  전주,  제주,  청주,  춘천,  원주,  대관령
    ##        105    156    143    133    159    108    146    184    131    101    114    100
    
    ## 출처: 기상청  국가기후데이터센터 (http://sts.kma.go.kr/jsp/home/contents/main/main.do)
    
    ## 지점마다 관측 기간이 다름
       ### 대관령: 1972-2016
       ### 춘천  : 1966-2016
       ### 강릉  : 1912-2016
       ### 서울  : 1908-2016
       ### 원주  : 1972-2016          
       ### 청주  : 1979-2016
       ### 대구  : 1909-2016
       ### 전주  : 1919-2016
       ### 광주  : 1940-2016
       ### 제주  : 1924-2016
    
       ## 1979-2016년에 대해 분석을 수행함.
    
    
    ####  강릉 지역에 대한 상관계수 및 유의성 검정
    data_L1 = data %>% 
       filter( id == 105 ) %>%
       filter( year >= 1979 )
    
    
    #### FIG
    X = data_L1$year
    Y = data_L1$temp
    
    dev.off()      # Initialization
    par(cex.main=1.2, cex.lab=1.2, cex.axis=1.2, cex=1.2, font=1)
    plot(X, Y, col='black', main="Time  series  of  yearly  averaged  temperature  for  the  year  of  1979-2016", 
         xlab="Time  [Year]", ylab="Temperature  [℃]",  xlim=c(1979, 2016), type="l", ylim=c(10, 15), 
         xaxs="i", yaxs="i", cex=1.5)
    lm.fit =lm(Y ~ X)
    abline(lm.fit, col="red")
    text(1980, 14.5, paste0("(Temperature) = ", round(coef(lm.fit)[2],2), " × (Year) ", round(coef(lm.fit)[1],2)), adj=0, col="red", cex=1.2)
    text(1980, 14, paste0("R = ", round(cor(X, Y), 2)), adj=0, col="red", cex=1.2)
    text(1980, 13.5, paste0("N = ", round(length(X),2)), adj=0, cex=1.2)
    
    
    
    ################################################### 강릉 지역에 대한 유의성 검정 ###########################################################
    DO = 100000     # Number of repetition
    N  = length(X)  # Number of sample
    
    Sort_X = lapply(1:DO, function(i) X[1:N] )
    Sort_Y = lapply(1:DO, function(i) sample(Y, N, replace=F))  # 비복원추출(무작위 정렬)
    Sort_R = mapply(cor, Sort_X, Sort_Y)
    
    #### FIG
    # nf <- layout(matrix(c(1,1),1,byrow=T), c(1,1), c(1,1)) ; layout.show(nf) ; par(mar=c(5,5,5,5)) ; par(cex=1.0) 
    hist(Sort_R, breaks=50, xlab="Sample Distribution Coefficient Correlation", xlim=c(-1, 1), col = "light grey",  xaxs="i", yaxs="i",
         border = "grey", main=paste0("Central Limit Theorem : number of sample = ", N, ", number of repetition = ", sprintf("%d", DO))) 
    
    XX1 = mean(Sort_R)+sd(Sort_R)
    XX2 = mean(Sort_R)-sd(Sort_R)
    XX3 = mean(Sort_R)+2*sd(Sort_R)
    XX4 = mean(Sort_R)-2*sd(Sort_R)
    XX5 = mean(Sort_R)+3*sd(Sort_R)
    XX6 = mean(Sort_R)-3*sd(Sort_R)
    YY = max(hist(Sort_R, breaks=50, plot=F)$counts)
    lines( c(mean(Sort_R), mean(Sort_R)), c(0, YY), lty=1, col=4) ; text(mean(Sort_R), YY/2, "Mean")
    lines( c(XX1, XX1), c(0, YY), lty=1, col=2 ) ; text( XX1, YY/2, "+1σ")
    lines( c(XX2, XX2), c(0, YY), lty=1, col=2 ) ; text( XX2, YY/2, "-1σ")
    lines( c(XX3, XX3), c(0, YY), lty=1, col=2 ) ; text( XX3, YY/2, "+2σ")
    lines( c(XX4, XX4), c(0, YY), lty=1, col=2 ) ; text( XX4, YY/2, "-2σ")
    lines( c(XX5, XX5), c(0, YY), lty=1, col=2 ) ; text( XX5, YY/2, "+3σ")
    lines( c(XX6, XX6), c(0, YY), lty=1, col=2 ) ; text( XX6, YY/2, "-3σ")
    lines( c(max(Sort_R), max(Sort_R)), c(0, YY), lty=1, col=3 ) ; text(max(Sort_R), YY/2, "Max")
    lines( c(min(Sort_R), min(Sort_R)), c(0, YY), lty=1, col=3 ) ; text(min(Sort_R), YY/2, "Min")
    lines( c(cor(X, Y), cor(X, Y)), c(0, YY), lty=1, col=5, lw=2 ) ; text(cor(X, Y), YY/2, "R")
    
    
    ## 상관계수에 대한 유의성 검정  ->  유의확률 (significance probability) = P값 (p-value)*100 %
    ##                                   신뢰도 (1 - P값)
    
    Pval = sum (abs(Sort_R) >= abs(cor(X, Y))) /length(Sort_R)    # (Source: http://strata.uga.edu/8370/lecturenotes/resampling.html)
    Pval
    
    ## 상관계수는 0.47로서 통계적으로 0.3 % 수준으로 유의하다.
    ##                                99.7 % 수준으로 신뢰할 만하다.
    ##                                1000번 중에 약 3번은 우연의 일치이다.
    ##                                1000번 중에 약 997번은 우연의 일치가 아니다.
    
    cor.test(X, Y)              
       # n <- length(X)                                 # How is the p-value calculated for pearson correlation ?
       # r <- cor(X, Y)
       # df <- n - 2
       # t = sqrt(df) * r/sqrt(1 - r^2)
       # pval = 2 * min(pt(t, df), pt(t, df, lower.tail = FALSE))
    
    
    ################################################### 10 지점에 대한 상관계수 및 유의성 검정 ###########################################################
    for ( i in c(105, 156, 143, 133, 159, 108, 146, 184, 131, 101, 114, 100) ) {
       
       data_L1 = data %>% 
          filter( id == i ) %>%
          # filter( year >= 1979 )
          filter( year >= 2000 )
       
       X = data_L1$year
       Y = data_L1$temp
       
       
       DO = 100000    # Number of repetition
       N  = length(X)  # Number of sample
       
       Sort_X = lapply(1:DO, function(i) X[1:N] )
       Sort_Y = lapply(1:DO, function(i) sample(Y, N, replace=F))  # 비복원추출(무작위 정렬)
       Sort_R = mapply(cor, Sort_X, Sort_Y)
       
       Pval = sum (abs(Sort_R) >= abs(cor(X, Y))) /length(Sort_R)    # (Source: http://strata.uga.edu/8370/lecturenotes/resampling.html)
    
       Pval2 = cor.test(X, Y) 
       
       ## 지점, 상관계수, 몬테카를로 시뮬레이션에 의한 유의성, 근사식에 의한 유의성
       cat(i, cor(X, Y), Pval, Pval2$p.value, "\n")
    }
    
    
    
    ################################################### 이동평균를 이용하여 상관계수 및 유의성 검정 ###########################################################
    
    ## 이동평균 예시
    rollmean(c(1:6), 5)
    
    data_L1 = data %>% 
       filter( id == 105 ) %>%
       filter( year >= 1979 ) 
    
       
    X = data_L1$year
    Y = data_L1$temp
    
    ## 5개의 이동평균      
    X2 = rollmean(data_L1$year, 5)
    Y2 = rollmean(data_L1$temp, 5)
    
    
    #### FIG
    dev.off()      # Initialization
    par(cex.main=1.2, cex.lab=1.2, cex.axis=1.2, cex=1.2, font=1)
    plot(X2, Y2, col='black', main="Time  series  of  yearly  averaged  temperature  for  the  year  of  1979-2016", 
         xlab="Time  [Year]", ylab="Temperature  [℃]",  xlim=c(1979, 2016), type="l", ylim=c(10, 15), 
         xaxs="i", yaxs="i", cex=1.5)
    lm.fit =lm(Y2 ~ X2)
    abline(lm.fit, col="red")
    text(1980, 14.5, paste0("(Temperature) = ", round(coef(lm.fit)[2],2), " × (Year) ", round(coef(lm.fit)[1],2)), adj=0, col="red", cex=1.2)
    text(1980, 14, paste0("R = ", round(cor(X2, Y2), 2)), adj=0, col="red", cex=1.2)
    text(1980, 13.5, paste0("N = ", round(length(X2),2)), adj=0, cex=1.2)
    
    
    #### FIG
    DO = 10000         # Number of repetition
    N  = length(X)     # Number of sample
    # N2 = length(X2)  # Number of sample
    
    Sort_X = lapply(1:DO, function(i) rollmean(X[1:N], 5) )  #  Sort_X = lapply(1:DO, function(i) X2[1:N2])
    Sort_Y = lapply(1:DO, function(i) rollmean(sample(Y, N, replace=F), 5))  # 비복원추출(무작위 정렬)
    Sort_R = mapply(cor, Sort_X, Sort_Y)
    
    # nf <- layout(matrix(c(1,1),1,byrow=T), c(1,1), c(1,1)) ; layout.show(nf) ; par(mar=c(5,5,5,5)) ; par(cex=1.0) 
    hist(Sort_R, breaks=50, xlab="Sample Distribution Coefficient Correlation", xlim=c(-1, 1), col = "light grey",  xaxs="i", yaxs="i",
         border = "grey", main=paste0("Central Limit Theorem : number of sample = ", N, ", number of repetition = ", sprintf("%d", DO))) 
    
    XX1 = mean(Sort_R)+sd(Sort_R)
    XX2 = mean(Sort_R)-sd(Sort_R)
    XX3 = mean(Sort_R)+2*sd(Sort_R)
    XX4 = mean(Sort_R)-2*sd(Sort_R)
    XX5 = mean(Sort_R)+3*sd(Sort_R)
    XX6 = mean(Sort_R)-3*sd(Sort_R)
    YY = max(hist(Sort_R, breaks=50, plot=F)$counts)
    lines( c(mean(Sort_R), mean(Sort_R)), c(0, YY), lty=1, col=4) ; text(mean(Sort_R), YY/2, "Mean")
    lines( c(XX1, XX1), c(0, YY), lty=1, col=2 ) ; text( XX1, YY/2, "+1σ")
    lines( c(XX2, XX2), c(0, YY), lty=1, col=2 ) ; text( XX2, YY/2, "-1σ")
    lines( c(XX3, XX3), c(0, YY), lty=1, col=2 ) ; text( XX3, YY/2, "+2σ")
    lines( c(XX4, XX4), c(0, YY), lty=1, col=2 ) ; text( XX4, YY/2, "-2σ")
    lines( c(XX5, XX5), c(0, YY), lty=1, col=2 ) ; text( XX5, YY/2, "+3σ")
    lines( c(XX6, XX6), c(0, YY), lty=1, col=2 ) ; text( XX6, YY/2, "-3σ")
    lines( c(max(Sort_R), max(Sort_R)), c(0, YY), lty=1, col=3 ) ; text(max(Sort_R), YY/2, "Max")
    lines( c(min(Sort_R), min(Sort_R)), c(0, YY), lty=1, col=3 ) ; text(min(Sort_R), YY/2, "Min")
    lines( c(cor(X2, Y2), cor(X2, Y2)), c(0, YY), lty=1, col=5, lw=2 ) ; text(cor(X, Y), YY/2, "R")
    
    
    ## 상관계수에 대한 유의성 검정  -->  유의확률 (significance probability) = P값 (p-value)*100 %
    ##                                   신뢰도 (1 - P값)
    
    Pval = sum (abs(Sort_R) >= abs(cor(X2, Y2))) /length(Sort_R)    # (Source: http://strata.uga.edu/8370/lecturenotes/resampling.html)
    Pval
    
    ## 상관계수는 0.78로서 통계적으로 3.3 % 수준으로 유의하다.
    ##                                96.7 % 수준으로 신뢰할 만하다.
    ##                                1000번 중에 약 33번은 우연의 일치이다.
    ##                                1000번 중에 약 967번은 우연의 일치가 아니다.
    
    
    
    ################################################### 10 지점에서 이동평균을 이용하여 상관계수 및 유의성 검정 ###########################################################
    
    for ( i in c(105, 156, 143, 133, 159, 108, 146, 184, 131, 101, 114, 100) ) {
       
       data_L1 = data %>% 
          filter( id == i ) %>%
          filter( year >= 1979 )
          # filter( year >= 2000 )
       
       X = data_L1$year
       Y = data_L1$temp
       
       X2 = rollmean(data_L1$year, 5)
       Y2 = rollmean(data_L1$temp, 5)
       
       DO = 100000      # Number of repetition
       N  = length(X)   # Number of sample
       # N2 = length(X2)  # Number of sample
       
       Sort_X = lapply(1:DO, function(i) rollmean(X[1:N], 5) )  #  Sort_X = lapply(1:DO, function(i) X2[1:N2])
       Sort_Y = lapply(1:DO, function(i) rollmean(sample(Y, N, replace=F), 5))  # 비복원추출(무작위 정렬)
       Sort_R = mapply(cor, Sort_X, Sort_Y)
       
       Pval = sum (abs(Sort_R) >= abs(cor(X2, Y2))) /length(Sort_R)    
       # (Source: http://strata.uga.edu/8370/lecturenotes/resampling.html)
       
       ## 지점, 상관계수, 몬테카를로 시뮬레이션에 의한 유의성
       cat(i, cor(X, Y), Pval, "\n")
    }

     

    • 표본 평균 집단

     

    • 몬테카를로 시뮬레이션 (Monte Carlo Simulation)을 통한 표본 표준편차 집단

      • 샘플 개수, 표본 평균의 표준편차, 표본 표준편차의 평균/Sqrt(N), 표본 평균의 표준편차 - 표본 표준편차의 평균 / Sqrt(N)

     

     

     

    상관계수에 대한 유의성 검정
    • 1979-2016년 기간 동안 강릉 지역에 대한 상관계수

     

    • 몬테카를로 시뮬레이션 (Monte Carlo Simulation)을 통한 유의성 검정

      • 상관 계수 및 유의 확률 (P-value)는 각각 0.47 및 0.00321로서 통계적으로 0.3 % 수준으로 유의하다.

      • 99.7 % 수준으로 신뢰할 만하다. 또는 1000번 중에 약 3번은 우연의 일치이다. 또는 1000번 중에 997번은 우연의 일치가 아니다.

     

     

    • cor.test 근사식에 통한 유의성 검정

     

     

    [조화 분석]

    ## Example Data Sets 
    X = seq(1, 12)
    Y = c(-0.10, 0.40, 5.70, 13.30, 17.60, 20.60, 25.30, 25.10, 20.20, 15.80, 7.80, -0.10)
    
    nn = length(X)
    nh = trunc((nn-1)/2+1)
    
    AA = numeric(nn)
    BB = numeric(nn)
    AAcos = matrix(rep(NA, nn*nh), nrow=nn, ncol=nh)
    BBsin = matrix(rep(NA, nn*nh), nrow=nn, ncol=nh)
    YY = numeric(nn)
    YY2 = numeric(nn)
    SYk = numeric(nn)
    SSYk = numeric(nn)
    
    SYt = 0  ;  SSYt = 0  ;  SYh = 0  ;  SSYh = 0
    SYa = 0  ;  SSYa = 0  ;  SYk = 0  ;    PA = 0
    
    for (i in 1:nh) {
       for (j in 1:nn) { 
           AA[i] = AA[i] + (Y[j]*cos(2.0*pi*j*i/nn))
           BB[i] = BB[i] + (Y[j]*sin(2.0*pi*j*i/nn))
       }
       AA[i] = AA[i]*2/nn
       BB[i] = BB[i]*2/nn
    
       if(i==nh){
          if(nn%%2==0){
             AA[i] = AA[i]/2
             BB[i] = 0.0
    
          }else{
             AA[i]=0
             BB[i]=0
       }
       }
    }
    
    
    for (i in 1:nn) {
       for (j in 1:nh) {
          AAcos[i,j] = AA[j]*cos(2*pi*j*i/nn)
          BBsin[i,j] = BB[j]*sin(2*pi*j*i/nn)
          YY[i] = YY[i] + (AAcos[i,j] + BBsin[i,j])
          if (AA[j] > 0)  { TT = atan(BB[j]/AA[j]) }
          if (AA[j] < 0)  { TT = atan(BB[j]/AA[j]) + pi }
          if (AA[j] == 0) { TT = pi/2 }
          YY2[i] = YY2[i] + sqrt(AA[j]**2 + BB[j]**2)*cos(2*pi*i*j/nn-TT)
       }
       
       Mean = mean(Y)
       SYt = SYt + Y[i]
       SSYt = SSYt + Y[i]**2
       SYh = SYh + (YY[i] + Mean)
       SSYh = SSYh + (YY[i] - Mean)
       SYa = SYa + (YY2[i] + Mean)
       SSYa = SSYa + (YY2[i] - Mean)
       
       for (j in 1:nh) {
          SYk[j] = SYk[j] + AAcos[i,j]+BBsin[i,j]
          SSYk[j] = SSYk[j] + (AAcos[i,j]+BBsin[i,j])**2
       }
    }
    
    for (j in 1:nh) {
       PA[j] = atan(BB[j]/AA[j])*180/pi
       if (AA[j] < 0) { PA[j] = PA[j] + 180 }
       if (AA[j] == 0) { PA[j] = 90 }
       PA[j] = PA[j] - 360.0/nn*j
       if (PA[j] < 0) { PA[j] = PA[j] + 360 }
       if (AA[j] == 0  &  BB[j]==0) { PA[j] = -999.0 }
    }
    
    
    data = data.frame(Y, AAcos+BBsin, YY+Mean, YY2+Mean)
    colnames(data) = c("Yt", "Y01", "Y02", "Y03", "Y04", "Y05", "Y06", "Yh", "Ya")
    summary(data)
    
    round( data, 2)                                                                # Time, Yt, Y01, Y02, Y03, Y04, Y05, Y06 | Yh Ya
    round( apply(data, 2, mean), 2)                                                # Mean
    round( apply(data, 2, var), 2)                                                 # Var = (CK*CK)/2
    round( apply(data, 2, var)/var(data$Yt)*100, 2)                                # Contribution [%] = R-squared/100
    round( sqrt(AA[1:nh]^2+BB[1:nh]^2), 2)                                         # Amplitude (CK) 
    round( ((sqrt(AA[1:nh]^2+BB[1:nh]^2))^2*nn)/((nn-1)*var(data$Yt))/2, 2)        # R-squared
    round( PA[1:nh], 2)                                                            # Phase Anglea
    round( nn/(1:nh), 2)                                                           # Time of length
    round( 1+nn/360*PA[1:nh], 2)                                                   # Time of 1-6st Harm.
    
    
    data_L1     = round( data, 2)                                                                
    Mean        = round( apply(data, 2, mean), 2)                                                
    Var         = round( apply(data, 2, stats::var), 2)                                                 
    Contri      = round( apply(data, 2, stats::var)/var(data$Yt)*100, 2)                                
    CK          = round( sqrt(AA[1:nh]^2+BB[1:nh]^2), 2)                                     
    Rsq         = round( ((sqrt(AA[1:nh]^2+BB[1:nh]^2))^2*nn)/((nn-1)*var(data$Yt))/2, 2)    
    Phase_angle = round( PA[1:nh], 2)                                                        
    Time_length = round( nn/(1:nh), 2)                                                       
    Time_1st    = round( 1+nn/360*PA[1], 2)                                                  
    
    
    # FIG.
    cols = brewer.pal(6, 'Set2')   
    legend_text = paste(paste(c("1st", "2st", "3st", "4st", "5st", "6st"), Contri[2:7], sep=" = "), "%")
    dev.off()      # Initialization
    par(cex.main=1.2, cex.lab=1.2, cex.axis=1.2, cex=1.2, font=1)
    plot (X, data_L1[,1], xaxs="i", yavs="i", xlim=c(1, 12), ylim=c(-10, 30),
         xlab="X lab", ylab="Y lab")
    lines(X, data_L1[,2]+Mean[1], type='l', col=cols[1], lwd=2)
    lines(X, data_L1[,3]+Mean[1], type='l', col=cols[2], lwd=2)
    lines(X, data_L1[,4]+Mean[1], type='l', col=cols[3], lwd=2)
    lines(X, data_L1[,5]+Mean[1], type='l', col=cols[4], lwd=2)
    lines(X, data_L1[,6]+Mean[1], type='l', col=cols[5], lwd=2)
    lines(X, data_L1[,7]+Mean[1], type='l', col=cols[6], lwd=2)
    legend( "topleft",  legend=c("Yt"), pch=c(21), col=c('black'),
           cex=1.2,  pt.cex=1.3, text.font=1, bty="n", text.col=c('black'),  y.intersp = 0)
    legend( "topright", legend=legend_text, col=cols, text.col=cols,
           cex=1.2,  pt.cex=1.3, text.font=1, lwd=2, bty="n", xpd=T,  y.intersp = 0.3)
    
    ## Fig. 2
    plot(Time_length, Contri[2:7], xlim=c(1, 12.5), ylim=c(-5, 100.5), type="b", col="blue", 
         xlab="Time  length", ylab="Contribution  [%]")

     

    • 각 주기에 따른 시계열

     

    • 주기에 따른 기여도

     

    [주성분 분석]

    • 통계학 및 기상학/해양학에서는 각각 주성분 분석 (Principal Component Analysis) 및 경험적 직교함수 (Empirical Orthogonal Function)으로 의미함

    • 여러 개의 독립변수로 얻어진 다변량 데이터에 대해 공분산/상관계수 구조를 선형결합식(주성분)으로 설명하고자 함

    • 즉 차원 축소 및 주성분을 통한 데이터의 해석 용이

    • [연습] 1987년 1월 이타카, 캐넌다이과 지역에 일평균 최저 기온

    • [실습] 기상청 최고 기온 자료를 이용한 영동 및 영서에 대한 주성분 분석

    ## Example Data Sets 
    
    ## 시간: 1987년 1월 일평균 자료 (지상관측)
    ## 변수: 최저 기온
    ## 지점: 이타가, 캐넌다이과 
    
    Ithaca = c(19, 25, 22, -1, 4, 14, 21, 22, 23, 27, 29, 25, 29, 15, 29, 24, 0, 2, 26, 17, 19, 9, 20, -6, -13, -13, -11, -4, -4, 11, 23)
    Canandaigua = c(28, 28, 26, 19, 16, 24, 26, 24, 24, 29, 29, 27, 31, 26, 38, 23, 13, 14, 28, 19, 19, 17, 22, 2, 4, 5, 7, 8, 14, 14, 23)
    data = data.frame(Ithaca, Canandaigua)
    plot(Ithaca, Canandaigua, xlim=c(-10, 35), ylim=c(-10, 35))
    
    cov(data)
    
    summary(data)
    
    
    nrow = dim(data)[1]
    ncol = dim(data)[2]
    anomaly = matrix(rep(NA, nrow*ncol), nrow=nrow, ncol=ncol)
    for (i in 1:ncol) {
       anomaly[,i] = data[ ,i] - colMeans(data)[i]
    }
    colnames(anomaly) = c("anomaly_Ithaca", "anomaly_Canandaigua")
    
    #  Mean : 13.0   Mean : 20.23 
    # anomaly_Ithaca = data$Ithaca - mean(data$Ithaca)
    # anomaly_Canandaigua = data$Canandaigua - mean(data$Canandaigua)
    
    ################################## 상관계수 (Correlation Coefficient), 공분산 (Covariance) ###########################################################
    
    ################################## 공분산 (Covariance) ###############################################################################################
    EOF = prcomp(data, scale=FALSE, center=TRUE)        # 표준화 미고려, 아노말리 고려
    # EOF = prcomp(data, scale=FALSE, center=FALSE)     # 표준화 미고려, 아노말리 미고려
    Eigen_value = EOF$sdev^2  ;  Eigen_value            # 고유근
    Eigen_vector = EOF$rotation  ;  Eigen_vector        # 고유벡터
    EOF_data = data.frame(data, anomaly_Ithaca, anomaly_Canandaigua, EOF$x)  ;  EOF_data
       ## 이타카, 캐넌다이과의 최저기온과 아노말리 및 주성분 (PC1, PC2)
       ## PC1 = -0.8478591*anomaly(Ithaca) -0.5302216*anomaly(Canandaigua)
       ## PC2 = -0.5302216*anomaly(Ithaca) -0.8478591*anomaly(Canandaigua)
    
    
    summary(EOF)  # 각  주성분의 설명력 및 표준편차
    
    ## FIG. 스크리 그림 (Scree plot): 주성분에 따른 분산/설명력
    PC_var = (Eigen_value/sum(Eigen_value))*100.0
    par(cex.main=1.2, cex.lab=1.2, cex.axis=1.2, cex=1.2, font=1)
    plot(PC_var, xlim=c(1, 10), ylim=c(0, 100), type='b',
         xlab='Principal  Component', ylab='Proportion  of  Variance,  Cumulative  Proportion')
    points(cumsum(Eigen_value)/sum(Eigen_value)*100., col='blue', type='l')
    
    
    ## FIG. 행렬도 : 변수와 주성분(PC)의 관계를 그래프로 표현.
    #                화살표는 변수와 PC의 상관계수, PC와 평행수록 해당 PC에 큰 영향.
    #                화살표 벡터의 길이가 변수의 분산을 표현.
       par(cex.main=1.2, cex.lab=1.2, cex.axis=1.2, cex=1.2, font=1)
       biplot(EOF, choices=1:2, scale=0, xlab="PC1 (96.85% explained var)", ylab="PC2 (0.03% explained var)" ) ; abline(h=0, v=0, lty=2)
       cor(data)
       
    ## FIG. 변수와 주성분(PC)의 시계열
    cols = brewer.pal(4, 'Set2')  
    par(cex.main=1.2, cex.lab=1.2, cex.axis=1.2, cex=1.2, font=1)
    legend_text = c("PC1 (0.96%)", "PC2 (0.04%)", "Anomaly_Ithaca", "Anomaly_Canandaigua")
    plot (EOF_data$PC1, type='l', xaxs="i", yaxs="i", col=cols[1], ylim=c(-40, 40), ylab="Temperature [deg. C]", xlab="Date  [Day]", lwd=2)
    lines(EOF_data$PC2, type='l', col=cols[2], lwd=2)
    lines(EOF_data$anomaly_Ithaca, type='l', col=cols[3], lwd=2)
    lines(EOF_data$anomaly_Canandaigua, type='l', col=cols[4], lwd=2)
    legend( "topleft", legend=legend_text, col=cols, text.col=cols,
            cex=1.5,  pt.cex=1.3, text.font=1, lwd=2, bty="n", xpd=T,  y.intersp = 0.3)
    
          
    ################################## 상관계수 (Correlation Coefficient) ################################################################################
    EOF = prcomp(data, scale=TRUE, center=FALSE)  # 표준화 미고려, 아노말리 고려
    Eigen_value = EOF$sdev^2  ;  Eigen_value
    Eigen_vector = EOF$rotation  ;  Eigen_vector
    EOF_data = data.frame(data, EOF$x)  ;  EOF_data
    ## 이타카, 캐넌다이과의 최저기온과 주성분
    
    summary(EOF)
    
    # dev.off()
    
    ## FIG. 주성분에 따른 분산
    PC_var = (Eigen_value/sum(Eigen_value))*100.0
    par(cex.main=1.2, cex.lab=1.2, cex.axis=1.2, cex=1.2, font=1)
    plot(PC_var, xlim=c(1, 10), ylim=c(0, 100), type='b',
         xlab='Principal  Component', ylab='Proportion  of  Variance,  Cumulative  Proportion')
    points(cumsum(Eigen_value)/sum(Eigen_value)*100., col='blue', type='l')
    
    
    ## FIG. 행렬도 : 변수와 주성분(PC)의 관계를 그래프로 표현.
    #                   화살표는 변수와 PC의 상관계수, PC와 평행수록 해당 PC에 큰 영향.
    #                   화살표 벡터의 길이가 변수의 분산을 표현.
    par(cex.main=1.2, cex.lab=1.2, cex.axis=1.2, cex=1.2, font=1)
    biplot(EOF, choices=1:2, scale=0, xlab="PC1 (95.06% explained var)", ylab="PC2 (0.05% explained var)" ) ; abline(h=0, v=0, lty=2)
    
    ## FIG. 변수와 주성분(PC)의 시계열.
    cols = brewer.pal(4, 'Set2')  
    par(cex.main=1.2, cex.lab=1.2, cex.axis=1.2, cex=1.2, font=1)
    legend_text = c("PC1 (0.95%)", "PC2 (0.05%)")
    plot(EOF_data$PC1, type='l', xaxs="i", yaxs="i", col=cols[1], ylim=c(-3, 3), ylab="PC1, PC2", lwd=2)
    lines(EOF_data$PC2, type='l', col=cols[2], lwd=2)
    legend( "topleft", legend=legend_text, col=cols, text.col=cols,
            cex=1.5,  pt.cex=1.3, text.font=1, lwd=2, bty="n", xpd=T,  y.intersp = 0.3)
    
    
    
    
    ####################### 기상청 최저/최고 기온 자료를 이용하여 영동과 영서에 대한 주성분 분석 ###########################################
    data = read.csv("INPUT/KMA/2012-2016_Daily_Mean_Maximum_Air_Temperature_Gangwon.KMA", sep="", header=TRUE)
    data = read.csv("INPUT/KMA/2012-2016_Daily_Mean_Minimum_Air_Temperature_Gangwon.KMA", sep="", header=TRUE)
    head(data)  # 파일의 첫 행
    tail(data)  # 파일의 끝 행
    
    #################################### 자료 설명 ##############################################################
    ##
    ## 시간: 2012-2016년 일평균 자료 (지상관측)
    ##
    ## 변수: 년,    월,      일,    8개 지점별 최저/최고 기온
    ##       year  month    day   
    ##
    ## 지점: 춘천,  홍천,  원주,  영월,  동해,  강릉,  속초,  양양
    ##       ~~~~~~~~~~~~~~~~~~~~~~~~~   ~~~~~~~~~~~~~~~~~~~~~~~~~
    ##              영서 지역                              영동 지역
    ##
    ## 출처: 기상청 국가기후데이터센터 (http://sts.kma.go.kr/jsp/home/contents/main/main.do) 
    ##       Received data from master's course Se-Hun Rim
    ##
    ############################################################################################################
    
    ## 시계열 그리기 위해서 "년, 월, 일"에 대한 변수를 고려한 xran 변수 추가 그리고 4월달 자료만 추출.
    MONTH = c(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
    data_L1 = data %>% 
       mutate( xran = year + ((month-1)/12.) + ((day-1)/(12.*MONTH[month])) ) %>%
       filter( year == 2016 ) %>%
       filter( month == 4 )
    
    head(data_L1)
    
    data_L1_FIG = data_L1 %>%
       filter( year == 2012 )
    
    ## FIG. 영동 지역에서 최고/최저 기온 자료 시계열
    cols = brewer.pal(4, 'Set2')  
    # display.brewer.all(n=10, exact.n=FALSE)
    par(cex.main=1.2, cex.lab=1.2, cex.axis=1.2, cex=1.2, font=1)
    plot (data_L1_FIG$day, data_L1_FIG$Donghae, type='l', xaxs="i", yaxs="i", col=cols[1], ylim=c(-10, 40), ylab="Max / Min  Air  Temperature [deg. C]", xlab="Time  [Year-Month-Day]", lwd=2)
    lines(data_L1_FIG$day, data_L1_FIG$Gangneung, type='l', col=cols[2], lwd=2)
    lines(data_L1_FIG$day, data_L1_FIG$Sokcho, type='l', col=cols[3], lwd=2)
    lines(data_L1_FIG$day, data_L1_FIG$Yangyang, col=cols[4], lwd=2)
    legend( "top", legend=c("Donghae", "Gangneung", "Sokcho", "Yangyang"), 
            col=cols, text.col=cols, cex=1.3,  pt.cex=1.3, text.font=1, lwd=2, bty="n", xpd=T, horiz=TRUE,  y.intersp = 0.25)
    
    ## FIG. 영서 지역에서 최고/최저 기온 자료 시계열.
    par(cex.main=1.2, cex.lab=1.2, cex.axis=1.2, cex=1.2, font=1)
    plot (data_L1_FIG$day, data_L1_FIG$Chuncheon, type='l', xaxs="i", yaxs="i", col=cols[1], ylim=c(-10, 40), ylab="Max / Min  Air  Temperature [deg. C]", xlab="Time  [Year-Month-Day]", lwd=2)
    lines(data_L1_FIG$day, data_L1_FIG$Hongcheon, type='l', col=cols[2], lwd=2)
    lines(data_L1_FIG$day, data_L1_FIG$Wonju, type='l', col=cols[4], lwd=2)
    lines(data_L1_FIG$day, data_L1_FIG$Yeongwol, type='l', col=cols[4], lwd=2)
    legend( "top", legend=c("Chuncheon", "Hongcheon", "Wonju", "Yeongwol"), 
            col=cols, text.col=cols, cex=1.3,  pt.cex=1.3, text.font=1, lwd=2, bty="n", xpd=T, horiz=TRUE,  y.intersp = 0.25)
    
    
    ## 시간(년, 월, 일) 및 NA 제거
    data_L2 = na.omit(data_L1)
    head(data_L2)
    
    ## year, month, day, xran 컬럼 제거
    data_L3 = data_L2[ ,-c(1:3, 12)]
    head(data_L3)
    
    ## 공분산 행렬
    COV = cov(data_L3)  ;  COV  ## 공분산 행렬
    ggcorrplot(COV, outline.col = "white", lab = TRUE) +
       scale_fill_gradientn(colours = matlab.like(10)) +
       labs(fill = "Cov") 
    
    
    ## 상관계수 행렬
    COR = cor(data_L3)  ;  COV          ## 상관계수 행렬 계산
    COR_pvalue = cor_pmat(data_L3)      ## 상관계수 행렬에 대한 p-value 계산
    ggcorrplot(COR, outline.col = "white", lab = TRUE, p.mat = COR_pvalue, sig.level = 0.05, 
               colors = c("#6D9EC1", "white", "#E46726")) 
    
    
    ## Anomaly calculation
    nrow = dim(data_L3)[1]
    ncol = dim(data_L3)[2]
    anomaly = matrix(rep(NA, nrow*ncol), nrow=nrow, ncol=ncol)
    for (i in 1:ncol) {
       anomaly[,i] = data_L3[ ,i] - colMeans(data_L3)[i]
    }     
    colnames(anomaly) = c("anomaly_chuncheon", "anomaly_hongcheon", "anomaly_wonju" , "anomaly_yeongwol",
                          "anomaly_donghae"  , "anomaly_gangneung", "anomaly_sokcho", "anomaly_yangyang")
    
    
    
    
    ## 주성분 분석
    EOF = prcomp(data_L3, scale=FALSE, center=TRUE)  ;  EOF
       ## scale = FALSE , center = FALSE : 공분산 행렬   (아노말리 미고려)
       ## scale = FALSE , center = TRUR  : 공분산 행렬   (아노말리 고려)
       ## scale = TRUE  , center = FALSE : 상관계수 행렬 (아노말리 미고려)
       ## scale = TRUE  , center = TRUE  : 상관계수 행렬 (아노말리 고려)
    names(EOF)
    Eigen_value = EOF$sdev^2      ;  Eigen_value         # 고유근
    Eigen_vector = EOF$rotation   ;  Eigen_vector        # 고유벡터
    EOF_data = data.frame(EOF$x)  ;  EOF_data            # Principal Components
    summary(EOF)
    
    
    ## Eigen_value Test
    sum(diag(COV))        # 공분산의 대각선 합
    sum(Eigen_value)      # 고유근의 합
    
    ## PC1 (Eigen_vector) Test (PC scores using R-project  vs  PC scores using calculator)
    EOF_data[1,1]
    ## PC1[1,1] = 0.3316495*anomaly(Chuncheon) + ... +  0.3798507*anomaly(Yangyang)
    # sum(-16.90909589*0.3448694, -17.093260274*0.3505063, -16.24663014*0.3380886, -16.991287671*0.3409752, -16.44942466*0.3352016,
        # -1.219956e+01*0.2659710, -13.33632877*0.2883571, -11.74356164*0.2815221, -15.407342466*0.3211499, -13.13715068*0.2810695)
    
    ## FIG. 주성분에 따른 설명력
    PC_var = (Eigen_value/sum(Eigen_value))*100.0
    fviz_screeplot(EOF, addlabels = TRUE, title="", x="Principal  Components", y="Percentage  of  Variance  [%]", ncp = 8) + 
       geom_point(aes(y=cumsum(PC_var)), col='red') + geom_line(aes(y=cumsum(PC_var)), col='red') +
       theme_bw(base_size = 15)
    
    ## FIG. 고유벡터를 이용하여 2D contour mapping 
    
    ## 위도 및 경도 설정
    ## 춘천,  홍천,  원주,  영월,  동해,  강릉,  속초,  양양
    lat = c( 37.90256000,  37.68358000,  37.33756000,  37.18126000,  37.50708000,  37.75147000,  38.25085000,  38.08724000)
    lon = c(127.73570000, 127.88040000, 127.94660000, 128.45743000, 129.12433000, 128.89098000, 128.56472000, 128.62966000)
    obs = c( "Chuncheon",  "Hongcheon",    "Wonju",   "Yeongwol",    "Donghae",  "Gangneung",     "Sokcho",    "Yangyang")
    
    data_L4 = data.frame( obs, lon, lat, unname(Eigen_vector) )
    colnames(data_L4) = c("obs", "lon", "lat", "PC1", "PC2", "PC3", "PC4", "PC5", "PC6", "PC7", "PC8")
    
    data_L5 = data_L4
    head(data_L5)
    
    coordinates(data_L5)  = ~lon + lat
    plot(data_L5)
    
    # summary(data_L5)
    
    ################################# 통계적 보간법 ##############################################################################
    ##
    ## 10개 지점별 고유벡터를 시각화하기 위해 공간분포의 통계적 보간법 (선형 내삽, 2차원 내삽, 역거리 가중치법, 크리킹 등) 이용
    ##
    ## 역거리 가중치법 (Inverse Distance Weighting, IDW)
    ## - 거리에 따른 주변값들의 가중값을 산정하여 가중평균을 통해 지점별 관측의 값을 보간하는 방법 (Kim et al., 2010)
    ## - 즉 IDW 보간법은 대표적인 공간분포 보간법으로 관측점간의 거리에 반비례하여 가중치를 할당하고, 
    ##   거리가 멀어짐에 따라 지수적으로 감소한다. 
    ##  
    ## Kim D, Ryu D, Choi Y, Lee W. 2010. Application of kriging and inverse distance weighting method for 
    ##        the estimation of geo-layer of Songdo area in Incheon. Journal of Korean Geotechnical Society 26(1):5-19.
    ##
    ##############################################################################################################################
    
    ## 1 km 해상도로 주변 격자를 구성
    y.range = as.numeric(c(35, 40))    # min/max latitude  of the interpolation area
    x.range = as.numeric(c(127, 130))  # min/max longitude of the interpolation area
    
    grd = expand.grid(x = seq(from = x.range[1], to = x.range[2], by = 0.01),
                      y = seq(from = y.range[1], to = y.range[2], by = 0.01))  # expand points to grid
    coordinates(grd) <- ~ x + y
    gridded(grd) <- TRUE
    
    # plot(grd, cex = 1.0, col = "grey")
    # points(data_L5, pch = 1, col = "red", cex = 1)
    
    idw = idw(formula = PC2 ~ 1, locations = data_L5, newdata = grd)  # apply idw model for the data
    idw.output = as.data.frame(idw)  # output is defined as a data table
    names(idw.output)[1:3] = c("long", "lat", "var1.pred")  # give names to the modelled variables
    
    world = map_data("worldHires")
    
    longitude = seq(100, 150, 0.5)
    latitude  = seq(20, 60, 0.5)
    x_longitude = unlist(lapply(longitude, function(x) ifelse(x < 0, paste0(abs(x), "°W"), ifelse(x > 0, paste0(x, "°E"),x))))
    y_latitude  = unlist(lapply(latitude, function(x) ifelse(x < 0, paste0(x, "°S"), ifelse(x > 0, paste0(x, "°N"),x))))
    
    ggplot() + 
       coord_fixed(ratio = 0.75) +
       theme_bw() +
       geom_tile(data = idw.output, aes(x = long, y = lat, fill = var1.pred)) + 
       scale_fill_gradient2() +
       # scale_fill_gradientn(colours = matlab.like(10), limits=c(-1.0, 1.0)) +
       guides( fill=guide_colorbar(barwidth=1.5, barheight=15, title.position="right", title.vjust = 0.5, title.hjust = 0.5) ) +
       geom_point(aes(x = lon, y = lat, colour=obs), data = data_L4, size=5, alpha=0.3, show.legend = FALSE) +
       geom_text(aes(x=lon, y=lat, label=obs, colour=obs), hjust=-0.25, vjust=0.5, nudge_x=0, nudge_y=0, size=5,
                 colour='black', data=data_L4) +
       # geom_label(aes(x=lon, y=lat, label=obs, colour=obs), hjust=-0.25, vjust=0.5, nudge_x=0, nudge_y=0, size=5,
       # data=data_L4, show.legend = FALSE) +
       geom_path(aes(x=long, y=lat, group=group), data = world, colour="black") +
       # scale_x_continuous(breaks = longitude, labels = x_longitude, expand=c(0,0), limits=c(125, 130)) +
       # scale_y_continuous(breaks = latitude,  labels = y_latitude,  expand=c(0,0), limits=c(32.5, 40)) +
       scale_x_continuous(breaks = longitude, labels = x_longitude, expand=c(0,0), limits=c(127, 130)) +
       scale_y_continuous(breaks = latitude,  labels = y_latitude,  expand=c(0,0), limits=c(36, 39)) +
       theme(plot.title=element_text(face="bold", size=20, color="black")) +
       theme(axis.title.x = element_text(face="bold", size=15, colour="black")) +
       theme(axis.title.y = element_text(face="bold", size=15, colour="black", angle=90)) +
       theme(axis.text.x  = element_text(face="bold", size=15, colour="black")) +
       theme(axis.text.y  = element_text(face="bold", size=15, colour="black")) +
       theme(legend.text=element_text(size=14, color="black")) +
       theme(legend.title=element_text(size=14, angle=90)) +
       labs(x = "") +
       labs(y = "") +
       labs(fill = "Eigen  Vector") +
       labs(colour = "") +
       labs(title  = paste0("PC2 (", sprintf("%.2f", PC_var)[2], "%  Explanined  Variance) \n")) +
       theme(legend.background=element_blank())
    
    
    ## FIG. 각 지점에서 각 주성분들의 기여도
    var = get_pca_var(EOF)
    contrib = var$contrib
    ggcorrplot(contrib, outline.col = "white", lab = TRUE) + 
       scale_fill_gradientn(colours = matlab.like(10)) +
       labs(fill = "Contrib") 
    
    rowSums(contrib)  # 행에 대한 합계
    colSums(contrib)  # 열에 대한 합계
    
    
    ## FIG. 각 지점별 주성분들의 기여도
    fviz_contrib(EOF, choice = "var", axes = 2)
    
    ## FIG. 각 사례별 주성분들의 기여도 == 고유벡터의 절대값이 큰 경우
    fviz_contrib(EOF, choice = "ind", axes = 2) + coord_flip()
    
    ## PC 1-2에 대해 고유벡터를 시각화
    fviz_pca_var( EOF, axes=c(2,2), col.var="contrib", gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07") ) 
    
    ## PC 1-2에 대해 주성분들를 시각화
    fviz_pca_ind(EOF, axes=c(2,2), col.ind = "contrib", gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"), repel = TRUE)
    
    ## PC 1-2에 대해 고유벡터 및 주성분 Score를 시각화
    fviz_pca_biplot(EOF, axes = c(2, 2), col.var="contrib", col.ind ="contrib", gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07")) +
       theme_bw(base_size = 15)
    
    
    ## 년, 월, 일, 관측소별 최고/최저 기온 및 아노말리, 주성분 score
    data_L6 = data.frame(data_L2$year, data_L2$month, data_L2$day, data_L3, anomaly, EOF_data)
    head(data_L6)
    
    summary(EOF)
    
    data_L6_FIG = data_L6 %>%
       dplyr::rename( year  = data_L2.year, 
                      month = data_L2.month, 
                      day   = data_L2.day ) %>%
       dplyr::filter( year == 2016 )
    
    ## FIG. 변수와 주성분(PC 1-5)의 시계열.
    cols = brewer.pal(5, 'Set2')  
    par(cex.main=1.2, cex.lab=1.2, cex.axis=1.2, cex=1.2, font=1)
    plot  (data_L6_FIG$day, data_L6_FIG$PC1, type='l', xaxs="i", yaxs="i", col=cols[1], ylim=c(-80, 80), ylab="Principal  Component  Scores", xlab="Time  [Year-Month-Day]", lwd=2)
    points(data_L6_FIG$day, data_L6_FIG$PC2, type='l', col=cols[2], lwd=2)
    points(data_L6_FIG$day, data_L6_FIG$PC3, type='l', col=cols[3], lwd=2)
    points(data_L6_FIG$day, data_L6_FIG$PC4, type='l', col=cols[4], lwd=2)
    points(data_L6_FIG$day, data_L6_FIG$PC5, type='l', col=cols[5], lwd=2)
    legend_text = c("PC1 (80.94%)", "PC2 (15.62%)", "PC3 (1.47%)", "PC4 (0.70%)", "PC5 (0.55%)")
    legend("top", legend=legend_text, col=cols, text.col=cols,
    cex=1.2,  pt.cex=1.3, text.font=1, lwd=2, bty="n", xpd=T,  y.intersp = 0.25, horiz=TRUE)
    
    
    ############################# 영동 및 영서 지점들에 대한 바람장미 ##############################################
    ## - 영동과 영서 지역에 온도 차가 클 때 (PC2 절대값 최대) 바람장미의 분포를 보고자 함.
    ## - 2016년 4월 9, 17일 (영동 - 영서) > 0 (푄 현상으로 인해 기온 상승)          ->  서풍 계열 예상
    ## - 2016년 4월    26일               < 0 (시베리안 고기압으로 인해 기온 하강)  ->  북풍 또는 동풍 계열 예상
    ################################################################################################################
    
    wind_data = read.csv("INPUT/KMA/201604_Hourly_Mean_Wind_Gangwon.KMA", sep="", header=TRUE)
    head(wind_data)  # 파일의 첫 행
    
    #################################### 자료 설명 ##############################################################
    ##
    ## 시간: 2016년 4월 시간별 평균된 자료 (지상관측)
    ##
    ## 변수: 년,    월,      일,    7개 지점별 풍향 및 풍속 자료
    ##       year  month    day                *_wd    *_ws
    ##
    ## 지점: 춘천,  홍천,  원주,  영월,  동해,  강릉,  속초
    ##       ~~~~~~~~~~~~~~~~~~~~~~~~~   ~~~~~~~~~~~~~~~~~~
    ##              영서 지역                영동 지역
    ##
    ## 출처: 기상청 국가기후데이터센터 (http://sts.kma.go.kr/jsp/home/contents/main/main.do) 
    ##
    ############################################################################################################
    
    wind_data_L1 = na.omit(wind_data)  # NA 제거
    
    wind_data_L2 = wind_data_L1 %>%
       filter( year  == 2016 ) %>%
       filter( month == 4 ) %>%
       filter( day   == 26 )
    
    summary(wind_data_L2)
    
    ## 영동 지역에 대한 바람장미
    FIG_Gangneung_wr = ggplot_windrose(spd = wind_data_L2$Gangneung_ws, dir = wind_data_L2$Gangneung_wd, spdres = 2, dirres=30, spdmin = 0, spdmax = 12) +
       labs(title = "Gangneung")
    FIG_Donghae_wr = ggplot_windrose(spd = wind_data_L2$Donghae_ws, dir = wind_data_L2$Donghae_wd, spdres = 2, dirres=30, spdmin = 0, spdmax = 12) +
       labs(title = "Donghae")
    FIG_Sokcho_wr = ggplot_windrose(spd = wind_data_L2$Sokcho_ws, dir = wind_data_L2$Sokcho_wd, spdres = 2, dirres=30, spdmin = 0, spdmax = 12) +
       labs(title = "Sokcho")
    grid.arrange(FIG_Gangneung_wr, FIG_Donghae_wr, FIG_Sokcho_wr, nrow=1, ncol=3)   ## 다중 그림
    
    
    ## 영서 지역에 대한 바람장미
    FIG_Chuncheon_wr = ggplot_windrose(spd = wind_data_L2$Chuncheon_ws, dir = wind_data_L2$Chuncheon_wd, spdres = 2, dirres=30, spdmin = 0, spdmax = 12) +
       labs(title = "Chuncheon")
    FIG_Wonju_wr = ggplot_windrose(spd = wind_data_L2$Wonju_ws, dir = wind_data_L2$Wonju_wd, spdres = 2, dirres=30, spdmin = 0, spdmax = 12) +
       labs(title = "Wonju")
    FIG_Yeongwol_wr = ggplot_windrose(spd = wind_data_L2$Yeongwol_ws, dir = wind_data_L2$Yeongwol_wd, spdres = 2, dirres=30, spdmin = 0, spdmax = 12) +
       labs(title = "Yeongwol")
    grid.arrange(FIG_Chuncheon_wr, FIG_Wonju_wr, FIG_Yeongwol_wr, nrow=1, ncol=3)   ## 다중 그림
    
    
    #################################### ECMWF 자료를 이용하여 주성분 분석 및 그래픽 표출 ###########################################
     
    #################################### 자료 설명 ##############################################################
    ##
    ## 시간: 2016년 4월 1-30일 일평균 자료 (ECMWF ERA-Interim)
    ##
    ## 변수: 위도 (181),    경도 (360),      시간 (30),    지표면 기압 (360, 181, 30)   ------ 1 deg
    ##        longitude      latitude          time              Surface pressure
    ##
    ##       위도 (1441),   경도 (2880),     시간 (30),    지표면 기압 (2880, 1441, 30) ------ 0.125 deg
    ##        longitude      latitude          time              Surface pressure
    ##
    ## 출처: ECMWF era-interim (https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era-interim) 
    ##       Received data from master's course Wenting Zhang
    ##
    #############################################################################################################
    
    ncfile = open.nc("INPUT/ECMWF_mslp_1deg_201604.nc")
    print.nc(ncfile)
    
    ncdata = read.nc(ncfile)
    
    file_lines = dim.inq.nc(ncfile, "time")$length
    time_units = att.get.nc(ncfile, "time", "units")
    time = utcal.nc(time_units, ncdata$time)
    
    # slp_scale     =  att.get.nc(ncfile, "sp", "scale_factor")
    # slp_offset    =  att.get.nc(ncfile, "sp", "add_offset")
    # slp_fillvalue =  att.get.nc(ncfile, "sp", "_FillValue")
       
    lon  = ncdata[["longitude"]]
    lat  = ncdata[["latitude"]]
    # slp  = ncdata[["sp"]]/100.0  # (ncdata[["sp"]]*slp_scale) + slp_offset
                                   # Pa -> hPa
    msl  = ncdata[["msl"]]/100.0   # (ncdata[["sp"]]*slp_scale) + slp_offset
                                   # Pa -> hPa
    
    ## Convert 2D matrix to 1D matrix
    msl_matrix = matrix(msl, nrow = dim(lon)*dim(lat), ncol = file_lines)
    head(msl_matrix)
    
    ##================================== slp_matxix ======================================================
    ##       1일      2일     ...     29일       30일     (2017년 4월)   => slp_matrix[1:65160, 30]
    ##    360*181                               360*181
    ##    (65,160)                              (65,160)   
    ##====================================================================================================
    
    
    ## FIG. ECMWF 자료를 이용한 지표면 기압 맵핑 (-90°N-90°N, 0°E-360°E)
    lonlat = as.matrix(expand.grid(lon,lat))
    colnames(lonlat) = c("long", "lat")
    
    longitude   = seq(-180, 180, 20)
    latitude    = seq(-90, 90, 10)
    x_longitude = unlist(lapply(longitude, function(x) ifelse(x < 0, paste0(abs(x), "°W"), ifelse(x > 0, paste0(x, "°E"),x))))
    y_latitude  = unlist(lapply(latitude, function(x) ifelse(x < 0, paste0(x, "°S"), ifelse(x > 0, paste0(x, "°N"),x))))
    
    output = data.frame(lonlat, slp_matrix)
    
    ## Convert longitude (0-360) to (-180 to 180 or 180°W-180°E)
    output$long = ( (output$long+180) %% 360 ) - 180.0
    
    ## Convert longitude (-180 to 180 or 180°W-180°E) to (0-360)
    # output$long = ( output$long %% 360 )
    
    world = map_data("worldHires")
    
    ggplot() + 
       coord_fixed(ratio = 0.75) +
       theme_bw() +
       geom_tile(data = output, aes(x = long, y = lat, fill = X1)) +
       scale_fill_gradientn(colours = matlab.like(10)) +
       # scale_fill_gradientn(colours = matlab.like(10), limits=c(500, 1100), na.value="#AA0000", title.vjust = 0.5, title.hjust = 0.5) +
       guides( fill=guide_colorbar(barwidth=1.5, barheight=15, title.position = "right", title.vjust = 0.5, title.hjust = 0.5) ) +
       geom_path(aes(x=long, y=lat, group=group), data = world, colour="black") +
       # scale_x_continuous(breaks = longitude, labels = x_longitude, expand=c(0,0), limits=c(-180, 180)) +
       # scale_y_continuous(breaks = latitude,  labels = y_latitude,  expand=c(0,0), limits=c(-90, 90)) +
       scale_x_continuous(breaks = longitude, labels = x_longitude, expand=c(0,0), limits=c(80, 160)) +
       scale_y_continuous(breaks = latitude,  labels = y_latitude,  expand=c(0,0), limits=c(10, 70)) +
       theme(plot.title=element_text(face="bold", size=20, color="black")) +
       theme(axis.title.x = element_text(face="bold", size=15, colour="black")) +
       theme(axis.title.y = element_text(face="bold", size=15, colour="black", angle=90)) +
       theme(axis.text.x  = element_text(face="bold", size=15, colour="black")) +
       theme(axis.text.y  = element_text(face="bold", size=15, colour="black")) +
       theme(legend.text=element_text(size=14, color="black")) +
       theme(legend.title=element_text(size=14, angle=90)) +
       labs(x = "") +
       labs(y = "") +
       labs(fill = "Mean  Sea  Level  Pressure  [hPa]") +
       theme(legend.background=element_blank())
    
    
    
    ## 동아시아 영역에 대한 주성분 분석 (20°N-60°N, 115°E-150°E)
    output_L1 = output %>%
       dplyr::filter(115 <= long  &  long <= 150) %>%
       dplyr::filter(20  <= lat   &  lat <= 60)
    
    head(output_L1)
    
    ## 위도, 경도 추출 
    mls_matxix_L1 = output_L1[ ,-c(1,2)]
    
    head(mls_matxix_L1)
    
    
    ## 전치행렬로 변환
    ##================================== slp_matxix_L1 ===================================================
    ##       1일      2일     ...     29일       30일     (2017년 4월)   => slp_matrix_L1[1:4941, 30]
    ##     81*61                                81*61
    ##     (4941)            ..                 (4941)   
    ##====================================================================================================
    
    ##                                  ↓ transpose of a matrix
     
    ##==================================  t(slp_matxix_L1)================================================
    ##      1일           81*61 (4941)                                   => t(slp_matrix_L1[1:4941, 30])
    ##      2일                                                          => [30, 1:4941]
    ##      .                 .
    ##      .                 .
    ##      .                 .
    ##     29일 
    ##     30일          81*61 (4941)
    ##  (2017년 4월)
    ##====================================================================================================
    
    EOF = prcomp(t(mls_matxix_L1), scale=F, center=T)
    Eigen_value  = EOF$sdev^2          # 고유근
    Eigen_vector = EOF$rotation        # 고유벡터
    EOF_data = data.frame(EOF$x)  
    summary(EOF)
    
    ## Anomaly calculation
    nrow = dim(mls_matxix_L1)[1]
    ncol = dim(mls_matxix_L1)[2]
    anomaly = matrix(rep(NA, nrow*ncol), nrow=nrow, ncol=ncol)
    for (i in 1:ncol) {
       anomaly[,i] = mls_matxix_L1[ ,i] - colMeans(mls_matxix_L1)[i]
    }
    
    
    
    ## FIG. 주성분에 따른 설명력
    PC_var = (Eigen_value/sum(Eigen_value))*100.0
    fviz_screeplot(EOF, addlabels = TRUE, title="", x="Principal  Components", y="Percentage  of  Variance  [%]", ncp = 30) + 
       geom_point(aes(y=cumsum(PC_var)), col='red') + geom_line(aes(y=cumsum(PC_var)), col='red') +
       theme_bw(base_size = 15)
    
    
    ## FIG. 주성분의 고유벡터를 이용하여 맵핑
    long = output_L1$long
    lat  = output_L1$lat
    output_L3 = data.frame(long, lat, Eigen_vector)
    head(output_L3)
    
    # world = map_data("worldHires")
    world = map_data("world")
    
    longitude <- seq(80, 160, 5)
    latitude <- seq(10, 70, 5)
    x_longitude <- unlist(lapply(longitude, function(x) ifelse(x < 0, paste0(abs(x), "°W"), ifelse(x > 0, paste0(x, "°E"),x))))
    y_latitude <- unlist(lapply(latitude, function(x) ifelse(x < 0, paste0(x, "°S"), ifelse(x > 0, paste0(x, "°N"),x))))
    
    # summary(output_L3)
    
    ggplot() + 
       coord_fixed(ratio = 0.75) +
       theme_bw() +
       geom_tile(data = output_L3, aes(x = long, y = lat, fill = -PC1)) + 
       # scale_fill_gradient2(limits=c(-0.1, 0.1)) +
       scale_fill_gradient2(low = 'blue', mid = 'white', high = 'red') +
       guides( fill=guide_colorbar(barwidth=1.5, barheight=15, title.position = "right", title.vjust = 0.5, title.hjust = 0.5) ) +
       geom_path(aes(x=long, y=lat, group=group), data = world, colour="black") +
       scale_x_continuous(breaks = longitude, labels = x_longitude, expand=c(0,0), limits=c(115, 150)) +
       scale_y_continuous(breaks = latitude,  labels = y_latitude,  expand=c(0,0), limits=c(20, 60)) +
       theme(plot.title=element_text(face="bold", size=20, color="black")) +
       theme(axis.title.x = element_text(face="bold", size=15, colour="black")) +
       theme(axis.title.y = element_text(face="bold", size=15, colour="black", angle=90)) +
       theme(axis.text.x  = element_text(face="bold", size=15, colour="black")) +
       theme(axis.text.y  = element_text(face="bold", size=15, colour="black")) +
       theme(legend.text=element_text(size=14, color="black")) +
       theme(legend.title=element_text(size=14, angle=90)) +
       labs(x = "") +
       labs(y = "") +
       labs(fill = "Eigen  Vector \n") +
       labs(title  = paste0("PC1 (", sprintf("%.2f", PC_var)[1], "%  Explanined  Variance) \n" )) +
       theme(legend.background=element_blank()) +
       ggsave(filename=paste0('FIG/PC2.png'), width=12, height=6, dpi=600)
    
    
    
    ## FIG. 각 지점별 주성분들의 기여도
    # fviz_contrib(EOF, choice = "var", axes = 3)
    
    ## FIG. 각 사례별 주성분들의 기여도 == 고유벡터의 절대값이 큰 경우
    fviz_contrib(EOF, choice = "ind", axes = 3) + coord_flip()
    
    ## PC 1-2에 대해 고유벡터를 시각화
    # fviz_pca_var( EOF, axes=c(2,2), col.var="contrib", gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07") ) 
    
    ## PC 1-2에 대해 주성분들를 시각화
    fviz_pca_ind(EOF, axes=c(2,2), col.ind = "contrib", gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"), repel = TRUE)
    
    ## PC 1-2에 대해 고유벡터 및 주성분 Score를 시각화
    # fviz_pca_biplot(EOF, axes = c(2, 2), col.var="contrib", col.ind ="contrib", gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07")) +
       # theme_bw(base_size = 15)
    
    
    
    ## FIG. 변수와 주성분(PC)의 시계열.
    output_L4 = data.frame(time, EOF_data)
    head(output_L4)
    
    summary(output_L4)
    
    summary(EOF)
    
    cols = brewer.pal(5, 'Set2')  
    par(cex.main=1.2, cex.lab=1.2, cex.axis=1.2, cex=1.2, font=1)
    plot  (output_L4$day, output_L4$PC1, type='l', xaxs="i", yaxs="i", col=cols[1], xlim=c(1, 30), ylim=c(-600, 600), ylab="Principal  Component  Scores", xlab="Time  [Day]", lwd=2)
    points(output_L4$day, output_L4$PC2, type='l', col=cols[2], lwd=2)
    points(output_L4$day, output_L4$PC3, type='l', col=cols[3], lwd=2)
    points(output_L4$day, output_L4$PC4, type='l', col=cols[4], lwd=2)
    points(output_L4$day, output_L4$PC5, type='l', col=cols[5], lwd=2)
    ## ECMWF_slp_1deg_201704
    legend_text = c("PC1 (34.04%)", "PC2 (16.21%)", "PC3 (11.79%)", "PC4 (8.61%)", "PC5 (6.26%)")
    ## ECMWF_slp_0.125deg_201704
    # legend_text = c("PC1 (34.52%)", "PC2 (15.82%)", "PC3 (11.67%)", "PC4 (8.61%)", "PC5 (6.28%)")
    legend( "top", legend=legend_text, col=cols, text.col=cols,
            cex=1.0,  pt.cex=1.3, text.font=1, lwd=2, bty="n", xpd=T,  y.intersp = 0.25, horiz=TRUE)
    
    
    ########################### 영동 및 영서 지점의 기온과 주성분(PC)의 상관 분석 ###################################################
    ## - 2016년 4월 1-30 일 영동 지역 (기온 하강 ~ 북풍 또는 동풍 계열)  <-  PC3의 고유벡터가 동해상에 고기압 위치
    ##                                                                   <-  영동 지역의 기온과 PC3의 주성분과의 높은 상관성 예상
    ##
    ##                      영서 지역 (기온 상수 ~ 서풍 계열)            <-  PC4의 고유벡터가 동해상에 저기압 위치
    ##                                                                   <-  영서 지역의 기온과 PC4의 주성분과의 높은 상관성 예상
    #################################################################################################################################
    Maxtemp = data_L1 %>%
       filter( year == 2016 ) 
    
    output_L5 = data.frame(Maxtemp, EOF_data)
    output_L6 = output_L5 %>%
       dplyr::select ( Chuncheon, Hongcheon, Wonju, Yeongwol, Donghae, Gangneung, Sokcho, Yangyang, 
                       PC1, PC2, PC3, PC4, PC5, PC6)
    
    ## FIG. 상관계수 행렬
    COR = cor(output_L6)                  ## 상관계수 행렬 계산
    COR_pvalue = cor_pmat(output_L6)      ## 상관계수 행렬에 대한 p-value 계산
    ggcorrplot(COR, outline.col = "white", lab = TRUE, p.mat = COR_pvalue, sig.level = 0.05, 
               colors = c("#6D9EC1", "white", "#E46726")) 
    ggcorrplot(COR, outline.col = "white", lab = TRUE,  
               colors = c("#6D9EC1", "white", "#E46726")) 
    
    ## FIG. 산점도 행렬 
    ggpairs(output_L6)
    
    ## 기여도가 높은 날짜에 대해서 선정
    output_L7 = output_L6 %>%
       slice( c(3, 4, 5, 6, 7, 11, 13, 17, 21, 22) )
    
    ## FIG. 상관계수 행렬
    COR = cor(output_L7)                  ## 상관계수 행렬 계산
    COR_pvalue = cor_pmat(output_L7)      ## 상관계수 행렬에 대한 p-value 계산
    ggcorrplot(COR, outline.col = "white", lab = TRUE, p.mat = COR_pvalue, sig.level = 0.1, 
               colors = c("#6D9EC1", "white", "#E46726")) 
    ggcorrplot(COR, outline.col = "white", lab = TRUE,  
               colors = c("#6D9EC1", "white", "#E46726")) 
    
    ## FIG. 산점도 행렬 
    ggpairs(output_L7)
    
    
    
    
    ############################# 연구 영역에 따른 PC3 and PC4 설명력 ###############################
    summary(EOF)
    
    LAT_MIN = seq(0, 60, 5)
    LON_MIN = seq(100, 180, 5)
    
    LAT_MAX = seq(5, 60, 5)
    LON_MAX = seq(105, 180, 5)
    
    for (i in 1:length(LAT_MIN)) {
    for (j in 1:length(LON_MIN)) {
    for (k in 1:length(LAT_MAX)) {
    for (l in 1:length(LON_MAX)) {
    
       output_L1 = output %>%
          dplyr::filter(LAT_MIN[i] <= lat   &  lat  <= LAT_MAX[k]) %>%
          dplyr::filter(LON_MIN[j] <= long  &  long <= LON_MAX[l])
       
       if (dim(output_L1)[1] > 0) {
          slp_matxix_L1 = output_L1[ ,-c(1,2)]
          EOF = prcomp(t(slp_matxix_L1), scale=F, center=T)
          Eigen_value  = EOF$sdev^2          # 고유근
          PC_var = (Eigen_value/sum(Eigen_value))*100.0
    
          # cat(LAT_MIN[i], LAT_MAX[k], LON_MIN[j], LON_MAX[l], PC_var[3:4], sum( PC_var[3:4]), "\n",
              # file = "OUTPUT/PC3 or PC4 variance according to research area.OUT", append=T)
       }
    }
    }
    }
    }
    
    output_L8 = read.csv("OUTPUT/PC3 or PC4 variance according to research area.OUT", sep="", header=F)
    colnames(output_L8) = c("lat_min", "lat_max", "lon_min", "lon_max", "PC3", "PC4", "PC34_sum")
    head(output_L8)  # 파일의 첫 행
    
    
    output_L8 %>% 
       dplyr::arrange( desc(PC34_sum) )  # 내림차순 정렬

     

    기상청 최고 기온 자료를 이용한 영동 및 영서에 대한 주성분 분석
    • 2012-2016년 일평균 최고 기온 자료를 이용한 공분산 행렬

     

    • 주성분에 따른 설명력

     

    • 2번째 주성분에 대한 고유벡터 가시화

     

    • 2016년 04월 17일 영동 및 영서 지역에 바람장미 분포

     

    • 2016년 04월 26일 영동 및 영서 지역에 바람장미 분포

     

    • 영동과 영서에 대한 기온 및 바람과 연관성

      • 2번째 고유 벡터 (PC2) > 0

        • 영동 > 영서 (푄 현상으로 인해 기온 상승) > 서풍 계열

      • 2번째 고유벡터 (PC2) < 0

        • 영동 < 영서 (시베리안 고기압으로 인해 기온 하강) > 북풍 또는 동풍 계열

     

    [기계 학습]

    • 인공신경망 (Neural Networks)

      • hidden = 1 : 은닉 노드 수 c(100,100) 

      • threshold : 편미분에 대한 종료기준 임계값 (기본값 0.01) 

      • rep : 훈련 과정 반복 수 (기본값 1) 

      • linear.output = FALSE : 출력 구간 [0, 1]의 활성화 함수에 일치되도록 보장 (기본값 TRUE)

      • act.fct : 미분 활성화 함수(기본값 "logistic") 

      • err.fct : 미분 오차 함수(기본값 "sse") 

      • learningrate : 학습속도(step), backprop 사용시 설정 

      • algorithm : backprop > 전통적인 역전파(backpropagation)

     

    • 딥러닝 (Deeplearning)

      • training_frame : 학습 데이터 셋 h2o type   

      • nfolds : 교차검정에서 N-fold

      • stopping_rounds : stops_metric의 수렴에 기초한 조기 정지 (기본값 5)

      • stopping_metric : 조기 정지에 사용되는 미터법 ("MSE", "RMSE", "MAE", "RMSLE" "AUC") 

      • MSE : 평균제곱오차 (Mean Squared Error) > ML에서 cost Function으로 사용 

      • epochs : 학습과정에서 훈련데이터를 모두 소진한 횟수 

      • overwrite_with_best_model : 훈련된 최적의 모형으로 대체 (default : TRUE)

      • activation : tanh (sigmoid 함수를 재활용, sigmoid의 범위를 -1에서 1로 넓힘)

      • input_dropout_ratio : 입력 레이어 드롭 아웃 비율(일반화 향상, 0.1 또는 0.2, 기본값 0)

    data = read.csv("INPUT/IEODO_Observation_QC_2017-06-16,17.OUT", sep="", head=T)
    data = na.omit(data)  # NA값 제거
    
    # 이어도 관측자료 (TrainDF: 2017-06-16, TestDF: 2017-06-17)
    # 년, 월, 일, 시, 분, 풍향, 풍속, 온도, 상대습도, 기압, 일사량, 일조시간, 태양 방위각, 태양 천정각
    head(data)
    
    #================================================
    #     Neural Networks
    #================================================
    set.seed(123)
    
    OriDataFrame = data[ ,c(-1:-5)]  # 년,월,일,시,분 제거
    str(OriDataFrame)
    
    # Normalizing the data in interval [0, 1]
    # Normalization is necessay so that each variable is scale properly
    # and none of the variables overdominates
    # scale function will give mean=0 and standard deviation=1 for each variables
    maxValue = apply(OriDataFrame, 2, max)
    minValue = apply(OriDataFrame, 2, min)
    rangeInsValue = (maxValue["ins"] - minValue["ins"])
    
    DataFrame = as.data.frame( scale(OriDataFrame, center=minValue, scale=maxValue-minValue) )
    
    summary(DataFrame)
    
    # Lets create the train and test data set
    ind = sample(1:nrow(DataFrame), length(DataFrame[,1])/2)
    # ind = 1:809
    trainDF = DataFrame[ind, ]
    testDF = DataFrame[-ind, ]
    
    # Lets take some configuration for neural network
    # say 13-4-2-1
    # So number of hidden layers=2
    # input layer had 10 units
    
    # we need this as formula
    # medv ~ crim + zn ...
    
    allVars = colnames(DataFrame)
    predictorVars = allVars[!allVars %in% "ins"]
    predictorVars = paste(predictorVars, collapse="+")
    form = as.formula(paste("ins~", predictorVars, collapse = "+"))
    # ins ~ ws + wd + temp + rh + pre + sunshine + azimuth + zenith
    
    # neuralModel = neuralnet(formula=form, data=trainDF)
    # neuralModel = neuralnet(formula=form, hidden=c(10,10), data=trainDF)
    # neuralModel = neuralnet(formula=form, hidden=c(20,20,20), data=trainDF)
    neuralModel <- neuralnet(formula = form, hidden = c(4, 2), linear.output = T, data = trainDF)
    
    # 3) NN모델 생성 - 은닉 노드 1개 
    # 형식) neuralnet(formula, data, hidden) 
    neuralModel = neuralnet(formula = form, data=trainDF, hidden = 1, threshold = 0.01,
                            linear.output=FALSE, act.fct = 'logistic')
    # ?neuralnet
    # hidden = 1 : 은닉노드수 c(100,100)
    # threshold : 편미분에 대한 종료기준 임계값(기본값:0.01)
    # rep : 훈련 과정 반복 수(기본값 1)
    # linear.output=FALSE -> 출력 구간[0, 1]의 활성화 함수에 일치되도록 보장(기본값: TRUE) 
    # act.fct : 미분 활성화 함수(기본값 "logistic")
    # err.fct : 미분 오차 함수(기본값 "sse")
    # learningrate : 학습속도(step), backprop 사용시 설정
    # algorithm : backprop -> 전통적인 역전파(backpropagation)
    
    
    # Plot the neural net
    # plot(neuralModel)
    
    # Predict for test data set
    predictions = compute(neuralModel, testDF[ ,-7])
    # str(predictions)
    
    # predictions = predictions$net.result*(max(testDF$ins)-min(testDF$ins)) + min(testDF$ins)
    # actualValues = (testDF$ins)*(max(testDF$ins)-min(testDF$ins)) + min(testDF$ins)
    
    # predictions = predictions$net.result
    # actualValues = testDF$ins
    
    predictions = predictions$net.result * rangeInsValue
    actualValues = testDF$ins * rangeInsValue
    
    RMSE = sqrt(sum( (predictions-actualValues)^2 )/nrow(testDF))  ;  RMSE
    cor(predictions, actualValues)
    
    plot(actualValues, predictions, col='blue', main='Recl vs Predicted', pch=1, type="p", xlab="Actual", ylab="Predicted")
    cor(testDF$ins, predictions)
    abline(0, 1, col="black")
    
    
    #================================================
    #     Deeplearning
    #================================================
    
    # H2o is a fast and scalable opensource machine learning platform.
    # Several algorithms are available.
    # set.seed(123)
    
    # initiallization
    h2o.init()
    
    # Defining x and y
    y = "ins"
    x = setdiff( colnames(DataFrame),y )
    
    # Lets create the train and test data set
    # ind = sample(1:nrow(DataFrame), 400)
    # trainDF = DataFrame[ind, ]
    # testDF = DataFrame[-ind, ]
    
    # Fitting the model
    # ?h2o.deeplearning
    
    model = h2o.deeplearning(x=x, y=y, training_frame = as.h2o(trainDF))
    # model = h2o.deeplearning(x=x, y=y, training_frame = as.h2o(trainDF), nfolds=5, hidden=c(10, 10))
    # model = h2o.deeplearning(x=x, y=y, training_frame = as.h2o(trainDF), hidden=c(5000,5000))
    # model = h2o.deeplearning(x=x, y=y, training_frame = as.h2o(trainDF), nfolds=5, hidden=c(1000,1000))
    model
    
    # model 생성 : network = 13-10-10-1 
    model <- h2o.deeplearning(x=x, y=y, training_frame = as.h2o(trainDF),
                              nfolds = 3, #stopping_rounds = 7,
                              stopping_metric = 'RMSE',
                              epochs = 400, overwrite_with_best_model = TRUE,
                              activation = 'Tanh', input_dropout_ratio = 0.1,
                              hidden = c(10,10), l1 =0,
                              loss = 'Automatic', distribution = 'AUTO')
    model  
    #training_frame : 학습데이터셋-h2o type   
    #nfolds : 교차검정에서 N-fold 
    #stopping_rounds : stops_metric의 수렴에 기초한 조기 정지(기본값 5)
    #stopping_metric : 조기 정지에 사용되는 미터법( "MSE", "RMSE", "MAE", "RMSLE" "AUC",) 
    #MSE : 평균제곱오차(Mean Squared Error) -> ML에서 cost Function으로 사용 
    #epochs(1에폭) : 학습과정에서 훈련데이터를 모두 소진한 횟수 
    #overwrite_with_best_model : 훈련된 최적의 모형으로 대체(default : TRUE)
    #activation : tanh(sigmoid 함수를 재활용, sigmoid의 범위를 -1에서 1로 넓힘)
    #input_dropout_ratio : 입력 레이어 드롭 아웃 비율(일반화 향상, 0.1 또는 0.2, 기본값 0)
    # 드롭 아웃 : 매개변수가 많아서 신경망이 복잡한 경우 뉴런을 임의 삭제하여 학습하는 방법 
    # 훈련 시 은닉층의 뉴런을 무작위 삭제하여 신호 전달 차단  
    # hidden : Hidden layer sizes(2층)
    
    # Predict for test data set
    predictions = as.data.frame(predict(model, as.h2o(testDF)))
    # str(predictions)   
    
    
    predictions = predictions$predict * rangeInsValue
    actualValues = testDF$ins * rangeInsValue
    
    RMSE = sqrt(sum( (predictions-actualValues)^2 )/nrow(testDF))  ; RMSE
    
    plot(actualValues, predictions, col='blue', main='Recl vs Predicted', 
         pch=1, type="p", xlab="Actual", ylab="Predicted")
    cor(testDF$ins, predictions)
    abline(0, 1, col="black")
    
    # h2o.shutdown(prompt=F)

     

    • 인공신경망을 이용한 일사량 예측 결과

      • 상관계수 (R) : 0.93

      • 평균제곱근오차 (RMSE) : 140.84

     

     

    • 딥러닝을 이용한 일사량 예측 결과

      • 상관계수 (R) : 0.97

      • 평균제곱근오차 (RMSE) : 89.09

     

     

    [전체]

     

     참고 문헌

    [논문]

    • 없음

    [보고서]

    • 없음

    [URL]

    • 없음

     

     문의사항

    [기상학/프로그래밍 언어]

    • sangho.lee.1990@gmail.com

    [해양학/천문학/빅데이터]

    • saimang0804@gmail.com

     

     

     

     

     

     

    본 블로그는 파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음
    • 네이버 블러그 공유하기
    • 네이버 밴드에 공유하기
    • 페이스북 공유하기
    • 카카오스토리 공유하기