※ 본 문서는 PC 환경에 최적화되어있습니다.
1 실습 목표
지리학 연구에 있어서 가장 만족스럽고 중요한 부분은 아마도 도출된 결과를 가지고 의사소통을 하는 것이다. 지도학의 기술이자 지도를 만드는 것은 오래전부터 행해져온 의사소통, 직관 그리고 창의적인 요소를 아우르는 기술이다. 잘 제작된 지도는 효과적으로 도출한 결과를 소통할 수 있는 강력한 도구가 될 수 있다.
Amateur-looking maps can undermine your audience’s ability to understand important information and weaken the presentation of a professional data investigation.
— (Brewer 2015)
또한, 최근 정보화 시대에 접어들면서 웹 상에서 여러 정보들을 손쉽게 얻거나 공유할 수 있게 되었다. 이 추세에 따라 지도 또한 인터넷 상으로 배포가 되어 과거처럼 소수만의 전유물이 아닌 어느 누구나 볼 수 있는 시대가 되었다.
이 실습에서는 직접 동적 웹 지도를 제작하여 이러한 동향들을 파악하는 시간을 만들고자 한다.
-
Web GIS의 장단점을 이해하고 사례를 활용할 수 있다.
-
R을 활용하여 상호작용이 가능한 지도를 제작할 수 있다.
-
제작한 지도를 웹 상에 배포할 수 있다.
2 환경 구축
2.1 설치 프로그램
이번 실습을 위해 설치하는 프로그램은 다음과 같다.
- R(base)
- RStudio
- Rtools40
이 중 필수로 설치를 요하는 프로그램은 R과 RStudio이며, Rtools40는 추가적으로 더 배워보고 싶은 사람만 선택적으로 설치하기를 권장한다.
아래에 제시된 링크에서 설치 파일을 먼저 받는다.
R
설명
R은 프로그래밍 언어이며 통계 컴퓨팅 및 그래픽을 위한 무료 소프트웨어 환경이다. R 언어는 통계학자와 데이터 마이너들 사이에서 통계 소프트웨어 및 데이터 분석을 개발하기 위해 널리 사용된다. 조사, 데이터 마이닝 조사 및 학술 문헌 데이터베이스에 대한 연구는 R의 인기가 상당히 상승했음을 보여준다. R은 프로그래밍 언어의 인기척도인 TIOBE 지수에서 14위를 차지했다. 많은 수의 패키지를 사용하여 무궁무진한 연구를 진행할 수 있으며, 공간 분석도 예외는 아니다.
RStudio
Rtools40
설명
R 및 R 패키지를 빌드하는 도구. Windows에서 직접 패키지를 빌드하거나 R 자체를 빌드하려면 필요하다. 컴파일이 필요한 패키지를 설치 시 C/C++, FORTRAN 등 여러 언어의 컴파일러를 지원한다.
보충설명 - The why and the how of installing Rtools
2.2 설치 방법
위에서 제시한 링크에서 받은 설치 파일을 다음 동영상을 참고하여 설치한다.
일반 사용자
심화 사용자
3 R Crash Course
지도를 제작시 필요한 기초 문법만 수록하였다.
3.1 RStudio에서 R 코드 실행 방법
실행을 원하는 부분에 텍스트 커서를 두고 Ctrl+Enter로 한 줄 한 줄 실행 가능하다.
3.2 변수 선언
변수 선언은 어떠한 프로그래밍 언어를 하든 꼭 필요한 작업이다. 변수를 선언해야 해당 변수에 자료를 담고, 이를 모아 연산을 하고 그 결과를 도출하며, 결과 또한 변수로 저장할 수 있기 때문이다.
R에서 변수를 선언하는 방법은 아주 간단하다. 사용할 변수명을 제시하고 해당 변수명에 들어갈 데이터를 <-
혹은 =
을 사용하여 선언할 수 있다.
3.2.1 변수에 숫자 지정
다음은 숫자형 자료를 변수에 지정하는 과정이다.
# 참고: 주석 다는법
#(해시, 샵) 사용(주석처리할 라인(혹은 부분) 맨 앞에)
# 주석(comment)이란?: 프로그래밍에 있어 내용을 메모하는 목적으로 쓰이며,
# 주석 처리가 된 줄은 실행되지 않는다.
n <- 1 #n에 1을 선언
m = .1 #m에 0.1을 선언
str(n) # 자료형 확인
num 1
str(m)
num 0.1
nm <- n*m # 반환형식:
# > str(nm)
# num 0.1 <<< 자료형 자료값
# 자세한 내용은 콘솔창에 ?str()
str(nm)
num 0.1
3.2.2 변수에 문자 지정
c <- "꿈과 희망이 가득한 대학원"
c = "꿈과 희망이 가득한 대학원" # 동일한 변수에 지정시 덮어쓰기
str(c)
chr "꿈과 희망이 가득한 대학원"
3.2.3 변수에 배열 지정
{1,2,3,4,5}와 같이 벡터 혹은 집합과 같은 데이터를 담는 방법으로, 배열은 c()
를 사용하여 생성한다.
an <- c(1,3,5,7)
ac <- c(c,"같이하실래요?","쪼-인","어스")
str(an)
num [1:4] 1 3 5 7
str(ac)
chr [1:4] "꿈과 희망이 가득한 대학원" "같이하실래요?" "쪼-인" "어스"
3.2.4 변수에 데이터프레임 지정
데이터프레임은 스프레드 시트 형식으로 자료를 저장하는 구조로, 행과 열로 구성됨.
df <- data.frame(an,ac) #각 배열의 차원이 같아야 데이터 프레임으로 지정 가능
str(df)
'data.frame': 4 obs. of 2 variables:
$ an: num 1 3 5 7
$ ac: chr "꿈과 희망이 가득한 대학원" "같이하실래요?" "쪼-인" "어스"
3.2.5 지정한 변수 값 반환
변수의 값을 확인하기 위해서는 커맨드 라인에 해당 변수명을 치거나 print()
함수를 사용하여 반환한다.
m # 변수명
[1] 0.1
print(df) # print() 함수 사용
an ac
1 1 꿈과 희망이 가득한 대학원
2 3 같이하실래요?
3 5 쪼-인
4 7 어스
an*m # 연산 결과도 표출 가능
[1] 0.1 0.3 0.5 0.7
3.3 패키지
R 패키지는 크게 R 설치 시, 함께 설치된 base
(내장) 패키지와 사용자의 사용 목적에 따라 외부패키지로 크게 구분될 수 있다. base
패키지는 주로 R의 기본문법이라고 이해해도 좋다. 다만, 외부패키지는 기본문법을 바탕으로 조금 더 편안하게 사용하고자 하는데 개발 목적이 있다.
패키지는 다시 설치와 사용방법에 따라서
Base system을 설치할 때 자동으로 설치가 되어 기본적인 통계분석과 그래프 작성, 데이터 처리 등에 즉시 사용이 가능한 Base packages (
base
,datasets
,graphics
,grid
,methods
,stats
,utils
등)Base system을 설치할 때 자동으로 설치가 되기는 하지만, 사용하려면 R로 불러오기를 해야만 사용이 가능한 Recommended packages (
MASS
,foreign
,lattice
등)통계 등 분석 목적/필요에 따라 따로 설치를 하고 R로 불러오기를 해서 사용해야 하는 Other packages (
tidyverse
,sf
,rgdal
,tmap
등 다수)
로 세분화할 수 있다.
Package 구분 | 설치여부 | 사용시 |
---|---|---|
Base Packages | 자동 | 불러오기 불필요 |
Recommended Packages | 자동 | 불러오기 필요library(Package) |
Other Packages | 개별설치install.packages("Package") |
불러오기 필요library(Package) |
3.3.1 패키지 설치
#install.packages("새로운_패키지명")
install.packages("tidyverse")
# 패키지 제거
#remove.packages("tidyverse")
혹은 다음과 같이 RStudio에서 그래픽 인터페이스 환경으로도 설치할 수 있다.
GUI로 패키지 설치 창에 접근할 수 있는 방법은 2가지가 있는데
- 상단바 중 ‘Tools’의 ’Install Packages…’
- 우측 ‘Packages’ 탭의 ‘Install’ (위 사진 참고)
패키지 설치 창에 접근하였으면 자동완성기능을 활용하여 원하는 패키지를 설치하면 된다.
3.3.2 패키지 불러오기
현재 R 세션에 패키지를 불러오기 위해서는 다음과 같은 명령이 필요하다. 예를 들어, 데이터 정제에 필수적인 tidyverse
패키지를 불러오려면,
#library(기설치된패키지명)
library(tidyverse)
-- Attaching packages --------------------------------------- tidyverse 1.3.1 --
v ggplot2 3.3.5 v purrr 0.3.4
v tibble 3.1.6 v dplyr 1.0.7
v tidyr 1.1.4 v stringr 1.4.0
v readr 2.1.0 v forcats 0.5.1
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag() masks stats::lag()
위와 같이 여러 메시지들이 나타나면서 정상적으로 로드가 된다.
설치시와 비슷하게 RStudio에서 그래픽 인터페이스 환경으로도 불러올 수 있다.
GUI환경에서 패키지 불러오는 법
- Packages 탭 누르기
- 검색창에 원하는 패키지 검색
- 원하는 패키지 체크
그러나 GUI에서 패키지를 불러오는 방법은 추천하지 않는데, 그 이유는 코드를 짜다보면 어떤 패키지를 불러왔는지 기록이 남지 않기 때문에 작업에 혼선을 야기할 수 있다. 따라서 library()
함수를 사용하여 코드 내에 기록을 하며 작업하기를 권장한다.
참고로 다음과 같이 패키지를 내릴 수도 있다.
# 패키지 unload
#detach("package:tidyverse", unload = TRUE)
3.4 데이터프레임 manipulation
3.4.1 Data Frame이란?
데이터 프레임(Data frame)은 다양한 형태의 데이터가 2차원으로 구성된 데이터 구조이며, 행(케이스)과 열(변수)로 구성된 표이다. 엑셀에서 이름 필드, 연령 필드, 성적 필드 등으로 이루어진 표와 같다고 생각하면 이해가 빠를 것이다. 통계분석에 가장 많이 사용된다. GIS에서 속성 테이블(Attribute table) 또한 해당 형식으로 나타낼 수 있다.
3.4.2 데이터 프레임 구조 보기
아래는 tidyverse
패키지에서 기본으로 제공하는 샘플 tibble로, 형태는 데이터 프레임과 유사하다.
table1
# A tibble: 6 x 4
country year cases population
<chr> <int> <int> <int>
1 Afghanistan 1999 745 19987071
2 Afghanistan 2000 2666 20595360
3 Brazil 1999 37737 172006362
4 Brazil 2000 80488 174504898
5 China 1999 212258 1272915272
6 China 2000 213766 1280428583
str(table1)
tibble [6 x 4] (S3: tbl_df/tbl/data.frame)
$ country : chr [1:6] "Afghanistan" "Afghanistan" "Brazil" "Brazil" ...
$ year : int [1:6] 1999 2000 1999 2000 1999 2000
$ cases : int [1:6] 745 2666 37737 80488 212258 213766
$ population: int [1:6] 19987071 20595360 172006362 174504898 1272915272 1280428583
데이터 프레임 또한 위와 같은 구조를 지닌다.
3.4.3 데이터 프레임 만들기
데이터 프레임을 생성하는 방법은 많다. 그 중에서 가장 많이 쓰이는 방법은 외부에서 데이터를 R에서 읽어 들이는 방법이다. 이 방법은 R 입출력에서 자세히 다루도록 하겠다.
두 번째 방법은 벡터 형식의 자료를 묶어서 데이터 프레임을 만드는 것이다. 아래 예제는 data.frame()
함수를 이용하여 벡터 변수 name, age, sex, score를 하나로 묶어서 데이터 프레임 df
를 만들어 보겠다.
name <- c("유재석", "홍진영", "송가인", "강호동", "이영자", "김종민", "김연아")
age <- c(24, 28, 31, 25, 27, 22, 29)
sex <- c("남", "여", "여", "남", "여", "남", "여")
score <- c(90, 80, 85, 75, 95, 80, 70)
# 'stringsAsFactors = F' 옵션 : 문자 데이터를 factor로 변환시키지 않음
df <- data.frame(name, age, sex, score, stringsAsFactors = F)
df
name age sex score
1 유재석 24 남 90
2 홍진영 28 여 80
3 송가인 31 여 85
4 강호동 25 남 75
5 이영자 27 여 95
6 김종민 22 남 80
7 김연아 29 여 70
세번째 방법은 수식 등의 규칙을 사용한 방법이다.
x <- 1:10 #1부터 10까지의 배열
y <- 2 #상수 2로 채워진 배열이며 길이는 x와 동일
z <- (x**2)+y #x^2 + 2 x와 y의 식으로 채워짐
num.df <- data.frame(x,y,z)
num.df
x y z
1 1 2 3
2 2 2 6
3 3 2 11
4 4 2 18
5 5 2 27
6 6 2 38
7 7 2 51
8 8 2 66
9 9 2 83
10 10 2 102
# deg 2 rad
deg <- 0:360
PI <- atan(1)*4 #the exact value of pi
rad <- deg*PI/180
rad.df <- data.frame(deg, PI, rad)
#head()와 tail()함수는 각각 자료의 앞과 뒤를 반환하는 함수이며,
#rbind() 함수는 차원이 동일하며 같은 열이름을 지닌 df를 합쳐준다.
rbind(head(rad.df,n=3),tail(rad.df,n=3))
deg PI rad
1 0 3.141593 0.00000000
2 1 3.141593 0.01745329
3 2 3.141593 0.03490659
359 358 3.141593 6.24827872
360 359 3.141593 6.26573201
361 360 3.141593 6.28318531
3.4.4 데이터 프레임에서 데이터 선택 및 추출
이 부분에서는 데이터 프레임에서 자료를 선택하고 이를 추출하는 방법에 대해 다룬다.
아래의 예시에서 반환되는 데이터는 모두 변수에 저장하여 사용이 가능하다.
# name 열(변수) 데이터 추출
# 데이터프레임과 컬럼사이에 $기호가 사용됨
df$name # df[,1], df[, "name"]와 동일
[1] "유재석" "홍진영" "송가인" "강호동" "이영자" "김종민" "김연아"
# df$name 대신 아래처럼 사용 가능
df[, "name"]
[1] "유재석" "홍진영" "송가인" "강호동" "이영자" "김종민" "김연아"
# 첫번째 열(name) 추출
df[, 1]
[1] "유재석" "홍진영" "송가인" "강호동" "이영자" "김종민" "김연아"
# 1열과 3열 추출
# 여러 항목을 넣을 때는 배열 형식인 c(1,6,8:11)으로 할 것.
df[, c(1, 3)]
name sex
1 유재석 남
2 홍진영 여
3 송가인 여
4 강호동 남
5 이영자 여
6 김종민 남
7 김연아 여
# name 열(변수)의 3번째 데이터 추출
df$name[3]
[1] "송가인"
# 2~3번째 행 추출
df[2:3, ]
name age sex score
2 홍진영 28 여 80
3 송가인 31 여 85
# 연령 변수의 데이터를 추출하여 평균을 구함
# na.rm = TRUE는 missing value를 제외하고 계산함
mean(df$age, na.rm = TRUE)
[1] 26.57143
아래와 같이 특정 영역을 제외하고 추출할 수 있다.
# 3번째 열 제외
df[, -3]
name age score
1 유재석 24 90
2 홍진영 28 80
3 송가인 31 85
4 강호동 25 75
5 이영자 27 95
6 김종민 22 80
7 김연아 29 70
행 또한 위와같이 -
기호를 사용하여 적용 가능하다.
혹은 다음과 같이 조건을 적용하여 추출이 가능하다.
# score가 90이상인 데이터 추출
df[df$score >= 90, ]
name age sex score
1 유재석 24 남 90
5 이영자 27 여 95
# score가 90이상인 데이터의 name과 age만 추출
# 1:2 대신 c("name", "age")를 사용해도 됨
df[df$score >= 90, 1:2]
name age
1 유재석 24
5 이영자 27
# 조건식과 출력 컬럼명을 변수에 입력하고 이를 활용
score90 <- df$score >= 90
cols <- c("name", "age")
df[score90, cols]
name age
1 유재석 24
5 이영자 27
subset()
함수 사용시
# score가 90이상인 데이터 추출 문법: subset(df, 조건)
subset(df, score >= 90)
name age sex score
1 유재석 24 남 90
5 이영자 27 여 95
# score가 90이상인 데이터의 name과 age만 추출
subset(df, score >= 90, select = c(name, age))
name age
1 유재석 24
5 이영자 27
# score가 90이상인 데이터에서 age와 sex만 제외하고 추출
subset(df, score >= 90, select = -c(age,sex))
name score
1 유재석 90
5 이영자 95
3.4.5 데이터 프레임의 구조 수정
열 추가/삭제
데이터 프레임의 가장 오른쪽에 열을 추가하는 방법이다.
#배열 생성
radian <- rad.df$rad[c(1,91,181,271,361)]
PI <- rad.df$PI[c(1,91,181,271,361)]
deg <- radian*180/PI
# 데이터 프래임 생성
rad2deg <- data.frame(radian,deg)
# 추가할 열 생성
`rad/pi` <- radian/PI #0, 1/2, 1, 3/2, 2
# rad2deg df의 rad/pi 열을 rad/pi로 정의하여 추가
rad2deg$`rad/pi` <- `rad/pi`
rad2deg
radian deg rad/pi
1 0.000000 0 0.0
2 1.570796 90 0.5
3 3.141593 180 1.0
4 4.712389 270 1.5
5 6.283185 360 2.0
아래는 원하는 열을 삭제하는 방법이다.
#삭제
## 불필요 열 생성
rad2deg$tmp <- "tmp"
rad2deg
radian deg rad/pi tmp
1 0.000000 0 0.0 tmp
2 1.570796 90 0.5 tmp
3 3.141593 180 1.0 tmp
4 4.712389 270 1.5 tmp
5 6.283185 360 2.0 tmp
## 삭제
rad2deg <- rad2deg[,-c(3,4)] # 3번 열과 4번 열 삭제
rad2deg
radian deg
1 0.000000 0
2 1.570796 90
3 3.141593 180
4 4.712389 270
5 6.283185 360
행 추가/삭제
데이터 프레임의 하단에 행을 추가하는 방법이다.
new_data <- list("김남준", 24, "남", 92)
new_data
[[1]]
[1] "김남준"
[[2]]
[1] 24
[[3]]
[1] "남"
[[4]]
[1] 92
df <- rbind(df, new_data)
df
name age sex score
1 유재석 24 남 90
2 홍진영 28 여 80
3 송가인 31 여 85
4 강호동 25 남 75
5 이영자 27 여 95
6 김종민 22 남 80
7 김연아 29 여 70
8 김남준 24 남 92
new_data <- data.frame(
name = "이지은",
age = 26,
sex = "여",
score = 93)
df <- rbind(df, new_data)
df
name age sex score
1 유재석 24 남 90
2 홍진영 28 여 80
3 송가인 31 여 85
4 강호동 25 남 75
5 이영자 27 여 95
6 김종민 22 남 80
7 김연아 29 여 70
8 김남준 24 남 92
9 이지은 26 여 93
다음은 원하는 행을 삭제하는 방법이다.
# 행 삭제
removed <- df[-c(2:8),] # 2~8행 삭제
removed
name age sex score
1 유재석 24 남 90
9 이지은 26 여 93
3.4.6 데이터 프레임 자료 수정
df
name age sex score
1 유재석 24 남 90
2 홍진영 28 여 80
3 송가인 31 여 85
4 강호동 25 남 75
5 이영자 27 여 95
6 김종민 22 남 80
7 김연아 29 여 70
8 김남준 24 남 92
9 이지은 26 여 93
위와 같은 데이터 프레임에서 홍진영의 점수를 100점으로 바꾸려면..
df[2,4] <- 100. # df[행#,열#]
# 목록에 조교 추가!
df[9,1] <- "서용훈"
df[9,3] <- "남"
df
name age sex score
1 유재석 24 남 90
2 홍진영 28 여 100
3 송가인 31 여 85
4 강호동 25 남 75
5 이영자 27 여 95
6 김종민 22 남 80
7 김연아 29 여 70
8 김남준 24 남 92
9 서용훈 26 남 93
위와 같이 행번호와 열번호를 지정하여 데이터를 수정할 수 있다.
3.5 자료 입출력
3.5.1 경로 개념 - 절대경로와 상대경로
엑셀과 같은 외부 데이터를 불러오기에 앞서, 파일 경로에 대한 이해가 필요하기 때문에 마련한 부분이다. 익혀두면 R 뿐만이 아니라 다른 프로그래밍을 할 때에도 도움이 되는 부분이라 생각된다.
절대경로
’절대경로(Absolute Path)’는 자신이 원하는 경로를 Root 디렉터리부터 모두 적은 것을 의미한다. 현재 문서를 작성하는 작업공간(working directory)을 예로 들자면, Windows 운영체제에서는 아래와 같이 적은 것이 절대경로이다.
‘작업공간’ 혹은 ’작업 폴더’는 데이터를 불러오거나 외부로 저장하는 작업을 수행하는 기본 폴더이다. 쉽게 말해서 작업이 이루어지는 공간으로, 파일을 읽거나 저장할 때, 경로를 지정하지 않으면 해당 폴더로 저장된다.
현재 문서의 작업공간은 다음과 같다.
# 현재 작업공간을 절대경로로 반환
getwd()
[1] "E:/workspace/active/ComputerCartography(TA)/ex8_rev/webGIS"
getwd()
함수의 반환 값으로 알 수 있는 현재 작업경로의 절대경로는 다음과 같다.
E:/workspace/active/ComputerCartography(TA)/ex8_rev/webGIS
상대경로
’상대 경로(Relative Path)’는 특정 경로를 기준으로 다른 경로는 표시하는 개념이다. 상대경로를 표시할 때는 ‘.’과 ‘..’을 함께 많이 사용하는데 ‘.’은 현재 경로(Current Directory)를 의미하고 ‘..’은 상위 경로(Parent Directory)를 의미한다.
예를 들어 현재 작업 공간을 상대경로로 다시 나타낸다면 다음과 같이 나타낼 수 있다.
.
간단하지요?
진짜인지 확인하기 위해 작업공간을 설정할 수 있는 setwd()
함수를 이용하여 확인해보자.
# 작업공간 설정
setwd(".") # 경로는 문자열로 받기 때문에 "your_dir" 씌울 것
getwd()
[1] "E:/workspace/active/ComputerCartography(TA)/ex8_rev/webGIS"
절대경로에서 확인한 경로와 동일함을 알 수 있다.
참고로 ‘..’은 상위 경로를 탐색할 때 사용되고, 하위 경로를 탐색할 때에는 절대경로와 동일하게 원하는 파일이나 폴더를 명시하면 된다. ‘.’은 현재 경로를 명시적으로 나타낼 때 사용된다.
# 예시
## 여기서 사용된 dir() 함수는 입력된 경로의 파일/폴더 목록을 보여준다.
# 절대경로 - 현재 작업공간
# E:/workspace/active/ComputerCartography(TA)/ex8_rev/webGIS
dir(getwd())
[1] "2020pop.html" "data" "ex8"
[4] "Ex8-1.html" "Ex8.html" "Ex8.Rmd"
[7] "ex8.zip" "Ex8_old.html" "fig"
[10] "map.html" "seoulGU.html" "test.html"
[13] "서울시데이터셋.html" "실습8.html" "실습8.Rmd"
# 상대경로 - 현재 작업공간
# E:/workspace/active/ComputerCartography(TA)/ex8_rev/webGIS
dir(".")
[1] "2020pop.html" "data" "ex8"
[4] "Ex8-1.html" "Ex8.html" "Ex8.Rmd"
[7] "ex8.zip" "Ex8_old.html" "fig"
[10] "map.html" "seoulGU.html" "test.html"
[13] "서울시데이터셋.html" "실습8.html" "실습8.Rmd"
# 상대경로 - 현재 작업공간의 상위 폴더
# E:/workspace/active/ComputerCartography(TA)/ex8_rev
dir("./..") # `./` <- 현재 경로임을 명시적으로 선언
[1] "lab7" "webGIS"
# 상대경로 - 현재 작업공간에 위치한 'data' 폴더(하위)
# E:/workspace/active/ComputerCartography(TA)/ex8_rev/webGIS/data
dir("./data/")
[1] "Datasets" "html" "raster" "Rawdata" "shp"
상대경로의 장점은 프로젝트 파일을 다른 사람과 공유할 때, 보통 R 문서(확장자가 .R, .Rmd)이 포함된 작업공간 폴더를 통째로 공유한다면 공유를 받은 사람이 작업 시 경로를 하나하나 해당 작업공간에 맞게 변경하지 않아도 되는 장점이 있다.
절대경로는 작업공간이 아닌 D 드라이브와 같은 자료 저장소에서 자료를 불러올 때 유용하다. 만약 저장소 파일을 상대경로로 지정한다면, 사용자의 PC 내에서 R 문서를 옮긴다면 오히려 파일 경로가 깨질 것이다.
다음 사진을 보면 이해가 빠를 것이다.
상대경로와 절대경로
3.5.2 구분자 형식 외부 데이터 R로 불러오기
이제부터는 여러 파일 형식의 파일을 불러오는 방법을 알아볼 것이다.
이 섹션에서 다루는 함수는 readr
패키지이며, 이는 tidyverse
에 포함되어 있으므로, 보통 tidyverse
만 불러오면 될 것이다. 기존 R base에도 유사한 함수가 존재하나 성능 및 tibble
지원 때문에 readr
패키지의 함수를 사용하는 것을 권장한다.
readr
의 함수 대부분은 파일을 데이터 프레임으로 바꾸는데 특화되어있다.
구분자(delimiter)로 이루어진 파일을 읽는 함수는 다음과 같다.
read_csv()
: 콤마(,) 구분자 파일(csv)read_csv2()
: 세미콜론(;) 구분자 파일read_tsv
: 탭( ) 구분자 파일read_delim()
: 모든 구분자 파일
위 함수의 사용 방법이 유사한 관계로 이 중 모든 형식의 구분자를 받을 수 있는 read_delim()
함수를 사용해보도록 하겠다.
쉼표 구분자 파일(CSV)
다음과 같이 쉼표로 구분되어 있는 형식의 데이터 파일을 Comma-Separated Values(CSV) 파일이라고 하며 메모장을 이용하여 열어본다면 다음과 형식으로 나타날 것이다.
지점,시작일,종료일,지점명,지점주소,관리관서,위도,경도,노장해발고도(m),기압계(관측장비지상높이(m)),기온계(관측장비지상높이(m)),풍속계(관측장비지상높이(m)),강우계(관측장비지상높이(m)) 400,2019-05-29,,강남,서울특별시 강남구일원동 580탄천 물재생센터 ,,37.4982,127.0816,28.7…..
위와 같은 형식의 파일을 tibble(데이터프레임과 유사) 형식으로 가져오려면…
# read_csv()와 동일
seoul_obs_loc <- read_delim("./data/Rawdata/IO/META_관측지점정보_20200627233901.csv",#상대경로
locale=locale('ko',encoding='euc-kr')) # 파일인코딩 설정
seoul_obs_loc
# A tibble: 65 x 13
지점 시작일 종료일 지점명 지점주소 관리관서 위도 경도
<dbl> <date> <date> <chr> <chr> <chr> <dbl> <dbl>
1 400 2019-05-29 NA 강남 "서울특별시 강남구~ <NA> 37.5 127.
2 400 2010-08-16 2019-05-29 강남 "서울특별시 강남구~ <NA> 37.5 127.
3 400 1994-12-04 2010-08-15 강남 "서울특별시 강남구~ 서울기상관~ 37.5 127.
4 401 2016-09-12 NA 서초 "서울특별시 서초구~ <NA> 37.5 127.
5 401 2010-08-16 2016-09-12 서초 "서울특별시 서초구~ <NA> 37.5 127.
6 401 1994-12-04 2010-08-15 서초 "서울특별시 서초구~ 서울기상관~ 37.5 127.
7 402 2010-08-16 NA 강동 "서울특별시 강동구~ <NA> 37.6 127.
8 402 1994-12-04 2010-08-15 강동 "서울특별시 강동구~ 서울기상관~ 37.6 127.
9 403 2010-08-16 NA 송파 "서울특별시 송파구~ <NA> 37.5 127.
10 403 1994-12-05 2010-08-15 송파 "서울특별시 송파구~ 서울기상관~ 37.5 127.
# ... with 55 more rows, and 5 more variables: 노장해발고도(m) <dbl>,
# 기압계(관측장비지상높이(m)) <dbl>, 기온계(관측장비지상높이(m)) <dbl>,
# 풍속계(관측장비지상높이(m)) <dbl>, 강우계(관측장비지상높이(m)) <dbl>
위와 같이 tibble
형식의 데이터 프레임을 불러올 수 있다.
탭 구분자 파일(TSV)
CSV 파일과 유사하지만 구분자가 tab( )인 파일은 다음과 같이 구성되어있다.
기간 자치구 세대 인구 인구 인구 인구 인구 인구 인구 인구 인구 세대당인구 65세이상고령자 기간 자치구 세대 합계 합계 합계 한국인 한국인 한국인 등록외국인 등록외국인 등록외국인 세대당인구 65세이상고령자 기간 자치구 세대 계 남자 여자 계 남자 여자 계 남자 여자 세대당인구 65세이상고령자 2020.1/4 합계 4,354,006 10,013,781 4,874,995 5,138,786 9,733,655 4,742,217 4,991,438 280,126 132,778 147,348 2.24 1,518,239
이를 데이터 프레임 형식으로 불러오려면…
# read_tsv()와 동일
# 이번 파일은 csv 예시와 다르게 인코딩이 패키지 기본 값인 UTF-8이므로
# 추가적으로 인코딩 선언은 불필요함
seoulGU21 <- read_delim("./data/Rawdata/population/20201stQGu.txt")
seoulGU21
# A tibble: 28 x 14
기간 자치구 세대 인구...4 인구...5 인구...6 인구...7 인구...8 인구...9
<chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 기간 자치구 세대 합계 합계 합계 한국인 한국인 한국인
2 기간 자치구 세대 계 남자 여자 계 남자 여자
3 2020.1/4 합계 4,35~ 10,013,~ 4,874,9~ 5,138,7~ 9,733,6~ 4,742,2~ 4,991,4~
4 2020.1/4 종로구 74,1~ 161,984 78,271 83,713 151,217 73,704 77,513
5 2020.1/4 중구 63,0~ 136,469 66,769 69,700 126,175 61,839 64,336
6 2020.1/4 용산구 110,~ 246,165 119,961 126,204 229,579 110,667 118,912
7 2020.1/4 성동구 135,~ 307,193 149,891 157,302 299,042 146,300 152,742
8 2020.1/4 광진구 165,~ 365,990 176,226 189,764 350,417 169,568 180,849
9 2020.1/4 동대문구 165,~ 362,793 178,202 184,591 346,156 171,896 174,260
10 2020.1/4 중랑구 182,~ 400,678 198,122 202,556 395,619 196,076 199,543
# ... with 18 more rows, and 5 more variables: 인구...10 <chr>,
# 인구...11 <chr>, 인구...12 <chr>, 세대당인구 <chr>, 65세이상고령자 <chr>
3.5.3 외부로부터 공간자료 불러오기
앞서 다뤘던 구분자 형식의 자료를 R 외부로부터 불러왔던 것과 같이, 이전 실습에서 다루었던 셰이프(.shp) 형식의 공간자료를 불러오는 법과 래스터 형식의 자료(.img)파일을 불러오는 방법을 살펴볼 것이다.
Shapefiles(.shp)
셰이프 파일을 불러오는 함수는 여러 개가 존재하나, 이번 실습에서는 rgdal
패키지를 사용하여 진행하고자 한다.
다음의 코드를 사용하여 rgdal
패키지를 설치하도록 한다.
if (require("rgdal")) {
# 참: 패키지 존재
print("패키지있어유~")
} else {
# 거짓: 패키지 설치
print("패키지깔게유~")
if (require("terra")){
print("terra 패키지 존재")
} else{
print("terra 패키지 설치..")
install.packages("terra")
}
install.packages("rgdal")
}
[1] "패키지있어유~"
library(rgdal) # 패키지 로드
아래는 rgdal
패키지의 함수인 readOGR()
함수를 사용하여 shp 파일을 불러오는 코드이다.
# 남한 시군구 shp를 불러오기
sigungu <- readOGR(dsn = "./data/shp/구", # dsn: shp파일 위치 경로
layer = "kr_si_gun-gu", # layer: 확장자를 제외한 파일명
encoding = "UTF-8", # 속성 테이블 인코딩
stringsAsFactors = FALSE, # 문자열을 factor로 받을지 선택
verbose = FALSE) # 로드 시 여러 메시지를 띄울지 여부
shp 파일을 불러왔으면 다음과 같은 명령으로 속성테이블(attribute table)을 데이터프레임 형식으로 조회할 수 있다.
# attr table
sigungu@data # shp지정변수명@data
SIG_CD SIG_ENG_NM SIG_KOR_NM
0 11110 Jongno-gu 종로구
1 11140 Jung-gu 중구
2 11170 Yongsan-gu 용산구
3 11200 Seongdong-gu 성동구
4 11215 Gwangjin-gu 광진구
5 11230 Dongdaemun-gu 동대문구
6 11260 Jungnang-gu 중랑구
7 11290 Seongbuk-gu 성북구
8 11305 Gangbuk-gu 강북구
9 11320 Dobong-gu 도봉구
10 11350 Nowon-gu 노원구
11 11380 Eunpyeong-gu 은평구
12 11410 Seodaemun-gu 서대문구
13 11440 Mapo-gu 마포구
14 11470 Yangcheon-gu 양천구
15 11500 Gangseo-gu 강서구
16 11530 Guro-gu 구로구
17 11545 Geumcheon-gu 금천구
18 11560 Yeongdeungpo-gu 영등포구
19 11590 Dongjak-gu 동작구
20 11620 Gwanak-gu 관악구
21 11650 Seocho-gu 서초구
22 11680 Gangnam-gu 강남구
23 11710 Songpa-gu 송파구
24 11740 Gangdong-gu 강동구
[ reached 'max' / getOption("max.print") -- omitted 225 rows ]
# 데이터프레임 형식과 동일하여 아래와 같이 속성테이블만 df로 추출 가능
# sigungu.as.df <- sigungu@data
불러온 이후에는 plot()
함수를 사용하여 간단하게 도시할 수 있다.
# 시각화
# 패키지명::함수()
# 위와 같은 형식으로 패키지를 명시하면 패키지를 불러오지 않더라도
# 패키지 내장 함수를 불러올 수 있다. 또한 동명의 패키지가 있어
# 시스템이 어느 패키지를 지정 못함으로 인해 발생하는 오류를 해결할 때도
# 이를 사용하면 해결이 가능함.
sp::plot(sigungu)
함수를 사용한 도시법 1
Raster files(.img)
R에서는 래스터 형식의 파일도 처리할 수 있다. raster
패키지는 해당 기능을 지원한다.
if (require("raster")) {
# 참: 패키지 존재
print("패키지있어유~")
} else {
# 거짓: 패키지 설치
print("패키지깔게유~")
install.packages("raster")
}
[1] "패키지있어유~"
library(raster)
다음은 raster
패키지의 raster()
함수를 사용하여 서울특별시 수치표고모델(DEM)을 불러오는 과정이다.
seoulDEM30 <- raster("./data/raster/DEM/seoul_dem.img") # 주의! 경로에 한글이나 띄어쓰기가 있으면 오류남!
# raster::plot() 사용
{ # 한번에 실행 가능한 중괄호
plot(seoulDEM30, # plot 대상(필수)
legend.args = list(text = 'Elevation (m)', # 범례 제목 넣기
side = 4, font = 2, line = 2.5, cex = 0.8)) # 범례 꾸미기 설정
title("서울시 수치표고모형", sub = crs(seoulDEM30), # 여러 타이틀 설정
xlab = "x(meter)", ylab = "y(meter)", # 여기서 crs()는 좌표계 반환
cex.main= 2, font.main= 4, col.main= "blue", # 타이틀 꾸미기 설정
cex.sub= 0.75, font.sub= 3, col.sub= "black")
# crs() 함수는 raster 패키지에 있음
# rgdal 패키지의 CRS()와 혼동 주의(대문자)
} # 괄호는 항상 닫아주기
함수를 사용한 도시법 2
4 R GIS
4.1 공간자료 다루기
4.1.1 좌표계 설정
ArcGIS
의 Define Projection
과 같은 내용이다.
우리나라 데이터 센터에서 제공하는 일부 셰이프 파일은 좌표 메타데이터 파일인 파일명.prj
파일이 없는 경우도 있다.
아래와 같이 좌표투영이 되어있지 않은 파일은 GIS 프로그램 상에 올릴 시 다음과 같이 올바르게 도시되지 않는다.
seoulemd <- readOGR(dsn = "./data/shp/행정동",
layer = "Z_SOP_BND_ADM_DONG_PG",
encoding = "UTF-8",
stringsAsFactors = FALSE,
verbose = FALSE)[c(1:424),] # 424행까지 - 서울시만 추출
# tmap RGIS-시각화 에서 다룸
library(tmap)
library(tmaptools)
# 64비트 R에서 'OpenStreetMap' 패키지 다루려면 64비트 자바 설치 필수 - 링크
# https://javadl.oracle.com/webapps/download/AutoDL?BundleId=245060_d3c52aa6bfa54d3ca74e617f18309292
library(OpenStreetMap)
# read_osm() 함수는 OpenStreetMap을 입력 공간자료의 범위로 잘라 줌
osm_seoul <- read_osm(seoulDEM30)
tm_shape(osm_seoul) + tm_rgb() + # 베이스 레이어 (맨 밑)
tm_shape(seoulemd) + tm_polygons(border.col="red", alpha = 0) # 상위 레이어
엥 어데갔누?
따라서 해당 자료 제작 시 어떠한 좌표 체계를 사용하였는지 파악하는게 중요하다.
좌표를 R
공간자료에 집어넣기 위해서는 PROJ.4
string(문자열) 형식을 알고 있어야 한다.
PROJ.4
string은 좌표계를 식별하는 간단한 방법이다. 이는 공간자료를 다루는 R
패키지에서 많이 사용된다.
일반적인 워크플로우는 자료를 제공하는 사이트 상에서 보통 알 수 있는 좌표 정보를 파악하고. 이를 가지고 ‘Spatialreference.org’ 웹 페이지에서 해당 좌표체계를 검색 후 Proj4
항목에 대한 정보를 아래와 같이 집어넣으면 된다.
아래의 예시는 구득 웹 사이트(국가공간정보포털 오픈마켓) 상에서 메타데이터를 확인하고, 지리원 표준 좌표계 중 하나인 ‘EPSG:5181’(중부원점, GRS80)로 좌표계를 PROJ.4
string 형식을 가지고 다음과 같이 정의하였다.
# 좌표계 정의
# CRS() 함수를 사용하여 폴리곤 공간자료 'seoulemd' 하위-
# 항목인 'proj4string' 항목에 다음과 같이 좌표계를 정의함.
# rgdal::CRS("proj.4 string"), raster::crs() 사용해도 무방
# proj4 오류 시 엔터(줄 바꿈) 지울 것
seoulemd@proj4string <- crs("+proj=tmerc +lat_0=38 +lon_0=127 +k=1 +x_0=200000 +y_0=500000
+ellps=GRS80 +towgs84=0.0,0.0,0.0,0.0,0.0,0.0,0.0 +units=m +no_defs")
# tmap RGIS-시각화 에서 다룸
tm_shape(osm_seoul) + tm_rgb() +
tm_shape(seoulemd) + tm_polygons(border.col="red", alpha = 0) # alpha = 불투명도
좌표계 정의가 올바르게 된 공간자료
정상적으로 중첩이 되는 것을 볼 수 있다.
이러한 과정이 불편하다면, 불러올 때 readOGR()
함수의 p4s
파라미터로 한번에 처리가 가능하다.
seoulemd <- readOGR(dsn = "./data/shp/행정동",
layer = "Z_SOP_BND_ADM_DONG_PG",
encoding = "UTF-8",
stringsAsFactors = FALSE,
verbose = FALSE,
p4s = "+proj=tmerc +lat_0=38 +lon_0=127 +k=1 +x_0=200000
+y_0=500000 +ellps=GRS80 +units=m +no_defs")[c(1:424),]
# 좌표계 확인
crs(seoulemd) # raster 패키지 CRS() 함수는 안 먹힘
Coordinate Reference System:
Deprecated Proj.4 representation:
+proj=tmerc +lat_0=38 +lon_0=127 +k=1 +x_0=200000 +y_0=500000
+ellps=GRS80 +units=m +no_defs
4.1.2 좌표계 변환
ArcGIS
의 Project
툴과 비슷한 기능이다. 타원체와 투영법이 다른 두 가지의 공간자료를 가지고 작업을 할 때 필수적으로 해야하는 작업이다.
가령, 아래와 같이 범위가 큰 래스터 자료를 사례지역으로 잘라내고 싶을 때 해당 래스터와 범위 자료가 서로 좌표체계가 다를 경우, 공간 연산이 불가능하다.
seoulgwanak <- subset(sigungu, SIG_KOR_NM == "관악구") # 관악구 경계만 추출
# Extract by mask(벡터 파일의 clip연산과 유사)
# 관악구 경계를 가지고 서울시 DEM을 관악구만 추출
# 작업이 행해지는 객체(Object) 대신
# 작업의 흐름을 강조하기 위해 '%>%'를 사용함
# '%>%'는 '파이프' 연산자라고 칭하고 'tidyverse' 패키지에 포함
# https://style.tidyverse.org/pipes.html <- 참고
DEMgwanak <- crop(seoulDEM30, extent(seoulgwanak), snap="out") %>%
mask(mask = seoulgwanak)
Error in h(simpleError(msg, call)): 함수 'mask'를 위한 메소드 선택시 인수 'x'를 평가하는데 오류가 발생했습니다: extents do not overlap
# 위 코드를 다음과 같이 쓸 수도 있음
# DEMgwanak <-mask(x = crop(seoulDEM30, extent(seoulgwanak), snap="out"), mask = seoulgwanak)
# 작업의 순서대로 코드를 짤 수 있는 장점이 있음
# 이전 작업의 결과물은 파이프로 다음 함수의 주요 변수로 우선 지정이 됨.
에러 메시지 상으로도 두 공간자료가 중첩되지 않는다고 나타난다.
따라서 이런 경우에는 좌표체계를 동일한 좌표체계를 사용하게끔 변환해줘야한다.
위에서 사용한 두 공간자료의 좌표체계는 다음과 같다.
crs(seoulgwanak) # EPSG:5179, UTM-K, GRS80
Coordinate Reference System:
Deprecated Proj.4 representation:
+proj=tmerc +lat_0=38 +lon_0=127.5 +k=0.9996 +x_0=1000000 +y_0=2000000
+ellps=GRS80 +units=m +no_defs
WKT2 2019 representation:
PROJCRS["PCS_ITRF2000_TM",
BASEGEOGCRS["ITRF2000",
DATUM["International Terrestrial Reference Frame 2000",
ELLIPSOID["GRS 1980",6378137,298.257222101,
LENGTHUNIT["metre",1]],
ID["EPSG",6656]],
PRIMEM["Greenwich",0,
ANGLEUNIT["Degree",0.0174532925199433]]],
CONVERSION["unnamed",
METHOD["Transverse Mercator",
ID["EPSG",9807]],
PARAMETER["Latitude of natural origin",38,
ANGLEUNIT["Degree",0.0174532925199433],
ID["EPSG",8801]],
PARAMETER["Longitude of natural origin",127.5,
ANGLEUNIT["Degree",0.0174532925199433],
ID["EPSG",8802]],
PARAMETER["Scale factor at natural origin",0.9996,
SCALEUNIT["unity",1],
ID["EPSG",8805]],
PARAMETER["False easting",1000000,
LENGTHUNIT["metre",1],
ID["EPSG",8806]],
PARAMETER["False northing",2000000,
LENGTHUNIT["metre",1],
ID["EPSG",8807]]],
CS[Cartesian,2],
AXIS["(E)",east,
ORDER[1],
LENGTHUNIT["metre",1,
ID["EPSG",9001]]],
AXIS["(N)",north,
ORDER[2],
LENGTHUNIT["metre",1,
ID["EPSG",9001]]]]
crs(seoulDEM30) # EPSG:32652, UTM 52N, WGS84
Coordinate Reference System:
Deprecated Proj.4 representation:
+proj=utm +zone=52 +datum=WGS84 +units=m +no_defs
WKT2 2019 representation:
PROJCRS["WGS_1984_UTM_Zone_52N",
BASEGEOGCRS["WGS 84",
DATUM["World Geodetic System 1984",
ELLIPSOID["WGS 84",6378137,298.257223563,
LENGTHUNIT["metre",1]]],
PRIMEM["Greenwich",0,
ANGLEUNIT["degree",0.0174532925199433]],
ID["EPSG",4326]],
CONVERSION["UTM zone 52N",
METHOD["Transverse Mercator",
ID["EPSG",9807]],
PARAMETER["Latitude of natural origin",0,
ANGLEUNIT["degree",0.0174532925199433],
ID["EPSG",8801]],
PARAMETER["Longitude of natural origin",129,
ANGLEUNIT["degree",0.0174532925199433],
ID["EPSG",8802]],
PARAMETER["Scale factor at natural origin",0.9996,
SCALEUNIT["unity",1],
ID["EPSG",8805]],
PARAMETER["False easting",500000,
LENGTHUNIT["meters",1],
ID["EPSG",8806]],
PARAMETER["False northing",0,
LENGTHUNIT["meters",1],
ID["EPSG",8807]]],
CS[Cartesian,2],
AXIS["easting",east,
ORDER[1],
LENGTHUNIT["meters",1]],
AXIS["northing",north,
ORDER[2],
LENGTHUNIT["meters",1]],
ID["EPSG",32652]]
관악구 경계는 GRS80
타원체의 UTM-K
좌표계를 가지고 있는데 반해 서울시 DEM은 WGS84
타원체의 UTM zone 52N
좌표계를 지니고 있다.
따라서 둘 중 하나의 좌표계를 다른 것과 동일하게 맞춰야 하는데 이 때 좌표계를 앞서 설명했던 Proj.4
string 형식으로 정의하여 관악구 경계를 DEM의 좌표계와 동일하게 변경하였다.
UTM52N <- CRS("+proj=utm +zone=52 +ellps=WGS84
+datum=WGS84 +units=m +no_defs") #EPSG:32652, UTM 52N, WGS84
gwanakUTM <- spTransform(seoulgwanak, UTM52N)
# crs 조회는 raster::crs()로만!
crs(gwanakUTM) #EPSG:32652, UTM 52N, WGS84
Coordinate Reference System:
Deprecated Proj.4 representation:
+proj=utm +zone=52 +datum=WGS84 +units=m +no_defs
WKT2 2019 representation:
PROJCRS["unknown",
BASEGEOGCRS["unknown",
DATUM["World Geodetic System 1984",
ELLIPSOID["WGS 84",6378137,298.257223563,
LENGTHUNIT["metre",1]],
ID["EPSG",6326]],
PRIMEM["Greenwich",0,
ANGLEUNIT["degree",0.0174532925199433],
ID["EPSG",8901]]],
CONVERSION["UTM zone 52N",
METHOD["Transverse Mercator",
ID["EPSG",9807]],
PARAMETER["Latitude of natural origin",0,
ANGLEUNIT["degree",0.0174532925199433],
ID["EPSG",8801]],
PARAMETER["Longitude of natural origin",129,
ANGLEUNIT["degree",0.0174532925199433],
ID["EPSG",8802]],
PARAMETER["Scale factor at natural origin",0.9996,
SCALEUNIT["unity",1],
ID["EPSG",8805]],
PARAMETER["False easting",500000,
LENGTHUNIT["metre",1],
ID["EPSG",8806]],
PARAMETER["False northing",0,
LENGTHUNIT["metre",1],
ID["EPSG",8807]],
ID["EPSG",16052]],
CS[Cartesian,2],
AXIS["(E)",east,
ORDER[1],
LENGTHUNIT["metre",1,
ID["EPSG",9001]]],
AXIS["(N)",north,
ORDER[2],
LENGTHUNIT["metre",1,
ID["EPSG",9001]]]]
DEMgwanak <- crop(seoulDEM30, extent(gwanakUTM), snap="out") %>%
mask(mask = gwanakUTM)
# tmap
tmap_mode("view")
tm_shape(DEMgwanak) +
tm_raster(alpha = 0.45) +
tm_shape(seoulgwanak) +
tm_polygons(border.col="red", alpha = 0)
4.1.3 위경도 좌표로 공간자료 생성
해당 문서에서 정제한 올리브영 자료는 2020년 7월 19일 기준이다.
해당 자료는 올리브영 매장안내에서 구득하였다.
oliveyoungXY <- read_csv("./data/Datasets/Oliveyoung/Oliveyoung.csv")
# noi는 관심매장으로 추가한 사람의 수
oliveyoungXY
# A tibble: 368 x 6
name addr ph.numb noi x y
<chr> <chr> <chr> <dbl> <dbl> <dbl>
1 은행사거리점 서울특별시 노원구 한글비석로 264 ~ 02-938-9~ 1278 127. 37.7
2 중계역점 서울특별시 노원구 동일로 1335 (상~ 02-930-2~ 518 127. 37.6
3 노원역사거리점 서울특별시 노원구 노해로 480 02-934-5~ 2365 127. 37.7
4 노원점 서울특별시 노원구 상계로 65 105호~ 02-935-5~ 1948 127. 37.7
5 홈플러스중계점 서울특별시 노원구 동일로204가길 1~ 02-948-6~ 526 127. 37.6
6 상계보람점 서울특별시 노원구 한글비석로 471 02-930-2~ 729 127. 37.7
7 창동점 서울특별시 도봉구 마들로11길 57 02-991-5~ 452 127. 37.7
8 공릉역점 서울특별시 노원구 동일로192길 74 ~ 02-948-8~ 1148 127. 37.6
9 창동역점 서울특별시 도봉구 노해로63길 84-16 02-908-5~ 1168 127. 37.7
10 노원공릉점 서울특별시 노원구 동일로 1083 02-948-1~ 294 127. 37.6
# ... with 358 more rows
주어진 좌표가 경위도 좌표(decimal degrees)이기 때문에 단위가 도(°)이다. 위경도 좌표를 가지고 포인트 공간자료를 제작할 때 평면 상에 투영되어 단위가 Meter인 투영좌표계(Projected Coordinate System, PCS)는 사용하지 못한다. 따라서 3차원 구 표면을 가지고 위치를 표현하며 단위를 도(°)로 가지는 지리좌표계(Geographic Coordinate System, GCS)를 사용해야 한다.
따라서 이번 예시에서는 WGS84
(EPSG:4326) 경위도 좌표를 사용하였다.
crsgcs <- crs("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs") # WGS84 GCS
oliveSP <- SpatialPointsDataFrame(oliveyoungXY[, 5:6], # df에서 x(경도), y(위도) 열 지정(5~6열)
oliveyoungXY, # 해당 df 지정
proj4string = crsgcs) %>% # 앞서 변수선언한 GCS
spTransform(crs(DEMgwanak)) # 앞서 다뤘던 관악구DEM 좌표계로 변경(PCS)
# %>% 파이프 복습
# 위 코드를 다음과 같이 쓸 수도 있음
# oliveSP <-spTransform(x = SpatialPointsDataFrame(olive[, 5:6], olive,proj4string = crsgcs),
# CRSobj = crs(seoulgu))
# 작업의 순서대로 코드를 짤 수 있는 장점이 있음
# 이전 작업의 결과물은 파이프로 다음 함수의 주요 변수로 우선 지정이 됨.
추후 다룰 tmap
패키지를 사용하여 도시하였다.
library(tmap)
library(leafem)
tmap_mode("view") # 상호작용지도
{
tm1 <- tm_shape(oliveSP) + tm_dots() # 공간자료 선언 + 표시 형식
lf <- tmap_leaflet(tm1) # (옵션) leafleat 기능 사용위한 변환
addMouseCoordinates(lf) # (옵션) 동적 지도에 좌표표시
}
4.1.4 테이블 Join
해당 자료는 서울시 주민등록인구 (구별) 통계에서 구득하였고, 일련의 과정을 통해 정제하였다.
공간자료의 속성 테이블(Attribute table)과 다른 데이터 프레임에 서로 분리되어 있는 데이터를 연결하여 하나의 공간자료로 출력해야 할 때 사용 하는 것이 조인(Join)이다.
먼저 기준이 될 서울시 폴리곤 공간자료이다.
# 시군구 셰입에서 서울만 추출
seoulGU <- subset(sigungu, SIG_CD <= 11740)
head(seoulGU@data)
SIG_CD SIG_ENG_NM SIG_KOR_NM
0 11110 Jongno-gu 종로구
1 11140 Jung-gu 중구
2 11170 Yongsan-gu 용산구
3 11200 Seongdong-gu 성동구
4 11215 Gwangjin-gu 광진구
5 11230 Dongdaemun-gu 동대문구
그리고 조인을 수행할 서울시 인구자료이다.
seoulgupop2020 <- read_csv("./data/Datasets/Population/20201stQGu.csv")
seoulgupop2020
# A tibble: 25 x 14
quarter GU HousHld TotlPop Male Female Domestc DomMale DomFmle Foreign
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 2020.1/4 종로구 74151 161984 78271 83713 151217 73704 77513 10767
2 2020.1/4 중구 63045 136469 66769 69700 126175 61839 64336 10294
3 2020.1/4 용산구 110895 246165 119961 126204 229579 110667 118912 16586
4 2020.1/4 성동구 135643 307193 149891 157302 299042 146300 152742 8151
5 2020.1/4 광진구 165287 365990 176226 189764 350417 169568 180849 15573
6 2020.1/4 동대~ 165279 362793 178202 184591 346156 171896 174260 16637
7 2020.1/4 중랑구 182220 400678 198122 202556 395619 196076 199543 5059
8 2020.1/4 성북구 193801 454532 218561 235971 442494 213926 228568 12038
9 2020.1/4 강북구 144805 316750 154141 162609 312985 152747 160238 3765
10 2020.1/4 도봉구 138595 333495 162774 170721 331238 161879 169359 2257
# ... with 15 more rows, and 4 more variables: ForMale <dbl>, ForFmle <dbl>,
# cap/hhd <dbl>, 65+ <dbl>
다음은 조인을 하는 과정이다. sp
패키지의 merge()
함수를 사용하였다.
# usage: sp::merge(x, y, by.x = "x기준열명", by.y = "y기준열명" ...)
seoulpopJOIN <- merge(seoulGU, seoulgupop2020 ,by.x ="SIG_KOR_NM", by.y = "GU")
head(seoulpopJOIN@data)
SIG_KOR_NM SIG_CD SIG_ENG_NM quarter HousHld TotlPop Male Female
23 종로구 11110 Jongno-gu 2020.1/4 74151 161984 78271 83713
24 중구 11140 Jung-gu 2020.1/4 63045 136469 66769 69700
21 용산구 11170 Yongsan-gu 2020.1/4 110895 246165 119961 126204
16 성동구 11200 Seongdong-gu 2020.1/4 135643 307193 149891 157302
Domestc DomMale DomFmle Foreign ForMale ForFmle cap/hhd 65+
23 151217 73704 77513 10767 4567 6200 2.04 28073
24 126175 61839 64336 10294 4930 5364 2.00 23794
21 229579 110667 118912 16586 9294 7292 2.07 39439
16 299042 146300 152742 8151 3591 4560 2.20 44728
[ reached 'max' / getOption("max.print") -- omitted 2 rows ]
tm_shape(seoulpopJOIN) +
tm_polygons(c("TotlPop","Domestc","Foreign","65+"))+
tm_facets(sync = TRUE, ncol = 2) # 움직임 동기화 / 열의 수
4.1.5 지도 대수(Map Algebra)
Normalized Difference Vegetaion Index(NDVI)
ArcGIS
의 Raster calculator
툴과 비슷한 기능이다.
R의 raster
패키지를 사용하면 위성영상의 활용도 충분히 수행할 수 있다.
다음의 예제는 Landsat 8 영상을 사용한다. 대기보정(Surface Reflectance, Collection 1)한 세종시 영상을 가지고 NDVI를 구하는 과정이다.
# 21년 3월 30일 세종시 LANDSAT8 자료의 밴드 수
raster("./data/raster/Landsat8/LC08_116035_20210330_clip.tif") %>% nbands()
[1] 9
# Layer stacked Raster로부터 Red, Near Infrared 밴드만 불러오기
Lsat8_RED <- raster("./data/raster/Landsat8/LC08_116035_20210330_clip.tif",band = 4)
Lsat8_NIR <- raster("./data/raster/Landsat8/LC08_116035_20210330_clip.tif",band = 5)
NDVI는 다음과 같은 식으로 구할 수 있으므로…
\[NDVI = \frac{NIR-RED}{NIR+RED}\] 위의 식을 R 코드로 작성하면 다음과 같음
#NDVI 계산
NDVI <- (Lsat8_NIR-Lsat8_RED)/(Lsat8_NIR+Lsat8_RED)
tmap_mode("view")
tm_shape(NDVI,raster.downsample = F) + # tm_shape
tm_raster(title = "Mar 30th 2021<br/>Sejong-si NDVI",midpoint = NA, palette = "RdYlGn",n = 10,style = "cont") # 범례 제목
Danger Zone
지도대수와 관련있는 내용은 아니지만 위성영상 자료 구득부터 분석까지의 과정을 R 안에서 가능하다는 것을 보이고자 넣어보았다.
# 설치 시 초기 Set-up 요함 아래 링크 참고
# https://r-spatial.github.io/rgee/articles/setup.html
library(rgee)
# Google Earth Engine 회원등록 필요(1~3일 소요)
# https://earthengine.google.com/signup/
rgee::ee_Initialize(drive = T,user = "dydgns0556@gmail.com",quiet = T)
# 사례지역 셰이프 불러온 후 earth engine 데이터로 만들기
sj <- sf::st_read("./data/shp/Si/sejong_si.shp") %>% sf_as_ee()
Reading layer `sejong_si' from data source
`E:\workspace\active\ComputerCartography(TA)\ex8_rev\webGIS\data\shp\Si\sejong_si.shp'
using driver `ESRI Shapefile'
Simple feature collection with 1 feature and 3 fields
Geometry type: POLYGON
Dimension: XY
Bounding box: xmin: 332770.7 ymin: 4030487 xmax: 357669.6 ymax: 4066915
Projected CRS: WGS 84 / UTM zone 52N
# 특정 일시 Landsat8 영상 선택 후 1~7번 밴드만 추출
LC08 <- ee$Image("LANDSAT/LC08/C01/T1_SR/LC08_116035_20210330")$
select(ee$List$sequence(0,8))
# Landsat영상 사례지역으로 자르기
aoi <- LC08$clip(sj) #aoi(Area of Interests)
#사례지역 확인하기(RGB true color)
Map$centerObject(sj, zoom = 12) # 지도 중앙 및 zoom level 설정
Map$addLayer(
eeObject = aoi, # 사례지역으로 자른 영상
visParams = list( # 시각화 파라미터
bands = c("B4", "B3", "B2"),## RGB에 할당할 밴드들
min = 0, # min val
max = 2^(12) # max val
),
name = "Mar 2021 (True colours)" # 레이어 명
)
# EE API 변수에서 local R변수로 불러오기
# 말 그대로 thumbnail, 분석용은 `ee_as_raster` 사용할 것
outras <- ee_as_thumbnail(
image = aoi,
region = sj$geometry()$bounds(),
dimensions = 1024,
vizparams = list(min = 0,
max = 2^(12),
bands = c("B4", "B3", "B2")),
raster = T)
- region parameters
sfg : POLYGON ((127.1277 36.40676 .... 6.73382, 127.1277 36.40676))
CRS : GEOGCRS["WGS 84",
DATUM["World Geodetic System 1984",
ELLIPSOID["WGS 84",6378137,298.257223563, .....
geodesic : FALSE
evenOdd : TRUE
Getting the thumbnail image ... please wait
# 좌표계 정의
crs(outras) <- "+proj=longlat +datum=WGS84 +no_defs"
# NA 값 0대신 NA로(배경 투명)
outras[outras <= 0] <- NA
# 정적인 지도 plot()과 유사
# plotRGB(outras, stretch = "lin")
# `leaflet`을 사용한 동적인 지도
library(leafem)
library(leaflet)
leaflet() %>%
addTiles(group = "OpenStreetMap") %>%
addRasterRGB(outras, 1,2,3, group = "True colours") %>%
addLayersControl(
#baseGroups = c("Satellite"),
overlayGroups = c("True colours"),
)
zona de peligro
# 진짜 Danger zone
# 산불 피해 지역 분류
# SVM Classification using Sentinel-2 composite.
## AoI 폴리곤으로 지정 - rectangle vertices
geometry <- ee$Geometry$Polygon(
list(
c(128.9833, 37.65),
c(128.9833, 37.55),
c(129.1, 37.55),
c(129.1, 37.65)
)
)
#L2C 데이터(필터조건-범위:폴리곤, 시간: 산불직후)
image <- ee$ImageCollection("COPERNICUS/S2_SR")$
filterBounds(geometry)$
filterDate("2019-04-20","2019-04-30")$
first()#4월 20일 데이터만 뽑기
# extract an image with the geometry mask
aoi <- image$clip(geometry)
# Display the result
Map$centerObject(geometry, zoom = 12)
Map$addLayer(
eeObject = aoi,
visParams = list(
bands = c("B4", "B3", "B2"),
min = 0,
max = 2^(12)
),
name = "Apr 2019 (True colours)"
) +
Map$addLayer(
eeObject = geometry
)
# Use these bands for prediction.
##all bands w/o atmosphiric detector
bands <- c("B2", "B3", "B4","B5","B6","B7", "B8","B11","B12")
# Manually created polygons.
## 수계 class - 0
water1 <- ee$Geometry$Rectangle(129.05, 37.64, 129.06, 37.63) # rectangle vertices
water2 <- ee$Geometry$Rectangle(128.984, 37.619, 128.988,37.618)
## 식생 class - 1
veget1 <- ee$Geometry$Rectangle(128.9837,37.6251, 128.986, 37.623)
veget2 <- ee$Geometry$Rectangle(129.05228,37.56383, 129.05833, 37.55921)
## 해빈 class - 2
beach1 <- ee$Geometry$Rectangle(129.07403, 37.60491, 129.07468, 37.60473)
beach2 <- ee$Geometry$Rectangle(129.0888, 37.59518, 129.08966,37.59469)
## 도시 class - 3
urban1 <- ee$Geometry$Rectangle(129.05612, 37.62045, 129.05897, 37.61923)
urban2 <- ee$Geometry$Rectangle(129.03256, 37.60757, 129.03406, 37.60702)
## 산불피해지역 class - 4
burnt1 <- ee$Geometry$Rectangle(129.04996, 37.60308, 129.05326, 37.59999)
burnt2 <- ee$Geometry$Rectangle(129.05876, 37.59954, 129.06502, 37.596280)
## 경작지 class - 5
crop1 <- ee$Geometry$Rectangle(129.02121, 37.61879, 129.02490, 37.61702)
crop2 <- ee$Geometry$Rectangle(129.08676, 37.58181, 129.09026, 37.57960)
# Make a FeatureCollection from the hand-made geometries.
polygons <- ee$FeatureCollection(c(
ee$Feature(water1, list(class = 0)),
ee$Feature(water2, list(class = 0)),
ee$Feature(veget1, list(class = 0)),
ee$Feature(veget2, list(class = 0)),
ee$Feature(beach1, list(class = 0)),
ee$Feature(beach2, list(class = 0)),
ee$Feature(urban1, list(class = 0)),
ee$Feature(urban2, list(class = 0)),
ee$Feature(burnt1, list(class = 1)),
ee$Feature(burnt2, list(class = 1)),
ee$Feature(crop1, list(class = 0)),
ee$Feature(crop2, list(class = 0))
))
# Get the values for all pixels in each polygon in the training.
training <- aoi$sampleRegions(
# Get the sample from the polygons FeatureCollection.
collection = polygons,
# Keep this list of properties from the polygons.
properties = list("class"),
# Set the scale to get Landsat pixels in the polygons.
scale = 10
)
# Create an SVM classifier with custom parameters.
classifier = ee$Classifier$libsvm(
kernelType = "RBF"
)
# Train the classifier.
trained = classifier$train(training, "class", bands)
# Classify the image.
classified = aoi$classify(trained)
# Display the classification result and the input image.
## visual parameter
geoviz_image = list(bands = c("B8", "B4", "B3"),min = 0, max = 2^(12))
geoviz_class = list(min = 0, max = 1, palette = c("green","red"))
Map$centerObject(geometry, zoom = 12)
Map$addLayer(
eeObject = aoi,
visParams = geoviz_image,
name = "False color image"
) +
Map$addLayer(
eeObject = classified,
visParams = geoviz_class,
name = "Burned area"
) +
Map$addLayer(
eeObject = polygons,
name = "Training polygons"
)
R Google Earth Engine API(rgee
패키지)에 대해 좀 더 알고 싶으면 메일로 문의
4.2 시각화(tmap)
먼저 다음의 코드를 사용하여 패키지를 설치하도록 하자.
if (require("tmap")) {
# 참: 패키지 존재
print("패키지있어유~")
} else {
# 거짓: 패키지 설치
print("패키지깔게유~")
install.packages("tmap")
}
[1] "패키지있어유~"
library(tmap)
4.2.1 기초 문법
load(url("https://github.com/mgimond/Spatial/raw/main/Data/Sample1.RData"))
회색의 기본적인 지도를 만들려면 다음을 입력한다.
tmap_mode("plot") # 일반 그림 지도
tm_shape(s.sf) + tm_polygons()
tm_shape()
함수는 공간자료를 패키지로 불러오는 역할을 하며 공간자료는 vector 형식이나 raster 형식이 될 수 있다. tm_polygons
함수는 tmap
패키지에서 어떻게 공간자료가 도시되는지 표현하는 여러 명령 중 하나이다.
tm_polygons
함수에 col=
파라미터를 넣어서 단순히 단색으로 채워 넣을 수도, 속성 값에 따라 색상의 변화를 줄 수도 있다.
tm_shape(s.sf) + tm_polygons(col="Income", border.col = "white") # border.col <- 경계선 색상
여기서 우리의 목표는 웹 상에 올려서 웹 GIS를 만드는 것이기 때문에 다음과 같은 코드로 html 형식의 지도를 만들 것이다.
tmap_mode("view")
는 정적인(static) 지도가 아닌 상호작용이 가능한 웹 문서에서 많이 쓰이는 html 형식의 지도를 제공한다.
기존 정적인 지도를 동적으로 바꾸기 위해서는 tmap_mode("view")
함수를 앞에 명시해주면 된다.
tmap_mode("view") # 상호작용 지도 <-> tmap_mode("plot")
tm_shape(s.sf) + tm_polygons(col="Income", border.col = "red")
4.2.2 Tmap을 활용한 지도 예시
Point 형식
AQstations <- readOGR(dsn = "./data/shp/point",
layer = "AQstations",
encoding = "UTF-8",
use_iconv=TRUE, #esri shapefile 설정
stringsAsFactors = FALSE,
verbose = FALSE)
names(AQstations@data) <- c("측정일시", "측정소명", "이산화질소농도(ppm)", "오존농도(ppm)", "이산화탄소농도(ppm)", "아황산가스(ppm)", "미세먼지(㎍/㎥)", "초미세먼지(㎍/㎥)","주소", "지점명", "일일교통량(대)", "lon", "lat")
AQstations@data[,1] <- lubridate::ymd(AQstations@data[,1]) # 측정일시 날짜형식으로 변환
traffic <- readOGR(dsn = "./data/shp/point",
layer = "traffic",
encoding = "UTF-8",
use_iconv=TRUE, #esri shapefile 설정
stringsAsFactors = FALSE,
verbose = FALSE)
names(traffic@data) <- c("지점번호","지점명","경도","위도")
tmap_mode("view")
lung <- tmap_icons("./fig/lung.png")
car <- tmap_icons("./fig/car.png")
tm_shape(AQstations) +
tm_symbols("측정소명", id="측정소명", popup.vars = names(AQstations@data), size = 0.5,shape = lung, legend.col.show = FALSE)+
tm_shape(traffic) +
tm_symbols("지점명", id="지점명", popup.vars = names(traffic@data),size = 0.5, shape = car,legend.col.show = FALSE)
범례
대기질 관측소
교통정보 수집지점
Polyline 형식
tm_shape(rail.sf) + tm_lines(col = "FULLNAME",id="FULLNAME",lwd=4)
Polygon 형식
Tmap
패키지에서는 다음과 같이 데이터를 여러 클래스로 결합하는 분류법을 제공한다.
- 등개수 분류법(quantile)
- Jenks 알고리듬
- 등간격 분류법(equal interval)
- 평균-표준편차 분류법(standard deviation)
classInt::classIntervals()
의 style에서 제공하는 다양한 분류법 사용 가능(도움말 찾아볼 것)
seoulDongPOP <- read_csv("./data/Datasets/Population/20201stQDong.csv")
merge(x = seoulemd, y = seoulDongPOP , "ADM_DR_CD" ) %>%
tm_shape() +
tm_polygons(title = "2020년 1/4분기 <br>서울시 행정동별 등록인구 <br>(Jenks 분류법)",
id="ADM_DR_NM.x",
col = "TotlPop",
popup.vars = c("GU","ADM_DR_NM.x","TotlPop","Domestc","Foreign"),
style = "jenks",
n = 7,
palette = "BuPu" #tmaptools::palette_explorer()
)
Facet 형식
data("World", package = "tmap") # tmap 기본 공간자료 - sf 형식
tm_shape(World) +
tm_polygons(c("HPI", "gdp_cap_est"),
palette = list("RdYlGn", "Purples"),
style = c("pretty", "fixed"), n = 7,
breaks = list(NULL, c(0, 500, 2000, 5000, 10000, 25000, 50000, Inf)),
title = c("Happy Planet Index", "GDP per capita")) +
tm_style("natural",
earth.boundary = c(-180, -87, 180, 87))
.
Raster 형식
tmap_mode("view")
# tm_basemap에 적용 가능한 배경지도는 다음의 링크 잠고
# https://leaflet-extras.github.io/leaflet-providers/preview/
tm_basemap(c("Stamen.Terrain","OpenStreetMap.HOT")) + # 배경지도(basemap)
tm_shape(seoulDEM30) + # tm_shape
tm_raster(n=10^5, # 간격 수
palette = "-Spectral", # 색 그라데이션 tmaptools::palette_explorer() 참고
style = "cont", # ArcGIS Symbology의 Classification. 간격 스타일 설정
title = "Seoul DEM 30M<br/>Elevation(Meter)") # 범례 제목
# 자세한 내용은 패키지 로드 후 Console에 ?tm_raster
4.2.3 결과물 저장
제작한 결과물을 웹 상에 호스팅하여 볼 수 있게 만들면 실습 목표인 webGIS 제작을 하는 것이다.
그러기 위해서는 저장 시 html
형식으로 해야 하는데 다음과 같은 코드를 사용한다.
# 서울시 구 예시
tmexp <- tm_shape(seoulpopJOIN) + tm_polygons()
# tmap_save(tm = tmexp, filename = "./seoulGU.html") # 경로/파일명.html 예시는 상대경로
하지만 위 함수로는 4 by 4 형식 등의 facets 지도를 추출 할 수 없다. 따라서 다음과 같이 RStudio에서 html 저장을 해주도록 하자.
RStudio 상에서 Viewer 창에 나타난 html 지도 저장 방법
- Export를 누른다.
- Save as Web Page…를 누른다.
- 저장 창이 뜨면 원하는 위치에 저장한다.
5 Github에 호스팅하기
앞서 만든 html
형식의 지도를 Github
에 호스팅하면 다음과 같이 URL을 통해 어디서든지 볼 수 있는 나만의 지도가 완성된다.
Github에 html 문서 호스팅하는 방법
먼저 사용 가능한 이메일 주소를 입력 후 회원가입을 진행한다.
위와 같이 회원 정보를 입력한다. 세부사항은 다음과 같다.
이메일 주소. 이미 전 단계에서 입력됨
비밀번호
사용자이름(닉네임)
Github
의 업데이트를 이메일로 받아볼 것인지 여부(Y/N)자동가입 방지 단계(CAPTCHA)
회원가입이 완료되었으면 로그인 후 위와 같은 화면이 나온다. 화면 우상단의 ‘Create repository’ 클릭
위와 같이 설정 후 저장소 생성. 세부 내용은 다음과 같음
repository 이름
공개 여부
해당 repository 웹 페이지의 메인 화면
생성
생성 후 위와 같은 repository 화면에서 설정 탭으로 들어간다.
메인 설정 화면에서 좌측 메뉴 중 ‘Pages’ 항목을 찾아 선택한다.
Pages 메뉴에서 다음과 같이 설정한다
Branch: 선택
Branch를 main으로 설정
저장
repository의 메인 화면으로 나오기
위 과정을 마치면 웹 주소 하나를 얻을 수 있다. 해당 주소에 업로드한 html이 호스팅이 되는 것이다.
repository의 메인 화면으로 왔으면 위와 같이 Upload files를 누른다.
올린 뒤 주소를 통해 결과물을 확인해보자.(접속이 가능하기까지 약 3분 소요)
https:// 1
.github.io/ 2
/ 3
- username
- repository 명
- 업로드한 파일 명
과제 8
Q1. R
을 사용하여 html
형식의 상호작용이 가능한 지도를 제작하시오. (8점)
- 팀 과제인 만큼 앞서 제시한 것들도 좋지만, 다른 시각화 기법을 사용해보기를 권장
- e.g)
Q2. 앞서 만든 지도를 Github
에 호스팅한 후, 배포한 지도 URL을 제출하시오. (2점)
유의사항
- 제출 시한은 12월 5일 일요일 23시 59분 59초
-
제출에 필요한 모든 파일을 압축하여, 과제 #차_조명.zip 형식으로 제출.
- e.g.) 과제 8차_X조.zip
- 지도를 배포한 Github 주소 제출. 주소는 eTL 자체 문서편집기 사용.
- 조장이 위 두 가지를 제출하며, 팀원들은 문서편집기로 소속 조 명시할 것.
-
과제 평가 관련
- 배점은 문제마다 상이.
- 부분 점수 있음.
- 지각 제출 시 주마다 –1점씩 감점.
-
실습 및 과제에 관한 문의 사항은 구체적으로 기술하여 메일로 문의할 것.
- “buffer가 안돼요.”등의 모호한 질문보다는 구체적인 error 사항 또는 화면 캡처 등 그 상황을 이해할 수 있을만한 설명이 필요함.
시스템 및 패키지 정보
CPU / RAM
"CPU"
[1] "CPU"
benchmarkme::get_cpu()
$vendor_id
[1] "GenuineIntel"
$model_name
[1] "Intel(R) Xeon(R) CPU E3-1231 v3 @ 3.40GHz"
$no_of_cores
[1] 8
"RAM"
[1] "RAM"
benchmarkme::get_ram()
34.3 GB
Session & Package Info
sessionInfo()
R version 4.1.0 (2021-05-18)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19044)
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=C
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] leaflet_2.0.4.1 rgee_1.1.0 leafem_0.1.6
[4] OpenStreetMap_0.3.4 tmaptools_3.1-1 tmap_3.3-2
[7] raster_3.5-2 rgdal_1.5-27 sp_1.4-6
[10] forcats_0.5.1 stringr_1.4.0 dplyr_1.0.7
[13] purrr_0.3.4 readr_2.1.0 tidyr_1.1.4
[16] tibble_3.1.6 ggplot2_3.3.5 tidyverse_1.3.1
[19] rmdformats_1.0.3 knitr_1.36
loaded via a namespace (and not attached):
[1] googledrive_2.0.0 colorspace_2.0-2 anicon_0.1.0
[4] ellipsis_0.3.2 class_7.3-19 benchmarkme_1.0.7
[7] base64enc_0.1-3 fs_1.5.0 dichromat_2.0-0
[10] httpcode_0.3.0 rstudioapi_0.13 proxy_0.4-26
[13] farver_2.1.0 bit64_4.0.5 fansi_0.5.0
[16] lubridate_1.8.0 xml2_1.3.2 codetools_0.2-18
[19] doParallel_1.0.16 jsonlite_1.7.2 rJava_1.0-5
[22] broom_0.7.10 dbplyr_2.1.1 rgeos_0.5-8
[25] png_0.1-7 compiler_4.1.0 httr_1.4.2
[28] backports_1.3.0 lazyeval_0.2.2 assertthat_0.2.1
[31] Matrix_1.3-4 fastmap_1.1.0 gargle_1.2.0
[34] cli_3.1.0 s2_1.0.7 leaflet.providers_1.9.0
[37] htmltools_0.5.2 tools_4.1.0 gtable_0.3.0
[40] glue_1.5.0 geojson_0.3.4 wk_0.5.0
[43] V8_3.6.0 Rcpp_1.0.7 cellranger_1.1.0
[46] jquerylib_0.1.4 vctrs_0.3.8 crul_1.1.0
[49] iterators_1.0.13 leafsync_0.1.0 crosstalk_1.2.0
[52] lwgeom_0.2-8 xfun_0.28 ps_1.6.0
[55] rvest_1.0.2 lifecycle_1.0.1 XML_3.99-0.8
[58] klippy_0.0.0.9500 terra_1.4-20 jqr_1.2.2
[61] scales_1.1.1 vroom_1.5.6 hms_1.1.1
[64] parallel_4.1.0 RColorBrewer_1.1-2 curl_4.3.2
[67] yaml_2.2.1 reticulate_1.22 sass_0.4.0
[70] stringi_1.7.5 highr_0.9 maptools_1.1-2
[73] foreach_1.5.1 e1071_1.7-9 benchmarkmeData_1.0.4
[ reached getOption("max.print") -- omitted 39 entries ]
installed.packages()[names(sessionInfo()$otherPkgs), "Version"]
leaflet rgee leafem OpenStreetMap tmaptools
"2.0.4.1" "1.1.0" "0.1.6" "0.3.4" "3.1-1"
tmap raster rgdal sp forcats
"3.3-2" "3.5-2" "1.5-27" "1.4-6" "0.5.1"
stringr dplyr purrr readr tidyr
"1.4.0" "1.0.7" "0.3.4" "2.1.0" "1.1.4"
tibble ggplot2 tidyverse rmdformats knitr
"3.1.6" "3.3.5" "1.3.1" "1.0.3" "1.36"