1 R기초

1.1 기본 개념

1.1.1 컴퓨터

컴퓨터는 범용계산기계다. ’범용’이란 수행할 수 있는 과제가 특정 영역에 국한되지 않는다는 의미다. 즉, 컴퓨터는 인간처럼 모든 영역의 과제를 수행할 수 있다. 컴퓨터는 인간과 달리 수행해야 하는 과제를 인간이 지정해야 한다. 인간은 해결해야 하는 문제를 스스로 설정한다.

컴퓨터는 하드웨어와 소프트웨어로 이뤄져 있다.

하드웨어 중앙처리장치(CPU), 저장장치, 입출력기기, 통신장치 등으로 이뤄져 있다.

1.1.1.1 하드웨어

범용계산기계(컴퓨터)를 작동하도록 하는 기계부품이다.

  • 중앙처리장치: 과제 수행에 필요한 계산 수행
  • 저장장치: 계산에 필요한 자료를 임시로 저장하는 내장메모리와 자료를 장기간 저장하는 외부저장장치로 구분한다. 내장메모리는 과제 수행에 필요한 자료를 올려 놓는 작업대에 해당한다. HDD 등 외부저장창치는 자료를 장기간 저장하는 일종의 창고로서 도서관의 서고에 해당한다.
  • 입출력기기: 키보드 마우스 모니터 등 입력과 출력을 처리하는 기기다.
  • 통신장치: 인터넷 등에 연결하는 기기

1.1.1.2 소프트웨어

범용계산기계(컴퓨터)의 작동에 필요한 신호체계다. 알고리듬과 자료(data)구조로 이뤄져 있다.

  • 알고리듬(algorithm): 문제를 푸는 방도. 기계가 수행해야 할 특정 과제를 순서대로 알려주는 구체적인 지시의 집합이다. 알고리즘이라고도 하지만, 알고리듬이 더 정확한 표현이다. algorism은 페르시아의 수학자 알-콰리즈미의 이름에서 유래한 용어로서 ’숫자를 이용한 연산’이란 의미다.

  • 자료구조: 데이터를 조직하는 특정한 방법. 예를 들어, 벡터(vector)는 자료의 값(value)을 나열한 자료구조고, 데이터프레임(data frame)은 자료의 값을 행(row)과 열(column)의 테이블 구조에 저장하는 자료구조다.

1.1.1.3 프로그래밍 언어

알고리듬을 표현하는 방식. 컴퓨터언어라고도 한다. 기계어, C, 자바, 파이썬, R 등이 있다. 프로그래밍은 알고리듬대로 소프트웨어를 만드는 작업이다.

  • 기계어: 컴퓨터가 직접적으로 이해할 수 있는 언어.

    • 가장 “낮은” 수준. 0과 1로만 이뤄짐
  • Fortran: 최초의 높은 수준의 범용 프로그래밍 언어. 인간의 언어에 유사

    • 1954년 IBM의 John Backus 개발
  • C: 1970년대 개발이후 가장 널리 사용됐던 언어. compiled 언어

  • Java: 컴파일 한번만 하면 모든 플래폼에서 실행. compiled 언어

컴파일드(Compiled)언어 소스코드를 기계어로 미리, 한번에 번역한다.

예를 들어, C언어의 경우 소스코드(예: sample.c)를 실행프로그램(예: sample.exe)으로 컴파일해 사용한다.

  • 소스코드 sample.c
    #include(studio.h)
    int main()
    {
      print("Hello World!"\n)
      return 0;
    }
  • 컴파일 gcc sample.c-o sample.exe

  • 기계어: sample.exe

    000111110000011111000000000011111111110101010101010000000000000100000000000000000001111111100000000000000000000000000000

C나 Java 등 컴파일드 언어(complied language)는 코드를 한번에 기계어로 변환한다. 한번에 변환하므로 실행이 빠르고 간편하다. 독립 소프트웨어 개발에 유리하다.

인터프리티드(interpreted)언어 프로그래밍 코드를 한줄씩 해석(기계어로 번역)해 실행한다. 한줄씩 해석하므로 코드 수정이 용이하다. 명령프롬프트 ( > )에 명령어를 한번에 하나씩 입력해서 실행한다. 바로 실행하므로 데이터분석에 편리하다.

  • JavaScript: 웹페이지 개발 등에 널리 사용. Java와 다른 언어

  • Python: 높은 수준의 범용, 인터프리티드 언어

    • C/C++, Java보다 더 높은 수준. 인간이 이해하기 더 수월하다.
  • R: 데이터분석에 특화된 높은 수준의 인터프리티드 언어

1.1.2 R

통계학자에 의해 개발된 오픈소스 컴퓨터프로그래밍언어다.

1.1.2.1 R 약사

  • 1976년 John Chambers, R 전신인 S언어 발표

    • Bell Labs
  • 1994년 Ross Ihaka & Robert Gentleman R 발표

    • 뉴질랜드 오클랜드 대학
  • 1997년 GNU project에 포함

  • 현재 R Development Core Team이 개발 및 유지

1.1.2.2 R의 장점

  • 데이터 분석에 필요한 모든 기법 구현 가능

  • 최신 통계 기법 신속 반영

  • 뛰어난 그래픽 처리

  • 데이터 탐색과 분석에 용이

  • 다양한 플래폼에서 작동(윈도, 리눅스, 유닉스, 맥 등)

  • 다양한 데이터 소스에 접근 가능

    • 텍스트파일부터 데이터베이스관리시스템, 통계패키지 등
    • 웹페이지, 소셜미디어 사이트 등 다양한 온라인 데이터 서비스에 직접 접근

1.2 R시작하기

R을 이용하는 방법에는 로컬컴퓨터(자신의 컴퓨터)와 클라우드를 이용하는 방법 2가지가 있다.

  1. 컴퓨터에 R을 설치해 이용
  • 장점: 내 컴퓨터에서 사용하므로 편의성이 높다.
  • 단점: 컴퓨터 사양이 낮으면 매우 불편하다.
  1. 클라우드에서 R 이용
  • 장점: 컴퓨터 사양이 낮아도 브라우저만 있으면 된다.
  • 단점: 매번 패키지를 설치해야 한다.

R Studio 클라우드구글 코랩 등이 R클라우드다. 구글 코랩의 기본값은 파이썬이지만, 이 주소로 연결하면 R이 사용언어로 설정된다.

1.2.1 로컬컴퓨터에 설치하기

  1. R project사이트에서 접속 이 주소(https://cloud.r-project.org)로 직접 접속하거나, 구글에서 “r project” 검색

  2. 본인의 운영체제에 맞는 R다운로드 후 설치. R을 설치하고 실행하면 콘솔 창이 열린다. > 프롬프트가 뜨면 정상이다 (Figure: 1.1).

R 콘솔

Figure 1.1: R 콘솔

1.2.2 R의 기능구현

함수와 객체를 통해 기능을 구현한다.

1.2.2.1 객체(object)

값(value)을 할당한 것. 데이터, 함수, 그래프, 분석결과 등을 할당해 객체를 생성한다. 언어로 따지면 명사에 해당한다.

아래 예시는 hello_v라는 객체에 “Hello World!”라는 문자벡터를 할당해 객체를 만들었다. 벡터(vector)는 데이터의 구조중 가장 기본이 되는 구조다.

hello_v <- "Hello World!"

할당할 때는 <-기호를 사용한다. =를 사용해도 된다. 다른 프로그래밍 언어에서는 객체를 생성할 때 값을 할당하기 위해 =를 주로 사용한다. R프로그래밍에서는 <-를 주로 사용한다. =를 이용해 할당하면 오류가 생기는 경우가 가끔 있다.

할당할 객체를 오른쪽에 놓고 싶을 때는 ->를 이용한다. 사고의 흐름과 일치해 코딩과정이 효과적이다.

"Hello World!" -> hello_v

생성된 객체는 내장 메모리에 저장된다. 객체를 따로 저장하지 않으면, R세션을 종료시 생성된 객체는 사라진다. 객체를 다시 사용하려면 외부저장장치(예: HDD)에 파일로 저장해야 한다.

생성한 객체의 내용을 보는 방법은 다양하지만, 가장 기본적인 방법은 프롬프트에 객체명을 입력하는 것이다. 프롬프트(아래 화면에서는 ## [1]로 표시)에 객체에 저장된 내용이 나타난다. 프롬프트에 표시된 숫자 [1]은 현재 표시된 화면에서 첫번째 출이라는 의미다.

hello_v
## [1] "Hello World!"

1.2.2.2 함수(function)

특정 동작을 수행하는 컴퓨터프로그램의 일부. 알고리듬이 함수에 구현돼 있다. 언어로 따지면 동사에 해당한다. 예를 들어, print()는 “출력하다”는 동작을 지정한 함수다. 앞서 만든 “hello_v” 객체의 내용을 화면에 출력하려면 다음과 같이 쓴다.

print(hello_v)
## [1] "Hello World!"

+는 ’더하기 하라’는 동작을 지정한 함수이고, mean()은 ’산술평균을 계산하다’는 동작을 지정한 함수다. q()는 R을 종료하라는 동작을 지정한 함수다.

37과 73을 더한 값을 구해보자.

37 + 73
## [1] 110

37과 73의 산술평균값을 구해보자. 먼저 37과 73을 c()함수로 벡터 데이터구조에 저장한 다음, R에서 산술평균을 구하는 mean()함수로 계산한다.

c(37, 73) -> num_v
mean(num_v)
## [1] 55

벡터를 num_v에 할당하지 않고, 곧바로 mean()함수의 인자(argument)로 투입해도 된다.

mean(c(37, 73))
## [1] 55

함수의 계산 대상이 되는 요소를 인자(argument 혹은 parameter)라고 한다. 다양한 인자를 이용해 함수를 보다 정밀하게 사용할 수 있다. 언어로 치면 목적어, 보어, 수식어 등에 해당한다. 함수는 서술어에 해당. 뒤에서 상술.

R에는 크게 세 종류의 함수가 있다.

  • 내장 함수: R을 설치하면 기본적으로 함께 제공되는 함수. R함수라고 줄여 말하기도 한다. 산술평균을 구하는 mean(), 표준편차를 구하는 sd(), 벡터를 만드는 c()함수 등이 있다.

  • 패키지 함수: 추가로 설치하는 패키지에서 제공하는 함수. 패키지는 R함수, 데이터, 완성된 코드를 정리해 종합한 꾸러미(package)다. 모아 놓았기 때문에 라이브러리(library)라고도 한다. R의 내장 함수 install.packages("패키지이름")으로 설치하고 library(패키지이름)로 R환경에 탑재해서 사용한다. 많이 사용하는 패키지로는 데이터를 다루는데 사용하는 dplyr 패키지, 엑셀파일을 R환경으로 이입(import)하는 readxl패키지가 있다. readxl패키지의 read_excel()함수를 이용하려면 먼저 install.packages("readxl")readxl패키지를 컴퓨터에 설치하고, library(readxl)로 R환경에 탑재해야 한다. 패키지에 대해서는 뒤에서 상술한다. :::

  • 사용자 함수: 사용자가 자신의 편의를 위해 만든 맞춤형 함수다. 예를 들어, 평균, 중간값, 표준편차를 한번에 계산하고 싶으면 mean() median(), sd() 등 3개 함수를 모아 하나의 함수로 만들면 사용자 함수가 된다. function()함수를 이용해 만든다.

숫자 두개를 더하는 사용자함수를 만들어 보자.

add_f <- function(x, y){
  add_v <- x + y
  return(add_v)
}

함수를 만들기 위해서는 3가지 요소를 지정해야 한다.

  1. 함수의 이름. 여기서는 add_f라고 이름을 부여했다.

  2. 함수에 투입할 인자(argument). 숫자 두개를 더하므로, 인자를 x, y 두개 지정했다. (인자의 명칭으로 반드시 “x”나 “y”를 사용할 필요는 없다. 어느 문자를 써도 무관. 다만 일관성있게 사용).

  3. 실행할 코드. function()함수 다음에 { }사이에 실행할 코드를 기입한다. 마지막 줄의 return()은 함수가 계산한 결과를 반환(return)해 보여주는 동작을 지정한 함수다.

이렇게 만든 사용자 함수를 이용해 37과 73을 더해 보자.

add_f(37, 73)
## [1] 110

산술평균과 표준편차를 한번에 구할 수 있는 함수를 만들어, 1부터 37까지의 연속한 숫자 37개의 평균과 표준편차를 구해보자. 1부터 37까지의 연속하는 값은 :를 이용한다 (1:37).

des_f <- function(x) {
  M <- mean(x)
  SD <- sd(x)
  des_v <- c(M, SD) # 산출된 값이 2개이므로 이를 하나의 벡터로 묶었다.
  return(des_v)
}

des_f(1:37)
## [1] 19.00000 10.82436
1.2.2.2.1 숫자와 문자의 차이

R은 숫자와 문자를 구분한다. 문자는 " "안에 넣어 숫자와 구분한다. R이 처리하는 방식도 다르다. 숫자와 문자를 합하는 방법을 통해 비교해 볼수 있다.

x에 숫자 10을 할당하고, y에 숫자 20을 할당해 x와 y를 더하는 코드를 작성해보자.

x <- 10
y <- 20 
x + y
## [1] 30

이번에는 x에 문자 10을 할당하고, y에 문자 30을 할당해 x와 y를 더하는 코드를 작성해 보자. 문자이므로 숫자에 따옴표 " "를 넣었다.

x <- "10"
y <- "20" 
x + y

Error in x + y : 이항연산자에 수치가 아닌 인수입니다라는 오류메시지가 나타난다. 숫자에 따옴표" "로 감싸 문자형이 됐는데, 숫자처럼 취급했기 때문이다. (작은 따옴표' '로 감싸도 문자형이 된다.)

문자 요소는 paste()함수로 결합한다.

paste(x, y, sep = " ")
## [1] "10 20"

1.2.2.3 인자(argument 또는 parameter)

함수 실행에 필요한 데이터, 실행방식 등을 지정하는 내용이다. 함수는 동사, 객체는 명사에 해당한다면, 인자는 목적어나 수식어 등에 해당한다. 예를 들어, 아래의 코드에서 sep =인자를 투입해 x와 y의 값이 결합하는 작동하는 방식을 지정한다. 아래 코드는 x와 y의 값 사이에 "과 "를 넣으라는 의미가 된다.

paste(x, y, sep = "과 ")
## [1] "10과 20"

함수에는 기본적으로 지정된 기본값(default)이 있다. paste()함수의 sep =인자 기본값(default)은 " "이다. 기본값은 따로 지정하지 않아도 된다. 즉, paste(x, y)paste(x, y, sep = " ")의 산출 결과는 동일하다.

1.2.2.4 기술문(statement)

함수, 객체, 인자로 구성된 일종의 문장이다. 일련의 기술문을 작성하는 것을 “코딩”한다고 한다.

기술문 사례

nd_v <- rnorm(n = 500, mean = 10, sd = 4)

  • rnorm(): 함수

    • 값의 개수(n)을 지정해 ’정규분포(normal distribution)를 만들라’는 명령을 컴퓨터에 전달하는 함수.
  • n = 500, mean = 10, sd = 4 : 인자.

    • 500개의 값으로 평균 10, 표준편차 4을 구성하라는 설정.
  • nd_v : 객체

    • 정규분포를 이루는 평균 10, 표준편차 4을 이루는 500개의 값이 할당된 객체.

1.2.2.5 결과의 재사용

분석의 산출물을 객체에 할당해 재사용한다. 아래 코드는 lm()함수를 이용해 mtcars라는 데이터의 wt(무게: 독립변수 혹은 예측변수)로 mpg(연료효율: 종속변수 혹은 산출변수)를 예측하는 회귀분석을 하는 기술문이다. (변수(variable), 회귀분석(regression analysis)에 대해서는 추후 자세하게 배운다.)

lm(mpg ~ wt, data = mtcars)

이 분석 결과는 화면에 나타날 뿐이다. 그 결과를 다시 사용하려면 객체에 할당한다.

  • mtcars는 R에 내장된 데이터다. (단수 복수에 주의한다. 오류의 주된 원인 중 하나가 복수 s누락)
  • ~는 공식(formula)을 만들때 사용하는 기호다.
  • mpg ~ wt는 공식(formula)이다. “wt가 독립변수(투입요소: input 또는 predictor)로서 종속변수(산출요소: output)인 mpg를 예측한다”는 의미다.

아래 코드는 fit에 기술문을 할당한 다음, fit의 내용을 summary()함수로 요약해 출력하고, plot()함수로 도표를 그리라는 내용이다.

fit <- lm(formula = mpg ~ wt, data = mtcars)
summary(fit)
plot(fit) 

1.2.2.6 코멘트 #

코딩할 때 코딩한 내용에 대해 사람이 참조하기 위해 기록을 남길 필요가 있다. #부호가 있으면 컴퓨터엑 해석(interpret)할 필요가 없다는 의미가 돼, #부호 다음의 내용은 컴퓨터가 무시하고 처리하지 않고 내용을 그대로 화면에 제시하기만 한다.

x <- rnorm(5) # 이런 식으로 다음에 적힌 글자는 화면에 표시만 한다. 

1.2.2.7 도움말

R의 모든 함수와 인자를 기억해 사용할 수 없다. 도움말을 이용해야 한다. 일반적인 도움말은 help.start()함수를 이용한다. 개별 함수에 대한 도움말은 help("함수")?함수의 형식으로 입력한다.

  • c()함수에 대해 알고 싶으면

    • ?c
    • help("c")
  • mean()함수의 도움말은:

    • ?mean
    • help("mean")

1.2.3 작업공간(workspace)

현재 실행중인 R의 작업환경이다. 사용자가 생성한 객체(object)가 저장돼 있는 곳이다. 컴퓨터의 하드디스크가 아니라 메모리에 올려져 있다. R을 종료하면 함께 사라진다.

R을 종료할때 “Save workspace image?”라는 창이 뜬다. 작업공간에 저장된 객체는 이미지파일로 하드디스크에 저장할 것인지 묻는 메시지다. ’예’를 선택하면 현재 작업공간의 객체들이 모두 .RData파일로 저장된다. 이 이미지 파일의 내용은 R을 다시 기동하면 작업공간으로 다시 올려진다.

ls()함수는 작업공간의 객체의 목록(list)을 보여준다. 조금 전에 객체 x, y, fit을 만들었으므로 ls()함수를 콘솔에 입력하면 이 세 객체가 화면에 나타난다.

ls()

rm()함수는 작업공간의 객체를 제거(remove)한다. 객체 x, y, fit를 제거하고 ls()함수를 실행해보자. x, y, fit을 제외한 R환경에 탑재돼 있는 객체의 목록이 나타난다.

rm(x, y, fit)
ls()

1.2.4 중요: 작업디렉토리(working directory)

R이 기본값으로(by default) 파일을 읽고 저장하는 디렉토리 (또는 폴더)로서 하드디스크 공간이다.

  • getwd() : 현재의 작업디렉토리를 알려준다. wd는 working directory의 약자. 즉, getwd는 working directory를 get하라는 의미.

자신의 작업디렉토리를 파악해보자.

getwd() 
  • 주의: 윈도는 드라이브명 다음에 역슬래시C:\를 사용하지만, R에서는 정슬래시 C:/를 이용한다.
  • setwd() : 지정한 폴더를 작업디렉토리로 설정. working directory를 set하라는 의미다.

1.2.4.1 연습

  1. C드라이브의 data폴더를 작업디렉토리로 설정하시오.
  • 주의: " "와 아포스트로피(apostrophe) “ ”는 다른 기호다. 다른 문서에서 코드 복사해 사용할때 주의.
setwd("C:/data")

만일 작업디렉토리를 설정하고자 하는 폴더가 드라이브에 없으면?

컴퓨터의 탐색기를 열어 해당 폴더를 만들거나, R콘솔에서 폴더 생성 함수dir.create()로 해당 폴더를 만든다.

’newfolder’라는 폴더를 C드라이브에 만들려면 다음과 같이 한다.

dir.create("C:/newfolder")
  1. C드라이브에 newdir이란 폴더를 생성하고, 이 폴더를 작업디렉토리로 설정하시오. 설정된 작업디렉토리를 확인하시오.
dir.create("C:/newdir")
setwd("C:/newdir")
getwd()
  • list.files() 현재의 작업디렉토리에 있는 파일과 폴더 목록 보여준다.

  • ls()는 작업공간의 객체 목록

주의: 작업공간(working space)은 메모리에 생성된 작업환경이고 작업디렉토리(working directory)는 HDD(하드디스크)에 생성된 폴더다.

유용한 기능

  • 키보드의 control키와 L키를 함께 누르면 콘솔 화면이 정리된다.
  • 키보드의 상하 방향키를 이용하면 이전에 입력했던 명령어를 다시 사용할 수 있다.

1.2.5 함수 정리

# 객체의 내용 화면에 출력
print() 
# 도움말
help()

# 작업공간의 객체 목록
ls()
# 작업공간의 객체 삭제
rm()

# 작업디렉토리 확인
getwd()
# 작업디렉토리 설정
setwd()
# 하드디스크에 폴더 생성
dir.create()
# 작업디렉토리의 파일과 폴더 목록 표시
list.files()

# 패키지 설치
install.packages()
# 패키지 탑재
library()

# 사용자 함수 생성
function()
# 문자 결합
paste()  
# 벡터 생성
c()

# 산술평균
mean() 
# 표준편차
sd()
# 값의 갯수(n)을 지정해 정규분포를 이루는 값 생성
rnorm()
# 선형회귀분석 계산
lm()
# 통계치 등 요약
summary()
# 도표 생성
plot()

1.3 IDE(통합개발환경: Integrated Development Environment)

R과 같은 프로그램언어를 보다 효율적으로 사용할 수 있도록 해주는 도구가 IDE다. 코드 편집기외에 다양한 부가기능이 있다. R의 대표적인 IDE가 RStudio다. 파이썬의 파이참에 해당한다.

1.3.1 RStudio 설치

구글에서 ’rstudio’를 검색하거나 이 링크 R Studio Desktop Free에서 다운로드 받아 설치한다.

설치한 다음 아래처럼 실행되면 설치에 성공한 것이다 (Figure 1.2). 화면에 3개의 창틀이 열려 있는데, 각 창을 pane(창틀)이라고 한다.

  • 왼쪽에 보이는 ’Console’이라고 된 창이 R을 실행했을 때 코드를 입력했던 콘솔 창이다. R의 콘솔과 동일하므로 사용법도 같다.

  • 오른쪽 위의 창이 작업공간이다. 메모리에 생성된 작업환경(Working envorionment).

  • 오른쪽 아래 창은 작업디렉토리. 파일이 저장돼 있는 하드디스크.

R 콘솔

Figure 1.2: R 콘솔

1.3.2 프로젝트 만들기

작업을 할 때 반드시 프로젝트로 관리애 해야 하는 것은 아니나, 프로젝트로 만들어 작업을 관리하는 것이 상당히 유용하고 편리하다.

  • 상단 왼쪽 위에 있는 File을 클릭하면 드롭다운 메뉴가 열린다. New Project를 클릭하면 아래 창이 열린다 (Figure 1.3).
R 프로젝트 만들기

Figure 1.3: R 프로젝트 만들기

위 그림에서 New Directory를 클릭하면 열리는 창에서 Empty Project를 선택하면 아래 창이 열린다. Browse... 버튼 클릭해 프로젝트 파일 설치할 디렉토리 선택하고, 그 아래에 생성할 디렉토리 명을 Directory name:에 입력한다. 아래 그림은 “E:/data/elearning”폴더를 선택한 화면이다 (Figure 1.4).

디렉토리 이름 정하기

Figure 1.4: 디렉토리 이름 정하기

예를 들어, Directory name:에 ’git2015’라고 입력하고, 아래 Create Project 버튼을 클릭하면, “E:/data/elearning”아래 ’git2015’란 폴더가 생성되면서 “E:/data/elearning/git2015”가 작업디렉토리가 된다 (Figure 1.5).

  • 콘솔 창에 작업디렉토리가 표시돼 있다.
  • 오른쪽 위의 작업공간 위에 새로 만든 프로젝명이 보인다.
  • 오른쪽 아래 작업디렉토리에 새로 만든 프로젝트 파일이 생성돼 있다.
R 프로젝트 생성

Figure 1.5: R 프로젝트 생성

1.3.3 편집창 열기

IDE를 사용하는 하는 이유 중 하나가 편집기(Editor)를 사용하기 위해서다. 콘솔에서는 한번에 한줄만 입력해 실행하지만, 편집창에서는 코드를 여러줄을 입력해 실행할 수 있다. 아래 그림의 화살표가 가리키는 아이콘을 클릭하면 열리는 창에서 R Script를 선택하거나, 단축키로 Ctrl + Shift + N을 이용한다. 또는 상단메뉴 File을 클릭하면 열리는 드롭다운 메뉴에서 New File 선택 (Figure 1.6).

R 편집창 열기

Figure 1.6: R 편집창 열기

아래처럼 편집창이 열리면 RStudio를 이용한 코딩 준비가 된 것이다 (Figure 1.7).

R 편집기

Figure 1.7: R 편집기

편집창에 코드를 입력하면 탭의 Untitled가 빨간색으로 변한다. 디스크 모양 아이콘 클릭해 파일 이름을 지정해 저장한다. 예를 들어, 2_createData라고 파일명을 지정하면 확장자가 .R인 파일 2_createData.R이 작업디렉토리에 생긴다. 오른쪽 아래 작업디렉토리에서 생성된 파일을 확인할 수 있다 (Figure 1.8).

R 파일 저장

Figure 1.8: R 파일 저장

1.3.4 코드 실행

편집창에서 마우스 커서가 있는 줄의 코드를 실행하는 방법은 다음과 같다.

  • 편집창에서 콘트롤 + 엔터

  • RStudio 편집창 화면에서 Run아이콘 클릭 (Figure 1.9).

R 코드 실행

Figure 1.9: R 코드 실행

여러 줄의 코드를 동시에 실행하려면 실행하려는 코드를 마우스로 드랙해 설정한 다음, 콘트롤 + 엔터키 혹은 - RStudio 편집창 화면에서 Run아이콘 클릭 (Figure 1.10).

R 코드 여러 줄 실행

Figure 1.10: R 코드 여러 줄 실행

1.3.5 한글사용 설정

한글을 사용하기 위해서는 인코딩을 해야 하는데, 운영체자가 윈도인 경우 CP949라는 마이크로소프트 고유의 확장완성형 인코딩을 이용한다. 이를 보편적으로 사용하는 UTF-8로 변경한다.

  • RStudio 상단메뉴 Tools를 클릭
  • 드롭다운 메뉴가 열리면 Global option 선택 (Figure 1.11).
  • Options 창이 열리면 ’Default text encoding 을 UTF-8으로 설정한다.
R 코드 여러 줄 실행

Figure 1.11: R 코드 여러 줄 실행

R스튜디오 사용법을 정리한 요약본(cheat sheet)은 여기서 다운로드 받을 수 있다. 전반적인 기능이 잘 정리돼 있다.

1.4 패키지(Package)

패키지는 R함수, 데이터, 완성된 코드를 정리해 종합한 꾸러미다. 라이브러리(library)라고도 한다. 패키지를 R환경에 올리는 함수가 library()인 이유다. require()도 패키지를 R환경에 올리는 함수이나 library()와는 달리, TRUEFALSE값을 산출한다. if()함수를 이용한 조건문에서 사용할 수 있다.

패키지::함수와 같은 방식을 이용해도 패키지의 함수를 이용할 수 있다. 아래 예문은 psych패키지의 headTail()함수 이용.

예: psych::headTail(df)

sessionInfo()함수를 이용해 R환경에 올려진 패키지와 버전을 확인할 수 있다.

패키지 버전만 확인하고 싶으면 packageVersion("패키지명")을 이용한다.

R Studio에서 버전을 확인하는 방법은 다음과 같다.

Tools -> Check for Package Updates ...

패키지를 설치할 때는 RStudio를 관리자 권한으로 실행해야 제대로 설치된다. 윈도가 보안정책을 강화했기 때문이다.

1.4.1 rtools

윈도에서 R의 다양한 패키지를 설치하고 사용하는데 필요한 패키지다. (맥이나 리눅스에서는 설치 불필요.)

  1. CRAN의 rtools페이지에 접속한다.

  2. 설치된 R버전과 일치하는 버전의 rtools를 다운로드받는다. 예를 들어, R이 4.0대 버전이면 rtools40을 설치한다.

  • rtools는 다른 패키지와 달리 install.packages()함수로 설치하지 않고, 설치파일을 컴퓨터에서 직접 실행해 설치한다.
  1. 설치할때 경로변경하지 말고 C:/Rtools에 설치한다. 설치과정에서 Add rtools to system PATH가 체크돼 있는지 확인한다.

1.4.2 tidyverse

정돈된 세계를 구성해 R을 한층 뛰어난 프로그래밍 언어로 만들어준 패키지다. (tidy를 직역하면 “깔끔한”이지만, tidyverse의 취지에 맞게 tidy를 “정돈된”으로 번역한다. )

정돈된 세상에 대해서는 한국통계학회 소식지 2019년 10월호에 실린 “데이터사이언스 운영체계 tidyverse 참조.

tidyverse는 정돈된 세상(tidy + universe)이란 의미의 종합패키지다. “정돈된 세계(tidyverse)”안에서는 코딩작업을 직관적이고도 일관성있게 할 수 있다. 해들리 위컴(Hadley Wicham)이 제시한 “정돈된 데이터 원리(tidy data principle)”에 따라 구성한 세계관이다. tidyverse패키지를 설치하면 ggplot2, dplyr, tidytext, lubridate 등 다수의 유용한 패키지가 함께 설치된다.

먼저 install.packages()함수를 이용해 tidyverse 패키지를 설치하고, library()함수를 이용해 현재의 R환경에 올려 패키지를 사용할 수 있도록 하자.

if(!require(tidyverse))tidyverse 패키지의 설치 여부의 조건에 따라 install.packages("tidyverse")가 실행되도록 한 조건문이다.

tidyverse 설치돼 있지 않다면 FALSE가 반환되나, 부정을 의미하는 !가 앞에 있으므로, TRUE가 전달돼 install.packages("tidyverse")를 실행하게 된다.

반대로, tidyverse 설치돼 있다면 TRUE가 반환되나, 부정을 의미하는 !가 앞에 있으므로, FALSE가 전달돼 install.packages("tidyverse")를 실행하지 않게 된다.

if(!require(tidyverse)) install.packages("tidyverse")
## 필요한 패키지를 로딩중입니다: 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.1     v forcats 0.5.1
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(tidyverse)

설치하면 -- Attaching packages --라는 메시지가 뜨며 아래 8종의 패키지 목록이 보인다. 이 8종의 패키지는 library(tidyverse)를 통해 tidyverse패키지를 현재의 R환경에 올리면 함께 R환경에 올라가는 부착된 패키지다. 즉, 아래 8개 패키지를 library()로 개별적으로 올리지 않아도 R환경에서 사용할 수있다.

  • ggplot2 시각화 도구모음. 그래픽의 문법에 기초

  • dplyr 데이터 조작. 일종의 공구상자

  • tidyr 데이터 정돈. 데이터를 정돈하는 함수 제공

  • readr 데이터 이입. 행과 열이 있는 데이터(예: csv, tsv, fwf) 이입(import)

  • purr 함수형프로그래밍(functional programming) 도구모음

  • tibble 데이터프레임의 현대적 양식

  • sringr문자형 데이터(string) 작업 도구 모음

  • forcats 데이터유형(type)이 요인(factor)일때 발생하는 문제해결 도구모음.

아래의 패키지는 tidyverse와 함께 설치되지만 library(패키지명)로 따로 R환경에 올려야 사용할 수 있는 패키지다.

  • hms housr와 time 데이터 처리 도구 모음

  • lubridate date와 times 데이터 처리 도구 모음

  • httr 웹 API

  • rvest 웹 스크레핑

  • readxl xls ghrdms xlsx 파일 이입

  • haven SPSS, SAS, STATA 파일 이입

  • jasonlite JSON

  • xml2 XML

  • modelr 파이프라인안에서 모델링

  • broom 모델을 tidydata로

1.5 데이터의 유형(data type)

데이터는 값(value)의 성격에 따라 다양한 유형으로 구분할 수 있다. 컴퓨터가 처리하는 방식이 다르기 때문에 이 구분은 중요하다. typeof()함수와 class()함수로 자료의 유형을 알수 있다. typeof()는 원시자료형(낮은 수준의 데이터 유형)을, class()는 높은 수준의 데이터 유형을 알려준다.

1.5.1 숫자형(numeric)

  • 정수형(integer): 1, 2, 3, 4, …
    • 정수형임을 명확하게 표기하기 위해 숫자 뒤에 L을 추가한다: 1L, 2L, 3L, …
  • 실수형(double): 1.12, 2.22, 3.14, 4.15, …

1.5.2 논리형(logical)

  • TRUE, 거짓 FALSE
  • TRUET, FALSEF로 표기 가능
  • 주의: “True,” “true” 등은 따옴표 안에 있으므로 논리형이 아니라 문자형.

1.5.3 문자형(character/string)

  • “1” , “2” , “3” , …
  • “TRUE,” “True,” “true,” …
  • “일,” “이,” “삼,” “사,” …
  • “남자,” “여자,” …
  • “rose,” “pink,” …

1.5.4 특수한 값(value)

1.5.4.1 NA

Not Available의 약어. 즉 결측값(missing value)이다. 데이터의 값(value)이 없다는 의미의 값(value)이다. 논리형이다. 결측값 여부는 is.na()함수를 이용한다.

NA
## [1] NA
is.na(NA)
## [1] TRUE
typeof(NA)
## [1] "logical"
class(NA)
## [1] "logical"

1.5.4.2 NULL

값 자체의 부재. NA는 값이 없다는 의미의 값이므로 값으로서 존재한다. 반면, NULL은 값 자체가 없다는 의미이므로 값으로서 존재하지도 않는다.

NULL
## NULL
is.na(NULL)
## logical(0)
typeof(NULL)
## [1] "NULL"
class(NULL)
## [1] "NULL"

1.5.4.3 NaN

’Not a Number’다. 즉, 숫자가 아니라는 의미지만 숫자형이다.

0/0
## [1] NaN
typeof(0/0)
## [1] "double"
class(0/0)
## [1] "numeric"

1.5.4.4 Inf

무한(infinity). 숫자형이다. 무한이나 양의 무한(Inf)과 음의 무한(-Inf) 등 양과 음의 방향이 모두 있다.

1/0
## [1] Inf
typeof(1/0)
## [1] "double"
class(1/0)
## [1] "numeric"

1.6 데이터구조

데이터가 저장된 데이터구조는 다양하다. 데이터를 책이라고 한다면, 데이터구조는 책을 보관하는 책장이나 서랍 캐비닛 등 에 비유할 수 있다. R에서 주로 사용하는 데이터 구조는 벡터(vector), 데이터프레임(dataframe), 리스트(list) 등 3가지다. 이외에도 매트릭스(matrix)와 어레이(array)가 있다. 5가지 데이터구조를 그림으로 표현하면 다음과 같다 (Figure: 1.12).

정확하게는 벡터를 아토믹벡터(atomic vector)와 제네릭벡터(generic vector)로 구분할 수있다. 아토믹벡터가 일반적으로 말하는 벡터다. 제네릭벡터는 리스트(list).

데이터 구조

Figure 1.12: 데이터 구조

1.6.1 벡터 c()

1차원의 데이터구조다. 개별 값(요소)를 1차원의 공간에 배치하는 데이터구조다. c()함수로 벡터를 만든다. ‘c’는 combine 혹은 concatenate로서 값들을 ’결합하다’ 혹은 ’연결시키다’는 의미다.

‘사과,’ ‘배,’ ‘오렌지’ 등 3개 요소를 벡터에 저장해 ’fruit_v’에 할당해보자.

fruit_v <- c('사과', '배', '오렌지')

저장하는 데이터의 유형에 따라 벡터의 종류 결정된다.

  • 숫자형 데이터로만 이뤄졌으면 숫자벡터
    • 실수형(double) 벡터: c(1, 2, 3)
    • 정수형(integer) 벡터: c(1L, 2L, 3L)
  • 논리형 데이터로만 이뤄졌으면 논리벡터
    • c(TRUE, FALSE)
  • 문자형 데이터로만 이뤄졌으면 문자벡터
    • c("1", "TRUE", "F", "포도", "apple")
    • " "' '로 값의 앞뒤를 감싸면 문자형이 된다.

주의: 벡터를 요소를 다양한 유형으로 구성하면 단일 유형으로 강제 변환(coerce)한다.

c(1, "1")
## [1] "1" "1"

숫자형(numeric)은 “double(실수형)”과 “integer(정수형)”로 구분한다. 실수형은 소숫점이 있고, 정수형은 소숫점이 없다.

num_v <- c(1, 2, 1, 2)
typeof(num_v)
## [1] "double"
class(num_v)
## [1] "numeric"

정수임을 명확하게 표현하기 위해서 1L 30L처럼 숫자 뒤에 L을 붙인다.

int_v <- c(1L, 2L, 1L, 2L)
typeof(int_v)
## [1] "integer"
class(int_v)
## [1] "integer"

1.6.1.1 요인(factor)

요인은 문자벡터인것처럼 보이지만 본질은 숫자벡터인 데이터의 구조다. 범주형(category)데이터를 다룰 때 사용하는 데이터 구조다. 예를 들어, 성(sex)이라는 범주형 데이터는 ’남자’와 ’여자’라는 속성을 갖고 있는데, 이때, ’남자’와 ’여자’라는 데이터의 속성을 문자형이 아니라 요인으로 처리하는 것이 효율적일 때가 있다.

예를 들어 보자. “male,” “female,” “female,” “male” 등 4개 값을 벡터로 만들어 sex_v에 할당하면, sex_v는 문자벡터가 된다. 4개의 문자요소가 생성된다.

  • typeof()함수는 낮은 수준의 자료형(원시자료형)을 제시한다.
  • class() 함수는 높은 수준의 자료형(자료구조 등)을 제시한다.
sex_v <- c("male", "female", "female", "male")
typeof(sex_v)
## [1] "character"
class(sex_v)
## [1] "character"

문자벡터를 factor()함수로 요인으로 만들면 ’male female female male ’이라는 글자는 그대로 보이나, " "가 사라진 것을 알수 있다. typeof()로 유형을 확인하면 정수(integer)라고 제시한다. 컴퓨터내부에서 female과 male을 각각 숫자(1과 2)로 처리했기 때문이다. 정수 1과 2에 대해 각각 female과 male이라는 “이름”을 부여한 셈이다. 이때 정수 1과 2에 부여된 값을 “이름”이라고 하지 않고 “level”이라고 한다. 즉, 문자 “female”을 1로 처리하고, ’female’이란 이름(level)에 부여하고, 문자 “male”은 2로 처리하고, ’male’이란 이름(level)을 부여한 것이다.

factor(sex_v)
## [1] male   female female male  
## Levels: female male
typeof(factor(sex_v))
## [1] "integer"
class(factor(sex_v))
## [1] "factor"

문자벡터뿐 아니라 숫자벡터로 요인으로 만들어 처리하면 효율적인 경우가 많다. 숫자로 돼 있어도 범주로 처리해야 하는 경우가 있기 때문이다. 숫자벡터인 num_vfactor()함수로 요인으로 바꿔보자. 유형은 정수(integer)이나 클래스는 요인(factor)이다.

num_v <- c(1, 2, 1, 2)
factor(num_v)
## [1] 1 2 1 2
## Levels: 1 2
typeof(factor(num_v))
## [1] "integer"
class(factor(num_v))
## [1] "factor"

1.6.1.2 중요: 부분선택(subsetting)

객체에 할당된 요소 일부만 부분적으로 선택(subsetting)할 수 있다. 부분선택(subsetting)은 데이터를 다루는데 매우 중요하니 잘 숙지해야 한다.

’fruit_v’에 할당된 세개의 값에는 위치가 숫자로 부여돼 있다. 따라서 그 위치에 대한 숫자로 해당 요소만 부분선택(subset)할 수 있다. 첫번째 요소를 부분선택 해보자.

  • R은 인덱싱할 때 첫번째 요소를 ‘1’에서 시작한다. (파이썬 등 다른 프로그래밍언어는 ’0’에서 시작). 즉, R은 인간의 직관대로 첫번째 요소는 ’1,’ 두번째 요소는 ’2’가 된다.
fruit_v <- c('사과', '배', '오렌지')
fruit_v[1]
## [1] "사과"

첫번째와 세번째 요소를 부분선택하려면 숫자벡터를 만들어 실행하면 된다.

fruit_v[c(1, 3)]
## [1] "사과"   "오렌지"

특정 요소를 제외하고 부분선택하려면 -기호를 이용한다. fruit_v에서 첫번째와 세번째 요소를 제외해 부분선택해보자.

fruit_v[-c(1, 3)]
## [1] "배"

연습

  1. 문자 ’참가자1, 참가자2, 참가자3’으로 이뤄진 문자벡터를 만들어 id_v에 할당하시오.
id_v <- c("참가자1", "참가자2", "참가자3")
  1. 숫자 ’32, 33, 45’로 이뤄진 숫자벡터를 만들어 age_v에 할당하시오
age_v <- c(32, 33, 45)
  1. 논리값 ’TRUE, FALSE, TRUE’로 이뤄진 논리벡터를 만들어 status_v에 할당하시오.
status_v <- c(TRUE, FALSE, TRUE)
  1. 숫자 ’60, 56, 50’으로 이뤄진 숫자벡터를 만들어 weight_v에 할당하시오.
weight_v <- c(60, 56, 30)
  1. 숫자 ’167, 160, 155’로 이뤄진 숫자벡터를 만들어 height_v에 할당하시오.
height_v <- c(167, 160, 155)

1.6.2 데이터프레임 data.frame()

행과 열로 구성된 2차원의 데이터구조다. 1차원 데이터구조인 벡터를 모아 만든다. data.frame()함수로 만든다. 벡터를 모아 데이터프레임의 열(column)로 투입한다.

앞서 만든 문자벡터, 숫자벡터, 논리벡터 5개를 이용해 데이터프레임을 만들어 ’df’에 할당해 보자.

df <- data.frame(id_v, age_v, status_v, weight_v, height_v)

summary()함수로는 각 변수(열)의 값에 대한 요약을 볼수 있다.

summary(df)
##      id_v               age_v        status_v          weight_v    
##  Length:3           Min.   :32.00   Mode :logical   Min.   :30.00  
##  Class :character   1st Qu.:32.50   FALSE:1         1st Qu.:43.00  
##  Mode  :character   Median :33.00   TRUE :2         Median :56.00  
##                     Mean   :36.67                   Mean   :48.67  
##                     3rd Qu.:39.00                   3rd Qu.:58.00  
##                     Max.   :45.00                   Max.   :60.00  
##     height_v    
##  Min.   :155.0  
##  1st Qu.:157.5  
##  Median :160.0  
##  Mean   :160.7  
##  3rd Qu.:163.5  
##  Max.   :167.0

str()함수는 데이터구조를 보여준다. ’structure’의 준말이다.

str(df)
## 'data.frame':    3 obs. of  5 variables:
##  $ id_v    : chr  "참가자1" "참가자2" "참가자3"
##  $ age_v   : num  32 33 45
##  $ status_v: logi  TRUE FALSE TRUE
##  $ weight_v: num  60 56 30
##  $ height_v: num  167 160 155

“‘data.frame’: 3 obs. of 5 variables:”이라고 요약해 준다. 3개 행(row)과 5개 열(column)로 이뤄진 데이터프레임이란 의미다.

“obs.”는 observation의 준말이다. 자료를 수집하면 행에는 개별 사례를 투입하고 변수를 열에 투입하기 때문에 행은 “obs.” 열을 “variables”이라고 표현했다 (Figure: 1.14).

행렬 구조의 데이터프레임

Figure 1.13: 행렬 구조의 데이터프레임

데이터프레임을 엑셀같은 스프레드시트 방식의 행렬로 보고 싶으면 View()함수를 이용한다. 별도의 창에서 행렬로 정렬된 데이터프레임이 열린다 (Figure: 1.14).

View(df)
View()함수로 보는 데이터프레임

Figure 1.14: View()함수로 보는 데이터프레임

데이터프레임 열이름의 기본값은 열벡터의 이름이 그대로 사용된다. 별도로 이름을 부여할수도 있다.

df <- data.frame(ID = id_v, 
                 age = age_v, 
                 status = status_v, 
                 weight = weight_v, 
                 height = height_v)
str(df)
## 'data.frame':    3 obs. of  5 variables:
##  $ ID    : chr  "참가자1" "참가자2" "참가자3"
##  $ age   : num  32 33 45
##  $ status: logi  TRUE FALSE TRUE
##  $ weight: num  60 56 30
##  $ height: num  167 160 155

1.6.2.1 부분선택(subsetting)

데이터프레임은 열벡터(column vector)로 이뤄져 있기 때문에 [ ]로 부분선택하면 해당 열이 부분선택된다. 부분선택된 열은 데이터프레임 구조를 유지한다.

df[2]    # `df`데이터프레임의 2번째 열 부분선택. 
##   age
## 1  32
## 2  33
## 3  45
df[2:4]  # `df`데이터프레임의 2~4번째 열 부분선택
##   age status weight
## 1  32   TRUE     60
## 2  33  FALSE     56
## 3  45   TRUE     30

데이터프레임은 행과 열로 이뤄져 있으므로, 부분선택할 때 행와 열을 나눠 지정할 수 있다.

  • n행 m열 선택 : df[n, m]
df[1, ]        # `df` 데이터프레임의 1행 부분선택
##        ID age status weight height
## 1 참가자1  32   TRUE     60    167
df[c(1,2), ]    #  df` 데이터프레임의 1행과 2행 부분선택
##        ID age status weight height
## 1 참가자1  32   TRUE     60    167
## 2 참가자2  33  FALSE     56    160
df[ ,2]        # `df` 데이터프레임의 2열 부분선택 (벡터구조로 산출)
## [1] 32 33 45
df[ ,c(2,3)]   # `df` 데이터프레임의 2열과 3열 부분선택 (데이터프레임으로 산출)
##   age status
## 1  32   TRUE
## 2  33  FALSE
## 3  45   TRUE
df[2,c(3:5)]   # `df` 데이터프레임의 2행과 3~5열 부분선택
##   status weight height
## 2  FALSE     56    160
  • 주의: 행과 열을 구분해 부분 선택할 때 단일 열만 부분선택하는 경우 부분선택된 결과의 데이터구조를 구분할 수 있어야 한다.
df[2]  # 2번째 열이 데이터프레임으로 부분선택
##   age
## 1  32
## 2  33
## 3  45
df[,2] # 2번째 열이 벡터로 부분선택
## [1] 32 33 45

데이터프레임은 열벡터(열을 구성하는 벡터)들의 합이므로, $기호와 열의 이름을 이용해 부분선택할 수 있다. $기호를 이용해 ’ID’열과 ’height’열을 열의 이름으로 부분선택해보자.

df$ID
## [1] "참가자1" "참가자2" "참가자3"
df$height
## [1] 167 160 155

열 부분선택은 dplyr패키지의 select()함수를 이용하면 편리하다. dplyr패키지는 tidyverse패키지와 함께 설치되고 탑재된다.

다음 코드는 select()함수를 이용해 열을 선택하는 사례다.

다른 패키지에서 같은 함수 명을 이용하는 경우가 있다. 다른 패키지의 select()함수와 혼동을 피하기 위해 dplyr::select()처럼 명시적으로 dplyr패키지의 select()함수를 사용한다고 기술해야 할때도 있다.

  • select()함수의 다양한 용법은 설명서 참조.
select(df, ID, age)        # ID와 age열 선택
##        ID age
## 1 참가자1  32
## 2 참가자2  33
## 3 참가자3  45
select(df, status:height)  # status열부터 height열까지 순서대로 모두 포함해 선택
##   status weight height
## 1   TRUE     60    167
## 2  FALSE     56    160
## 3   TRUE     30    155
select(df, -c(ID, age))    # ID열과 age열만 제외하고 선택
##   status weight height
## 1   TRUE     60    167
## 2  FALSE     56    160
## 3   TRUE     30    155

dplyr패키지의 filter()함수를 이용하면 행을 부분선택할수 있다.

  • filter()함수의 다양한 용법은 설명서 참조.

  • 주의: =<-와 같은 의미로 ’할당하다’가 된다. “같다”는 의미는 ==다.

ID열의 ’참가자1’과 같은 행에 있는 행을 선택해 보자.

filter(df, ID == "참가자1") 
##        ID age status weight height
## 1 참가자1  32   TRUE     60    167

!기호는 ’~을 제외하고’라는 의미가 된다. ID열에서 “참가자1”과 같은 행의 행을 제외하고 부분선택해 보자.

filter(df, !ID == "참가자1")
##        ID age status weight height
## 1 참가자2  33  FALSE     56    160
## 2 참가자3  45   TRUE     30    155

dplyr사용법요약: dplyr 사용법을 정리한 요약본(cheat sheet)은 여기서 다운로드 받을 수 있다. 전반적인 기능이 잘 정리돼 있다.

1.6.3 리스트 list()

리스트는 다양한 구조의 데이터를 담을 수 있는 일종의 서랍장과 같은 데이터구조다.

먼저 아래의 경우처럼 벡터를 구성하는 요소의 수가 다른 경우부터 살펴보자.

data.frame(a = 1:3, b = 1:4)

Error in data.frame(a = 1:3, b = 1:4) : arguments imply differing number of rows: 3, 4라며 행의 수가 같지 않으면 오류가 생긴다. 데이터프레임을 구성하는 열벡터에 포함된 요소의 숫자는 같아야 한다. 행렬구조이기 때문이다.

이처럼 구성 요소의 길이가 다르면 리스트 형식의 데이터터구조에 담아야 한다.

list(a = 1:3, b = 1:4)
## $a
## [1] 1 2 3
## 
## $b
## [1] 1 2 3 4

데이터프레임은 길이가 같은 열벡터로만 만들지만, 리스트는 벡터, 데이터프레임, 리스트 등 모든 형식의 데이터구조를 이용해 만들수 있다. 리스트는 이것 저것 넣어두는 서랍장이라 할수 있다.

cha <- "리스트"
number <- c(25, 26, 18, 39)
string <- c("one", "two", "three", "four")
df2 <- data.frame(number, string)

list_l <- list(CH = cha, NU = number, ST = string, DF = df2)
str(list_l)
## List of 4
##  $ CH: chr "리스트"
##  $ NU: num [1:4] 25 26 18 39
##  $ ST: chr [1:4] "one" "two" "three" "four"
##  $ DF:'data.frame':  4 obs. of  2 variables:
##   ..$ number: num [1:4] 25 26 18 39
##   ..$ string: chr [1:4] "one" "two" "three" "four"

lm()등과 같은 함수의 계산결과에는 다양한 구조의 데이터가 산출되기 때문에, 이런 경우 산출값을 리스트 구조에 담는다. 예시에서는 12개의 값을 갖고 있는 리스트(list of 12)라고 나온다. $와 함께 각 요소의 이름(예: $ coefficients, $ model 등)과 구성요소가 제시돼 있다.

df %>% 
  lm(height ~ weight, .) %>% 
  str()
## List of 12
##  $ coefficients : Named num [1:2] 144.832 0.325
##   ..- attr(*, "names")= chr [1:2] "(Intercept)" "weight"
##  $ residuals    : Named num [1:3] 2.646 -3.053 0.407
##   ..- attr(*, "names")= chr [1:3] "1" "2" "3"
##  $ effects      : Named num [1:3] -278.28 -7.5 -4.06
##   ..- attr(*, "names")= chr [1:3] "(Intercept)" "weight" ""
##  $ rank         : int 2
##  $ fitted.values: Named num [1:3] 164 163 155
##   ..- attr(*, "names")= chr [1:3] "1" "2" "3"
##  $ assign       : int [1:2] 0 1
##  $ qr           :List of 5
##   ..$ qr   : num [1:3, 1:2] -1.732 0.577 0.577 -84.293 -23.036 ...
##   .. ..- attr(*, "dimnames")=List of 2
##   .. .. ..$ : chr [1:3] "1" "2" "3"
##   .. .. ..$ : chr [1:2] "(Intercept)" "weight"
##   .. ..- attr(*, "assign")= int [1:2] 0 1
##   ..$ qraux: num [1:2] 1.58 1.14
##   ..$ pivot: int [1:2] 1 2
##   ..$ tol  : num 1e-07
##   ..$ rank : int 2
##   ..- attr(*, "class")= chr "qr"
##  $ df.residual  : int 1
##  $ xlevels      : Named list()
##  $ call         : language lm(formula = height ~ weight, data = .)
##  $ terms        :Classes 'terms', 'formula'  language height ~ weight
##   .. ..- attr(*, "variables")= language list(height, weight)
##   .. ..- attr(*, "factors")= int [1:2, 1] 0 1
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr [1:2] "height" "weight"
##   .. .. .. ..$ : chr "weight"
##   .. ..- attr(*, "term.labels")= chr "weight"
##   .. ..- attr(*, "order")= int 1
##   .. ..- attr(*, "intercept")= int 1
##   .. ..- attr(*, "response")= int 1
##   .. ..- attr(*, ".Environment")=<environment: 0x000000001f206488> 
##   .. ..- attr(*, "predvars")= language list(height, weight)
##   .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
##   .. .. ..- attr(*, "names")= chr [1:2] "height" "weight"
##  $ model        :'data.frame':   3 obs. of  2 variables:
##   ..$ height: num [1:3] 167 160 155
##   ..$ weight: num [1:3] 60 56 30
##   ..- attr(*, "terms")=Classes 'terms', 'formula'  language height ~ weight
##   .. .. ..- attr(*, "variables")= language list(height, weight)
##   .. .. ..- attr(*, "factors")= int [1:2, 1] 0 1
##   .. .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. .. ..$ : chr [1:2] "height" "weight"
##   .. .. .. .. ..$ : chr "weight"
##   .. .. ..- attr(*, "term.labels")= chr "weight"
##   .. .. ..- attr(*, "order")= int 1
##   .. .. ..- attr(*, "intercept")= int 1
##   .. .. ..- attr(*, "response")= int 1
##   .. .. ..- attr(*, ".Environment")=<environment: 0x000000001f206488> 
##   .. .. ..- attr(*, "predvars")= language list(height, weight)
##   .. .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
##   .. .. .. ..- attr(*, "names")= chr [1:2] "height" "weight"
##  - attr(*, "class")= chr "lm"

1.6.3.1 부분선택

리스트에는 다른 데이터구조가 하부요소로 포함돼 있기 때문에 부분선택할 때 [ ][[ ]]를 이용한다. 앞서 만든 리스트 ’list_l’의 2번째 요소를 [ ][[ ]]로 각각 부분선택해 결과를 비교해보자.

list_l[2] %>% typeof()
## [1] "list"
list_l[[2]]
## [1] 25 26 18 39

[ ]로 부분선택하면 리스트 구조를 유지한 채 부분선택한다. [[ ]]로 부분선택하면 구성요소의 구조(예기서는 벡터)로 부분선택한다.

데이터프레임이 리스트의 구성요소일때는 $[ ]를 함께 사용하거나 [[ ]][ ]를 함께 이용한다.

list_l$DF[2]    # 리스트 list_l의 DF요소에서 2번재 열 부분선택
##   string
## 1    one
## 2    two
## 3  three
## 4   four
list_l[[4]][2]  # 리스트 list_l의 DF요소의 4번재 요소 중 2번째 열 부분선택
##   string
## 1    one
## 2    two
## 3  three
## 4   four

1.6.4 매트릭스와 어레이

벡터를 2차원 구조로 구성한 데이터구조가 매트릭스이고, 3차원 구조로 구성한 데이터구조가 어레이다. 달리 표현하면, 벡터는 1차원 어레이, 매트릭스는 2차원 어레이, 어레이는 3차원 어레이라고도 할수 있다.

1.6.4.1 매트릭스 matrix()

벡터에 행과 열을 지정해 만든다. 1부터 20까지의 숫자로 이뤄진 벡터를 5개 행으로 이뤄진 매트릭스를 만들면 다음과 같다.

matrix(1:20, nrow = 5)
##      [,1] [,2] [,3] [,4]
## [1,]    1    6   11   16
## [2,]    2    7   12   17
## [3,]    3    8   13   18
## [4,]    4    9   14   19
## [5,]    5   10   15   20

열을 지정해 만들수도 있다.

matrix(1:20, ncol = 10)
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,]    1    3    5    7    9   11   13   15   17    19
## [2,]    2    4    6    8   10   12   14   16   18    20

1.6.4.2 어레이 array()

기본 속성은 벡터나 매트릭스와 같다. 1개 차원만 지정하면 벡터, 2개 차원만 지정하면 매트릭스가 된다. 차원은 dim =인자를 이용한다.

1부터 6까지의 숫자벡터를 2행 3열의 매트릭스로 만들어 보자. matrix()함수와 array()함수를 이용한다. dim = c(2, 3)은 행 2개, 열 3개 등 2차원으로 배치하라는 의미이므로 매트릭스를 만들게 된다.

matrix(1:6, nrow = 2)
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6
array(1:6, dim = c(2, 3))
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6

3차원 어레이를 만들려면 차원 인자 dim =에 행과 열 외에 추가차원을 지정한다. 1에서 24까지의 숫자벡터를 2행과 3열로 이뤄전 3차원 어레이를 만드는 경우, 투입한 인자 dim = c(2, 3, 4)는 2행 3열의 행렬을 4개 만들라는 의미다.

array(1:24, dim = c(2, 3, 4))
## , , 1
## 
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6
## 
## , , 2
## 
##      [,1] [,2] [,3]
## [1,]    7    9   11
## [2,]    8   10   12
## 
## , , 3
## 
##      [,1] [,2] [,3]
## [1,]   13   15   17
## [2,]   14   16   18
## 
## , , 4
## 
##      [,1] [,2] [,3]
## [1,]   19   21   23
## [2,]   20   22   24

::: infobox 코딩 스타일

코딩도 일종의 글쓰기이므로, 코딩에도 스타일이 있다. 코딩은 기능적인 글쓰기이므로 실용성과 가독성이 중요하다. 코드를 작성한 다음 나중에 그 코드를 다시 봤을 때 혹은 다른 사람이 그 코드를 봤을 때 직관적으로 잘 이해할 수 있도록 일관적이고도 효율적으로 코드를 작성해야 한다.

널리 사용되는 코딩스타일의 지침은 해들리 위컴의 R스타일 가이드다.

  1. 다른 사람 혹은 본인이 나중에 봤을 때 그 의미를 쉽게 파악할 수 있도록 설정. good: fruit_v
    bad: f

  2. 객체이름의 의미 단위는 _-로 구분. good: plots_combined
    bad: plotsCombied

  • 데이터를 할당한 객체이름 객체의 특성(예: 데이터구조) 명기. 이 방법이 좋은 이유는 객체의 이름을 다른 중요한 함수 이름과 중복되지 않도록 할수 있을 뿐 아니라, 데이터구조를 간단하게 파악할 수 있기 때문이다.

  • 예:

    • 벡터: name_v
    • 데이터프레임: name_df
    • 매트릭스: name_m
    • 리스트: name_l
    • 사용자 함수: name_f
    • 토큰: name_tk

1.7 파이프(pipe) %>%

dplyr패키지는 magrittr패키지의 파이프%>%를 이용한다. 파이프는 앞의 값을 ’파이핑’해 뒤로 전달해 주는 기능을 한다.

예를 들어 select(df, ID, age)에서 df를 파이핑해 코딩하면 다음과 같이 하면 된다.

df %>% select(ID, age) 
##        ID age
## 1 참가자1  32
## 2 참가자2  33
## 3 참가자3  45

같은 원리로 filter(df, ID == "참가자1")에서 df를 파이핑해보자.

df %>% filter(ID == "참가자1")
##        ID age status weight height
## 1 참가자1  32   TRUE     60    167

파이핑을 이용하면 select()filter()를 연속적으로 연결할 수 있다. df 데이터프레임에서 ’status’가 TRUE인 행에서 ID, age, weight열을 부분선택하면 다음과 같다.

df %>% 
  filter(status == TRUE) %>% 
  select(ID, age, weight) 
##        ID age weight
## 1 참가자1  32     60
## 2 참가자3  45     30

이런 식으로 여러 함수를 파이핑함으로써 보다 간결하고 이해하기 쉬운 코드를 작성할 수 있다.

파이핑된 값을 명시적으로 지정해야 하는 경우도 있다.

df %>% lm(height ~ weight)

Error in as.data.frame.default(data) : cannot coerce class ‘"formula"’ to a data.frame라는 오류가 발생한다. data =인자에 투입할 값이 파이핑됐다는 것을 .을 이용해 명시적으로 표기해야 한다.

df %>% lm(height ~ weight, .) 
## 
## Call:
## lm(formula = height ~ weight, data = .)
## 
## Coefficients:
## (Intercept)       weight  
##    144.8317       0.3254

.으로 명시적으로 파이핑하면 다음과 같은 방법도 가능하다.

df %>% .$age
## [1] 32 33 45
df %>% .[1, 2]
## [1] 32

이 방법이 유용한 이유는 여러 함수를 파이핑한 다음 부분선택해야 하는 상황이 있기 때문이다.

df %>% 
  filter(status == TRUE) %>% 
  select(ID, age, weight) %>% 
  .[1,2]
## [1] 32

lm()함수로 계산한 결과에서 계수(coefficients)만 추출해야 하는 경우, .을 이용해 파이핑해 계수만 부분선택할 수있다.

df %>% 
  lm(height ~ weight, .) %>% 
  names()
##  [1] "coefficients"  "residuals"     "effects"       "rank"         
##  [5] "fitted.values" "assign"        "qr"            "df.residual"  
##  [9] "xlevels"       "call"          "terms"         "model"
df %>% 
  lm(height ~ weight, .) %>% 
  .$coefficients
## (Intercept)      weight 
## 144.8316583   0.3253769

퀴즈: 아래와 같이 select()함수를 이용하지 않는 이유는? ::: infobox 파이프(pipe) %>%

dplyr패키지는 magrittr패키지의 파이프%>%를 이용한다. 파이프는 앞의 값을 ’파이핑’해 뒤로 전달해 주는 기능을 한다.

예를 들어 select(df, ID, age)에서 df를 파이핑해 코딩하면 다음과 같이 하면 된다.

df %>% select(ID, age) 
##        ID age
## 1 참가자1  32
## 2 참가자2  33
## 3 참가자3  45

같은 원리로 filter(df, ID == "참가자1")에서 df를 파이핑해보자.

df %>% filter(ID == "참가자1")
##        ID age status weight height
## 1 참가자1  32   TRUE     60    167

파이핑을 이용하면 select()filter()를 연속적으로 연결할 수 있다. df 데이터프레임에서 ’status’가 TRUE인 행에서 ID, age, weight열을 부분선택하면 다음과 같다.

df %>% 
  filter(status == TRUE) %>% 
  select(ID, age, weight) 
##        ID age weight
## 1 참가자1  32     60
## 2 참가자3  45     30

이런 식으로 여러 함수를 파이핑함으로써 보다 간결하고 이해하기 쉬운 코드를 작성할 수 있다.

파이핑된 값을 명시적으로 지정해야 하는 경우도 있다.

df %>% lm(height ~ weight)

Error in as.data.frame.default(data) : cannot coerce class ‘"formula"’ to a data.frame라는 오류가 발생한다. data =인자에 투입할 값이 파이핑됐다는 것을 .을 이용해 명시적으로 표기해야 한다.

df %>% lm(height ~ weight, .) 
## 
## Call:
## lm(formula = height ~ weight, data = .)
## 
## Coefficients:
## (Intercept)       weight  
##    144.8317       0.3254

.으로 명시적으로 파이핑하면 다음과 같은 방법도 가능하다.

df %>% .$age
## [1] 32 33 45
df %>% .[1, 2]
## [1] 32

이 방법이 유용한 이유는 여러 함수를 파이핑한 다음 부분선택해야 하는 상황이 있기 때문이다.

df %>% 
  filter(status == TRUE) %>% 
  select(ID, age, weight) %>% 
  .[1,2]
## [1] 32

lm()함수로 계산한 결과에서 계수(coefficients)만 추출해야 하는 경우, .을 이용해 파이핑해 계수만 부분선택할 수있다.

df %>% 
  lm(height ~ weight, .) %>% 
  names()
##  [1] "coefficients"  "residuals"     "effects"       "rank"         
##  [5] "fitted.values" "assign"        "qr"            "df.residual"  
##  [9] "xlevels"       "call"          "terms"         "model"
df %>% 
  lm(height ~ weight, .) %>% 
  .$coefficients
## (Intercept)      weight 
## 144.8316583   0.3253769

주의:
아래와 같이 select()함수를 이용하지 않는 이유는 select()함수가 처리하는 데이터는 데이터프레임이기 때문이다.

df %>% 
  lm(height ~ weight, .) %>% 
  select(coefficients)

Error in UseMethod("select_") : 클래스 "lm"의 객체에 적용된 'select_'에 사용할수 있는 메소드가 없습니다라는 오류가 발생한다. lm()함수로 계산한 결과는 데이터프레임이 아닌 ’리스트(list)’라는 데이터구조로 산출하기 때문이다.

1.8 시각화

시각화는 자료와 정보의 시각적 표현이다. 자료-정보-지식-지혜(DIKW: Data-Information-Knowledge-Wisdom) 위계론에 따르면, 자료(data)는 현상의 관측으로서 1차 부호화 통해 생성하고, 정보(information)은 자료(data)를 분석해(즉, 2차 부호화) 생성한다. 시각화라 하더라고 데이터시각화(data visualization)와 정보시각화(information visualization)은 기능과 목표에 차이가 있다.

  • 데이터시각화: 시각화에 투입하는 요소(데이터) 강조. 데이터분석의 한 방법. 데이터를 시각적으로 분석해 정보구성. 시각적 자료분석으로 논문으로 치면 분석단계.

  • 정보시각화: 시각화로 산출하는 요소(정보) 강조. 정보 해석의 한 방법. 정보를 시각적으로 해석해 지식구성. 정보를 생성한다는 의미로 본다면 데이터시각화와 동의어로서 논문의 분석단계에 해당한다. 그러나, 정보시각화를 시각적인 정보해석으로 본다면, 논문의 논의에 해당한다.

탐색적 단계에서 자료의 특성을 파악하기 위해 시각화한다면 데이터시각화에 해당하고, 분석을 마친 다음 분석결과를 소통하기 위해 시각화 한다면 정보시각화에 해당한다.

1.8.1 시각화를 하는 이유

백문(百聞)이 불여일견(不如一見)이기 때문이다. 시각화함으로써 숫자만으로는 파악하기 어려운 내용을 파악할 수 있다. 좋은 사례가 통계학자 Francis Anscombe(1918-2001)가 시각화의 기능을 설명하기 위해 만든 ’안스콤의 4개조(Anscombe’s Quartet)’다. R의 내장데이터 anscombe으로 제공된다. str()함수로 살펴보자. 11행 8열로 이뤄진 데이터프레임이다.

str(anscombe)
## 'data.frame':    11 obs. of  8 variables:
##  $ x1: num  10 8 13 9 11 14 6 4 12 7 ...
##  $ x2: num  10 8 13 9 11 14 6 4 12 7 ...
##  $ x3: num  10 8 13 9 11 14 6 4 12 7 ...
##  $ x4: num  8 8 8 8 8 8 8 19 8 8 ...
##  $ y1: num  8.04 6.95 7.58 8.81 8.33 ...
##  $ y2: num  9.14 8.14 8.74 8.77 9.26 8.1 6.13 3.1 9.13 7.26 ...
##  $ y3: num  7.46 6.77 12.74 7.11 7.81 ...
##  $ y4: num  6.58 5.76 7.71 8.84 8.47 7.04 5.25 12.5 5.56 7.91 ...
print(anscombe)
##    x1 x2 x3 x4    y1   y2    y3    y4
## 1  10 10 10  8  8.04 9.14  7.46  6.58
## 2   8  8  8  8  6.95 8.14  6.77  5.76
## 3  13 13 13  8  7.58 8.74 12.74  7.71
## 4   9  9  9  8  8.81 8.77  7.11  8.84
## 5  11 11 11  8  8.33 9.26  7.81  8.47
## 6  14 14 14  8  9.96 8.10  8.84  7.04
## 7   6  6  6  8  7.24 6.13  6.08  5.25
## 8   4  4  4 19  4.26 3.10  5.39 12.50
## 9  12 12 12  8 10.84 9.13  8.15  5.56
## 10  7  7  7  8  4.82 7.26  6.42  7.91
## 11  5  5  5  8  5.68 4.74  5.73  6.89

각 열의 평균(mean)과 표준편차(sd: standard deviation)를 구해보자.

mean(anscombe$x1)
mean(anscombe$x2)
mean(anscombe$x3)
mean(anscombe$x4)
mean(anscombe$y1)
mean(anscombe$y2)
mean(anscombe$y3)
mean(anscombe$y4)

sd(anscombe$x1)
sd(anscombe$x2)
sd(anscombe$x3)
sd(anscombe$x4)
sd(anscombe$y1)
sd(anscombe$y2)
sd(anscombe$y3)
sd(anscombe$y4)

apply()함수를 이용해 mean()sd()함수가 반복(iteration)작업을 하도록 하면, 같은 함수를 반복해서 쓸 필요없이 한번에 계산하도록 할 수 있다.

apply(), lapply(), sapply()처럼 함수가 다른 함수를 실행대상으로 설정하는 작업을 함수형프로그래밍(functional programming)이라고 한다. apply()의 용법은 다음과 같다.

apply(X, MARGIN, FUN, ...)
- X : 함수로 실행할 대상. 매트릭스 등 행열데이터 구조.
- MARGIN : 함수의 적용 방향. 값이 1이면 행(row)방향, 2는 열(column)방향으로 계산.
- FUN : 투입한 X인자의 각 요소에 대해 실행할 함수.
- … : 추가로 사용할 수 인자가 많이 있다는 의미다.

아래 코드는 ’anscombe’데이터프레임에 대하여 각 열에 대하여 열방향(2)으로 투입한 함수(여기서는 mean()sd())를 적용(apply)해 반복적으로 mean()sd()함수를 실행하라는 의미다.

apply(anscombe, 2, mean)  # 각 열의 평균 계산
##       x1       x2       x3       x4       y1       y2       y3       y4 
## 9.000000 9.000000 9.000000 9.000000 7.500909 7.500909 7.500000 7.500909
apply(anscombe, 2, sd)    # 각 열의 표준편차 계산
##       x1       x2       x3       x4       y1       y2       y3       y4 
## 3.316625 3.316625 3.316625 3.316625 2.031568 2.031657 2.030424 2.030579

x1열부터 x4열까지 그리고 y1열부터 y4열까지 평균값이 같다. 표준편차도 마찬가지다.

x1열부터 x4열까지 그리고 y1열부터 y4열 사이의 각각에 대한 상관계수도 모두 같다.

상관관계(correlation)는 두 변수가 서로 관련돼 있는 정도다. 상관관계의 정도는 상관계수로 나타낸다. 상관관계의 범위는 -1에서 1까지이다. 상관계수가 -1 혹은 1이면 상관성이 완전한 관계이고, 0이면 상관성이 없다. 상관계수가 0.8이면 상당히 높은 수준의 상관성을 나타낸다. 0.2는 낮은 수준의 상관성.

x열과 y열의 4개 쌍을 cor()함수로 계산한 피어슨 상관관계 계수(coefficient) \(r\)은 모두 0.82다.

cor(anscombe$x1, anscombe$y1)
## [1] 0.8164205
cor(anscombe$x2, anscombe$y2)
## [1] 0.8162365
cor(anscombe$x3, anscombe$y3)
## [1] 0.8162867
cor(anscombe$x4, anscombe$y4)
## [1] 0.8165214

이번에도 cor()함수를 네번이나 반복했으므로, 이를 프로그래밍으로 자동화할 수 있다. 이번에는 for 루프(loop: 반복문)를 이용해 반복작업을 자동화해보자.

cor_l <- list()
for(i in 1:4){
  cor_l[i] <- cor(anscombe[i], anscombe[i+4])
}
cor_l
## [[1]]
## [1] 0.8164205
## 
## [[2]]
## [1] 0.8162365
## 
## [[3]]
## [1] 0.8162867
## 
## [[4]]
## [1] 0.8165214

for 반복문은 세개요소로 이뤄져 있다.

  1. 컨테이너: 반복 작업을 통해 생성될 값을 저장할 객체를 미리 만들어 놓은 빈 객체. 값을 할당하지 않은 벡터, 데이터프레임, 리스트 등이다. 위의 코드에서는 cor_l <- list()로 컨테이너를 만들었다.

  2. 카운터와 범위: for(i in X) 표현식의 ( )안의 있는 i가 카운터다. X는 카운터의 범위(~부터 ~ 까지). 위의 코드에서 1:4는 “1부터 4까지”라는 의미다. 즉, i in 1:4는 “i 카운터를 1부터 4까지 순서대로 투입해 작업하라”는 의미가 된다. (관례적으로 카운터를 i로 사용하지만, 어느 문자를 써도 관계없다. 일관성있게 쓰면 된다.)

  3. 실행부 : { } 안의 함수를 반복해서 실행하는 부분. ifor( )에서 지정한 범위에서 순서대로 투입해 실행하게 된다. 위의 코드에서 { }안의 실행부를 풀어서 표시하면 아래와 같다.

cor_l[1] <- cor(anscombe[1], anscombe[1+4])
cor_l[2] <- cor(anscombe[2], anscombe[2+4])
cor_l[3] <- cor(anscombe[3], anscombe[3+4])
cor_l[4] <- cor(anscombe[4], anscombe[4+4])

이런 식으로 순차적으로 { }안의 함수를 실행하면, 이 과정을 통해 미리 만들어 둔 컨테이너에 순차적으로 값이 쌓이게 된다. 여기서는 빈 객체를 리스트로 만들었기 때문에, 생성된 객체는 리스트다.( 반복문에 대해 보다 자세한 내용은 R2DS의 반복문 편 참고.) )

평균, 표준편차, 및 각 상관계수는 모두 같은 값이지만, x열과 y열의 4개 쌍의 관계를 시각화하면 각 쌍의 상관관계는 전혀 다른 모습으로 나타난다. plot()함수로 1번째행(x1)과 5번째행(y1), 2번째행(x2)과 6번째행(y2), 3번째행(x3)과 7번째행(y3), 4번째행(x4)과 8번째행(y4)의 관계를 산점도로 그려보자.

par(mfrow = c(2,2))
plot(anscombe[,1], anscombe[,5], 
     main = paste("Quartet", 1, sep = " "),
     xlab = colnames(anscombe)[1], 
     ylab = colnames(anscombe)[5],
     pch = 16, cex = 2, col = "blue")

plot(anscombe[,2], anscombe[,6], 
     main = paste("Quartet", 2, sep = " "),
     xlab = colnames(anscombe)[1], 
     ylab = colnames(anscombe)[5],
     pch = 16, cex = 2, col = "blue")

plot(anscombe[,3], anscombe[,7], 
     main = paste("Quartet", 3, sep = " "),
     xlab = colnames(anscombe)[1], 
     ylab = colnames(anscombe)[5],
     pch = 16, cex = 2, col = "blue")

plot(anscombe[,4], anscombe[,8], 
     main = paste("Quartet", 4, sep = " "),
     xlab = colnames(anscombe)[1], 
     ylab = colnames(anscombe)[5],
     pch = 16, cex = 2, col = "blue")

par(mfrow = c(2,2))에서 par()함수는 도표 표시하는 방식을 지정한다. mfrow인자는 행과 열의 갯수다. mfrow = c(2,2)는 “2행 2열”이란 의미가 된다. “3행 4열”로 지정하면 par(mfrow = c(3,4))이 된다.

R에서 기본함수로 제공하는 시각화 도구는 plot(x, y, ...)함수다. x축의 값과 Y축의 값을 투입해 산점도를 표시한다. 산점도 모양은 다양한 인자를 이용해 설정한다.

  • pch : 점 모양. pch = 16은 꽉찬 원. R에서 사용하는 점의 모양은 다음과 같다.

  • cex : 크기. cex = 2는 기본값의 2배.

  • col : 색. 색의 용법은 w3school의 Colors Tutorial 참조.

같은 코드를 반복해서 작성했으므로 반복문으로 4번의 plot() 함수 작업을 자동화해 보자. (도표를 표시하기 때문에 컨테이너를 만들지 않았다.)

par(mfrow = c(2,2))
for(i in 1:4){
  plot(anscombe[ ,i], anscombe[ ,i+4], 
       main = paste("Quartet", i, sep = " "),
       xlab = colnames(anscombe)[i], 
       ylab = colnames(anscombe)[i+4],
       pch = 16, cex = 2, col = "blue")
}

이처럼 시각화를 이용하면 계수로만 파악하기 어려운 관계를 표현할 수 있다. 평균, 표준편차, 상관계수가 모드 같지만, 시각화한 상관관계는 모두 다르다.

1.8.2 ggplot2

현대적인 시각화는 ggplot2패키지가 제공한다. ’gg’는 ’grammar of graphics’로서 ’도표를 작성하는 문법’이라는 의미다. 도표를 일관된 원리에 의해 작성하도록 했기 때문에 붙인 이름이다. ggplot2패키지는 tidyverse패키지의 일부로서 함께 설치되고 함께 탑재된다.

ggplot2패키지로 안스콤 4개조 중 x2와 y2의 관계를 점도표로 표시하면 다음과 같다.

ggplot(data = anscombe) + 
  geom_point(mapping = aes(x = x2, y = y2))

ggplot2패키지는 층(layer)에 층을 겹겹이 쌓아 올리는 식으로 도표를 구성한다. 각 층은 +기호로 연결한다. 이를 체이닝(chaining)이라고 한다. dplyr패키지에서 사용하는 파이프 %>%와 비슷하지만 작동원리는 다르다. 파이프는 앞의 값을 뒤로 전달하는 기능을하는 반면, 체인은 층을 쌓아 올리는 기능을 한다.

즉, 위 코드는 ggplot()함수로 ’anscombe’데이터로 좌표가 있는 층을 만든 다음, 그 위에 geom_point()함수로 x축과 y축에 미적(aes) 기하객체(geom_point: 점)을 배치(mapping)해 만든 층을 추가한 것이라 할 수 있다.

geom_point()라는 함수의 이름은 기하객체(geom)가 점(point)이라는데서 왔다. 이 원리를 적용하면, 기하객체(geom)가 막대인 경우는 geom_col()이나 geom_bar()가 된다. 선인 경우는 geom_line() 혹은 geom_smooth()다. 투입하는 변수의 수, 종류에 따라 매우 다양한 도표를 시각화할 수 있다. (자세한 내용은 ggplot2 설명서를 참고. 요약본도 있다.)

anscombe데이터를 ggplot()함수에 대해 파이핑한 다음, 산점도를 그리고, 그 위에 x2와 y2의 관계를 회귀선으로 표시하면 다음과 같다. method =인자는 x2와 y2의 관계를 계산하는 방식을 지정하는 인자다. lm은 선형모형(linear models)을 계산하는 함수다.

anscombe %>%
  ggplot() + 
  geom_point(aes(x2, y2)) +
  geom_smooth(aes(x2, y2), method = lm)
## `geom_smooth()` using formula 'y ~ x'

geom_smooth()method =인자를 따로 지정하지 않으면 기본값인 loess가 적용된다. loess는 ’LOcally Weighted Scatter-plot Smoother’의 약어로 국소(locally)적으로 가중치를 적용해 비선형 모형을 계산하는 함수다.

anscombe %>%
  ggplot() + 
  geom_point(aes(x2, y2)) +
  geom_smooth(aes(x2, y2))
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

aes()geom_...()함수에 반복적으로 투입하지 않고 ggplot()함수에 한번 투입해도 된다.

anscombe %>%
  ggplot(aes(x2, y2)) + 
  geom_point() +
  geom_smooth(method = lm)

작성한 도표에 labs()함수로 텍스트 층을 추가해 제목, 부제목, 캡션 등을 붙인 다음 theme()함수로 제목의 크기, 색, 위치 등을 지정할 수 있다.

anscombe %>%
  ggplot() + 
  geom_point(aes(x2, y2)) +
  geom_smooth(aes(x2, y2), method = lm) +
  labs(title = "안스콤의 4개조",
       subtitle = "x2와 y2의 관계", 
       caption = "Source: anscombe") +
  theme(plot.title = element_text(size = 20),
        plot.subtitle = element_text(color = "purple", size = 15))
## `geom_smooth()` using formula 'y ~ x'

x열과 y열의 4개 쌍의 관계를 모두 산점도와 선도로 시각화해보자. x1-y1, x2-y2, x3-y3, x4-y4 등 4개 쌍에 대해 각각 ggplot() 함수를 실행할수도 있지만, 반복문을 이용해 4번의 과정을 자동화할 수 있다.

이번에는 lapply()함수와 사용자함수를 이용해보자.

apply(), lapply(), sapply()처럼 함수가 다른 함수를 실행대상으로 설정하는 작업을 함수형프로그래밍(functional programming)이라고 한다. lapply()의 용법은 다음과 같다. lapply(X, FUN, ...)
- X : 함수로 실행할 벡터 또는 리스트.
- FUN : 투입한 X인자의 각 요소에 대해 실행할 함수.
- … : 투입한 FUN인자에 사용할 인자.

  • apply(X, MARGIN, FUN, ...) : 계산 방향을 MARGIN =인자로 행 방향인지 열방향인지 지정.

  • lapply(X, FUN, ...) : 투입한 객체에 대하여 지정한 함수를 반복 계산해 리스트로 산출.

  • sapply(X, FUN, ...) : : 투입한 객체에 대하여 지정한 함수를 반복 계산해 매트릭스로 산출.

base_plot <- ggplot()
plots_combined <- lapply(1:4, function(i) {
  x <- anscombe[,i]
  y <- anscombe[,i+4]
  geom_p <- geom_point(aes_(x,y))
  geom_s <- geom_smooth(aes_(x,y), method = "lm", se = F)
  base_plot + geom_p + geom_s
})
plots_combined
## [[1]]
## `geom_smooth()` using formula 'y ~ x'

## 
## [[2]]
## `geom_smooth()` using formula 'y ~ x'

## 
## [[3]]
## `geom_smooth()` using formula 'y ~ x'

## 
## [[4]]
## `geom_smooth()` using formula 'y ~ x'

patchwork패키지를 이용하면 복수의 도표를 +/로 이어 붙여(patch) 하나의 도표로 표시할 수 있다 (패키지에 대해서는 다음 장에서 상세하게 설명).

위의 코드에서 4개의 도표는 plots_combined에 리스트로 저장돼 있으므로, plots_combined의 각 요소를 [[ ]]로 부분선택(subsetting)해 각 도표를 +로 좌우방향 patch하고 /로 상하방향 patch해 이어 붙인다.

  • plot_annotation()함수는 이어 붙인 도표에 제목, 부제목, 캡션 등을 달수 있다.

  • theme()함수는 제목의 위치(hjust: 가로위치 조정)나 크기(size)를 설정할 수 있다.

plot_annotation()함수와 theme()함수 사이를 &로 연결한 것에 주의하자.

if(!require(patchwork)) install.packages("patchwork")     
library(patchwork)

(plots_combined[[1]] + plots_combined[[2]]) / (plots_combined[[3]] + plots_combined[[4]]) +
  plot_annotation(title = "안스콤의 4개조") &
  theme(plot.title = element_text(hjust = .5, size = 20))

1.9 오류(error)

Warning(경고)메시지는 참고만 하고 무시해도 되지만, 오류(error)메시지는 거의 대부분 해결해야 다음 단계로 넘어갈 수 있다.

오류가 발생하면 당황하지 말고, 오류메시지를 잘 읽어보자.

흔한 오류는 다음과 같다.

1.9.1 오자와 탈자

가장 흔한 오류의 원인은 오타다.

  • 영어는 단수와 복수의 구분이 엄격하다. 철자에 ’s’가 정확하게 들어 있는지 확인한다.

  • ’1’과 ’l’의 차이. 사람 눈에 비슷해 보이는 글자에 주의한다. 기계에게는 전혀 다른 내용이다. 예를 들어, readxl패키지를 readx1로 입력하지 않았는지 확인해보자.

1.9.2 괄호의 불일치

  • 괄호의 앞()가 일치해야 한다. 마무리를 하지 않으면 코드 실행이 될수가 없다. R스튜디오 편집창에서 오류 표시를 해 준다.

1.9.3 보이지 않는 코드

PDF문서의 내용을 R스튜디오 편집창에 복사해서 붙일 때, 문서의 코드를 그대로 복사해서 붙였으므로, 오자나 탈자가 없는데도, 코드가 작동하지 않는 경우가 있다. 이런 일이 생기는 이유는 사람의 눈에 동일한 문자라도 기계는 다른 문자코드로 인식할 수 있기 때문에. 특히, PDF문서를 복사해서 편집기에 복사해서 붙이면 사람 눈에 보이지 않는 코드도 함께 복사돼 붙여지는 경우가 있다.

이런 문제가 생기면, 메모장같은 텍스트에디터에 해당 코드를 붙여넣었다 다시 복사해서 R스튜디오 편집창에 붙여 넣으면 해결할 수 있다.

1.9.4 패키지 설치시 겪을 수 있는 오류

패키지설치할 때 아래와 같은 오류가 발생하는 경우가 있다.

library(“tidyverse”) Error: package or namespace load failed for ‘tidyverse’ in loadNamespace(i, c(lib.loc, .libPaths()), versionCheck = vI[[i]]): namespace ‘scales’ 0.4.0 is already loaded, but >= 0.4.1 is required

내용을 해석하면 tidyverse패키지와 함께 설치되는 패키지가 의존하는 scale패키지가 컴퓨터에서 업데이트돼 있지 않아 오류가 발생했다는 의미다.

해당 패키지(이 경우 scale)를 새로 설치하거나 업데이트한다.

새로 설치할 때는 dependencies=TRUE를 명령어에 추가해 모든 의존 패키지도 설치하도록 하자.

install.packages("패키지명", dependencies=TRUE)

패키지 업데이트를 해보는 방법도 있다.

update.packages("패키지명")

만일 새로 설치해도 해결이 안되면, 패키지를 R콘솔에서 설치해본다. 이때 R을 관리자권한으로 실행하자.

그래도 안되면, 패키지가 설치돼 있는 하드디스크폴더에서 해당 패키지 폴더를 삭제하고 다시 설치한다.

패키지가 설치된 위치는 다음과 같다. .libPaths()함수를 통해 확인할 수 있다.

패키지가 설치되는 위치는 RStudio를 관리자 권한으로 실행하는 경우 C:/Program Files/R/[R버전]/library다.

관리자권한으로 실행하지 않으면 아래의 경우처럼 문서폴더에 패키지가 설치된다.

내 PC > 문서 > R > win-library
또는
C:\Users\[윈도사용자]\Documents\R\win-library
예를 들어:
C:\Users\myPC\Documents\R\win-library

패키지 설치위치는 .libPaths("폴더명")함수로 패키지 설치위치를 바꿀 수 있다.

예를 들어, C드라이브의 library폴더를 만들어 .libPaths("c:/library")를 입력하면 패키지 설치 경로가 변경된다.

1.9.5 실행할 때 겪을 수 있는 오류

다음과 같은 에러메시지가 뜨는 경우가 있다. 메시지의 내용을 잘 읽어보자.

Error in tibble(text = text_vword) %>% unnest_tokens(output = word, input = text) : 
  함수 "%>%"를 찾을 수 없습니다

실행하는데 필요한 함수 %>%를 찾을 수 없다는 의미다. %>%는 파이핑에 필요한 함수로서 dplyr에서 magrittr패키지를 통해 제공한다. dplyrtidyverse를 올리면 함께 부착된다.

따라서 아래 3가지 중 하나만 하면 해결할 수 있다.

library(tidyverse)
또는
library(dplyr)
또는
library(magrittr)

마찬가지로 아래와 같은 에러메시지가 뜨면 어떻게 해야할까?

Error in unnest_tokens(., output = word, input = text) : 
  함수 "unnest_tokens"를 찾을 수 없습니다  

오류메시지의 내용을 보니, unnest_tokens함수가 없다고 한다. unnest_tokens가 어디에 속해 있는 함수인지 검색해보자. tidytext패키지의 함수란 정보를 어렵지 않게 찾을 수 있다. 따라서 unnest_tokens함수를 제공하는 패키지 tidytext를 실행한다. 설치가 안돼 있으면 설치부터 한다.

if(!require(tidytext)) install.packages("tidytext")
library(tidytext)
  • 기타 패키지 설치 관련 정보는 이 문서 참조

1.10 여러 패키지 한번에 설치

필요한 패키지는 install.packages()를 이용해 설치하고, library() 혹은 require() 함수를 이용해 패키지를 R환경에 탑재한다.

require()library()와 달리 실행후 TRUE 혹은 FALSE 값을 반환한다. if()조건문에서 사용한다.

만일, 사용하는 패키지가 많다면 어떻게 해야할까? 설치해야 하는 패키지를 벡터에 저장해 한번에 설치하면 된다. 엑셀파일을 읽는데 이용하는readxl패키지와 tidyverse패키지를 한번에 설치는 상황을 설정해보자. 다음과 같이 install.packages()함수를 두번 입력한다.

install.packages("readxl")
install.packages("tidyverse")

만일 패키지 10개를 설치한다면 같은 문자를 10번 반복해야 한다. 코딩을 하는 이유는 반복적인 작업을 하지 않기 위해서다. 아래와 같이 설치할 패키지를 벡터(여기서는 pkg_v)에 지정해 install.packages(pkg_v)를 실행하면 한번에 패키지를 설치할 수 있다.

c("readxl", "tidyverse") -> pkg_v
install.packages(pkg_v)

R에서는 객체를 할당할 때 ->를 이용하면 객체를 오른쪽에 놓을 수 있다. 파이핑 코드처럼 사고의 흐름과 일치하는 장점이 있다.

그런데, 이 방법은 단점이 있다. 이미 설치된 패키지를 반복해서 설치하도록 하기 때문이다. readxl패키지는 tidyverse패키지에 포함돼 있으므로 따로 설치하지 않아도 되는데 불필요하게 이중으로 설치하게 된다.

설치돼 있는 패키지는 설치를 피하고, 새로운 패키지만 골라서 동시에 설치하는 방법을 알아보자.

먼저 컴퓨터에 설치된 패키지의 목록을 만들어보자.

installed.packages()함수는 “installed”라는 과거형 동사가 의미하듯, 이미 설치된 패키지의 목록을 보여준다. 데이터구조는 매트릭스다. 설치된 패키지 목록은 “Package”이름의 열에 있다. 따라서 installed.packages()[, "Package"]로 부분선택하면 설치된 패키지목록을 벡터로 구할 수 있다.

c("readxl", "tidyverse") -> pkg_v
pkg_v %in% installed.packages()[,"Package"] -> pkg_installed

%in%함수는 “~이 포함된”이란 의미의 연산자이다.

fruits_v <- c("Apple", "Banana", "Orange")
"Apple" %in% fruits_v
## [1] TRUE
f1_v <- c("Apple", "Grape")
f2_v <- c("Apple", "Banana", "Orange")

f1_v %in% f2_v
## [1]  TRUE FALSE

설치된 패키지 목록을 벡터로 저장했으므로, “~을 제외하고”라는 의미의 ! 함수를 이용하면 설치되지 않은 패키지만 부분선택해 벡터로 저장할 수 있다.

pkg_v[!pkg_installed] -> pkg_new

if()는 조건을 걸어 실행하도록 하는 함수다. if()조건문의 산출값은 TRUE 혹은 FALSE 등의 논리값이 나온다. if()조건문의 산출값이 TRUE면 이후 제시된는 함수를 실행하고, FALSE인 경우에는 실행하지 않는다.

target_v <- "Apple"
fruit_v <- c("Apple", "Banana", "Orange")

if(target_v %in% fruit_v) {
  print("Eat!")
} else {
  print("Do not Eat!")
}
## [1] "Eat!"
target_v <- "Stone"
fruit_v <- c("Apple", "Banana", "Orange")

if(target_v %in% fruit_v) {
  print("Eat!")
} else {
  print("Do not Eat!")
}
## [1] "Do not Eat!"

새로 설치할 패키지 목록이 할당된 객체 pkg_new에서 값이 0(조건문에서 0은 FALSE)이면 install.packages(pkg_new)를 실행하지 않고, pkg_new에서 값이 0이 아니면(즉, TRUE면) install.packages(pkg_new)를 실행한다.

if(length(pkg_new)) install.packages(pkg_new)

위의 코드를 종합하면 다음과 같다.

c("readxl", "tidyverse") -> pkg_v # 설치할 패키지 목록
pkg_v %in% installed.packages()[,"Package"] -> pkg_installed # 컴퓨터에 설치된 패키지 목록
( pkg_v[!pkg_installed] -> pkg_new ) # 설치되지 않은 패키지 보기.
if(length(pkg_new)) install.packages(pkg_new) # 패키지 설치

1.11 여러 패키지를 한번에 탑재

설치한 여러 패키지를 R환경에 올려면 다음과 같이 library()함수를 반복해서 입력해야 한다.

library(patchwork)
library(tidyverse)

그런데 이는 좋은 방법이 아니다. library()함수를 반복해서 입력하기 때문이다. sapply()함수를 이용하면, 다른 함수를 반복해서 투입해 반복(iteration)작업을 하도록 코딩할 수 있다.

apply(), lapply(), sapply()처럼 함수가 다른 함수를 실행대상으로 설정하는 작업을 함수형프로그래밍(functional programming)이라고 한다. sapply()의 용법은 다음과 같다.

sapply(X, FUN, ...)
- X : 함수로 실행할 벡터 또는 리스트.
- FUN : 투입한 X인자의 각 요소에 대해 실행할 함수.
- … : 투입한 FUN인자에 사용할 인자.

아래 코드는 탑재할 패키지 목록을 pkg_v에 저장한 다음, 이 목록에 있는 패키지(“patchwork,” “tidyverse”)에 대해 sapply()library()함수를 character.only = TRUE 인자를 투입해 반복해서 실행하라는 의미다. character.only = TRUElibrary()함수에 투입하는 대상이 문자형으로 투입됐음을 알려주는 역할을 한다. character.only = TRUEch = T로 줄여써도 된다.

c("patchwork", "tidyverse") -> pkg_v
sapply(X = pkg_v, FUN = library, character.only = TRUE)

즉, 다음 두줄의 코드를 실행하도록 한줄로 구현한 것이다. (탑재할 패키지가 10개라면!)

library("patchwork", character.only = TRUE)
library("tidyverse", character.only = TRUE)

sapply()함수는 실행결과를 매트릭스 형식으로 산출한다. 실행결과로 나타난 패키지 목록을 보면, 탑재된 패키지 뿐 아니라 탑재되는 함께 탑재되는 패키지 목록을 보여준다.

c("patchwork", "tidyverse") -> pkg_v
sapply(pkg_v, library, ch = TRUE)
##       patchwork   tidyverse  
##  [1,] "patchwork" "patchwork"
##  [2,] "forcats"   "forcats"  
##  [3,] "stringr"   "stringr"  
##  [4,] "dplyr"     "dplyr"    
##  [5,] "purrr"     "purrr"    
##  [6,] "readr"     "readr"    
##  [7,] "tidyr"     "tidyr"    
##  [8,] "tibble"    "tibble"   
##  [9,] "ggplot2"   "ggplot2"  
## [10,] "tidyverse" "tidyverse"
## [11,] "stats"     "stats"    
## [12,] "graphics"  "graphics" 
## [13,] "grDevices" "grDevices"
## [14,] "utils"     "utils"    
## [15,] "datasets"  "datasets" 
## [16,] "methods"   "methods"  
## [17,] "base"      "base"

함수형프로그래밍을 이용한 반복작업은 많이 사용하는 유용한 방법이므로 사용법을 숙지하도록 하자.

1.12 파일경로(path) 표시

1.12.1 슬래시 /

윈도에서는 경로 표시 역슬래시\를 사용하지만, R환경에서는 슬래시/를 이용해 경로를 표시한다. \\처럼 역슬래시를 두번 쓰기도 한다.

/만 쓰거나 첫번째로 적는 /는 루트디렉토리를 의미한다.

list.files("/") #루트디렉토리에 있는 모든 파일과 폴더 표시
list.files("/data") #루트디렉토리 아래의 data폴더에 있는 모든 파일과 폴더 표시
list.files("data") # 현재 작업디렉토리 아래의 data폴더에 있는 모든 파일과 폴더 표시

1.12.1.1 퀴즈

list.files("data\images")를 실행하면 아래와 같은 오류가 발생한다. 이유는?

> list.files("data\images")
에러: ""C:\U"로 시작하는 문자열들 가운데 16진수가 아닌 "\U"가 사용되었습니다

윈도에서 사용하는 경로표시 \를 R환경에서 사용했기 때문이다. \/로 수정한다.

1.12.2 마침표 . ..

  • 마침표 하나. 현재 작업디렉토리
  • 마침표 둘.. 현재 작업디렉토리 바로 한단계 위에 있는 폴더
list.files(".") #작업디렉토리에 있는 모든 파일과 폴더 표시
list.files("./images") #작업디렉토리아래에 있는 images폴더에 있는 모든 파일과 폴더 표시. 

list.files("./images")의 산출결과는 list.files("images")와 같다. ./imagesimages는 둘다 현재 작업디렉토리 아래에 있는 images란 의미.

list.files("..") # 작업디렉토리 위 폴더에 있는 모든 파일과 폴더 표시
list.files("../dir") #작업디렉토의 위 폴더 아래(즉, 현 작업디렉토리와 같은 단계의 위치에 있는 폴더) 아래에 있는 images폴더에 있는 모든 파일과 폴더 표시

1.12.3 물결 ~

물결표시~는 홈디렉토리를 의미한다. 로그인 사용자가 사용할 수 있는 최상위 디렉토리.

윈도의 경우에서 만일 사용자 ID를 user1이라고 한 경우 C:/Users/user1/Documents폴더가 홈디렉토리가 된다. (윈도환경에서는 경로를 역슬래시를 사용하므로 C:\Users\user1\Documents로 표시된다.)

따라서 list.files("~")list.files("C:/Users/user1/Documents")는 같은 결과 산출.

list.files("~") #홈디렉토리에 있는 모든 파일 표시
list.files("~/R/win-library") #홈디렉토리 아래단계에 있는 R/win-library폴더의 모든 파일과 폴더 표시 

1.13 파일과 객체

1.13.1 하드디스크에 있는 파일을 다루는 함수

dir.create("C:/newdir") 디렉토리(폴더) 생성
list.files() 현재 작업디렉토리 파일과 폴더 목록

1.13.2 R환경내 객체를 다루는 함수

ls() 현재 작업공간에 있는 객체 목록
rm(객체명) 작업공간의 객체 제거. 필요없는 객체 제거에 사용. 

getwd() 작업디렉토리(working directory) 표시
setwd("C:/newdir") "C:/newdir"을 작업디록토리 설정

단일 R객체를 파일로 저장하는 방법

saveRDS(name_df, file = "name_df.rds")
name_df <-readRDS("name_df.rds")

복수의 R객체를 파일로 저장

save(n1_df, n2_df, file = "name.RData") n1_df과 n2_df객체를 작업디렉토리에 name.RData란 이름의 파일로 저장
load("name.RData") name.RData를 작업공간에 탑재

R환경의 모든 객체를 이미지로 저장.

save.images("myData.RData") 작업공간을 이미지파일로 저장. 파일명 지정하지 않으면 .RData로 저장. 
load("myData.RData") 작업디렉토리 파일을 현 작업공간에 객체로 탑재

fst패키지를 이용하면 대용량 파일을 빠르게 처리할 수있다.

# Store the data frame to disk
  write.fst(df, "dataset.fst")

# Retrieve the data frame again
  df <- read.fst("dataset.fst")

1.14 따옴표와 백틱

1.14.1 겹따옴표 홑따옴표

겹따옴표와 홑따옴표는 문자형요소를 지칭하는데, 함께 사용해야 할때가 있다.

인용문안에서 인용해야 할때는 겹따옴표와 홑따옴표를 함께 사용한다.

"이렇게 인용문 안에 '다시 인용할때' 겹따옴표와 홑따옴표를 함께 사용"

1.14.2 백틱(backquote/backtick) `

변수 혹은 객체명이 한글 특수기호 혹은 띄어쓰기가 있는 경우, 키보드 가장 왼쪽 위에 있는 부호 백틱 한쌍을 이용한다.

`한글변수(명)`

1.15 주의(중요)

R작업에 관련된 폴더이름은 모두 영문으로 지정한다. 한글명 폴더를 이용할 경우 오류발생하는 경우가 드물지 않다.

폴더명을 지정할 때 띄어쓰기를 하지않는다. 오류의 원인이다. 데이터분석 작업을 하는 폴더의 이름은 모두 영문으로 붙여쓴다.

R스튜디오는 작업디렉토리 기본설정이 홈디렉토리(~)로 돼 있다. 만일 윈도나 맥 등 운영체제에서 한글을 사용자명으로 지정했을 꼉우, 경로에 한글폴더가 포함된다. 대부분 문제없지만, 간혹 오류 발생의 원인이 된다.

작업디렉토리 기본값을 루트디렉토리 아래 영문폴더(예: C:/data)를 만들어 설정하자.

1.15.1 글꼴

R문서/그래프/코딩 글꼴(font)을 바꾸고 싶을 때가 있다. 아래 문서 참조. https://statkclee.github.io/viz/viz-r-font.html

1.16 기타

1.16.1 NANULL의 차이

결측값 NA는 값이 없지만, 값이 들어갈 자리는 있는 상태. NULL은 값과 자리가 모두 없는 상태.

0은 결측값이 아니다. 0은 숫자형 값 "0"은 문자형 값