1.3 벡터 파싱
readr
패키지가 디스크에 있는 데이터 파일을 읽은 다음 컬럼의 데이터 유형을 전환하는 방법에 대하여 알아 보기로 한다. readr
패키지에서는 다양한 데이터 유형 변환 함수가 있는데 이 함수들은 parse_
로 시작하는 함수들이다. 이번 절에서는 이러한 parse_*()
함수들에 대하여 살펴보기로 한다.
1.3.1 파싱 함수
파싱 함수들은 readr
패키지의 중요한 구성요소로 독립적으로도 사용할 수 있다. 이 절에서는 개별 파서(parser)가 어떻게 활용되는지를 확인하고, 다음 절에서 개별 파서들이 어떻게 구성되어 파일 전체를 파싱하는지 살펴보기로 한다.
파싱함수를 잘 활용하려면, 어떤 종류의 함수가 있는지, 그리고 각 함수들이 입력 유형을 어떻게 다루는지를 잘 이해해야 한다.
다음과 같은 특별히 중요한 9개의 파서 함수들에 대하여 살펴보기로 한다.
parse_logical()
과parse_integer()
는 문자형의 데이터를 각각 논리형과 정수형으로 을 파싱한다.parse_double()
은 엄격한 수치형 파싱 함수이고,parse_number()
는 유연한 수치형 파싱 함수이다. 이들은 예상보다 사용하기가 간단하다.parse_character()
는 너무 단순해서 필요 없을 것 같다고 생각할 지도 모른다. 그러나 문자 인코딩과 관련하여 매우 중요하게 활용이 되는 파싱 함수이다.parse_factor()
는 범주형 데이터인 팩터형을 생성하는데 사용된다.parse_datetime()
,parse_date()
, 그리고parse_time()
을 사용하면 다양한 날짜와 시간 데이터를 파싱할 수 있다. 날짜의 사용은 매우 다양하기 때문에 이 함수들이 가장 복잡하다. 다음 절들에서 더 자세히 살펴보기로 하자.
1.3.2 문자형 벡터의 변환
1.3.2.1 논리형 벡터로 변환
parse_logical()
함수를 이용하면, TRUE
, FALSE
등의 논리값을 문자열 요소로 구성하는 문자형 벡터를 인수로 하여, 논리형 벡터로 변환할 수 있다. 예를 들면 다음과 갇다.
<- (parse_logical(c("TRUE", "FALSE", "NA")))
a a
## [1] TRUE FALSE NA
class(a)
## [1] "logical"
str(a)
## logi [1:3] TRUE FALSE NA
parse_logical()
함수의 인수는 “문자열 벡터”이다.- 문자열 벡터의 각 요소가
TRUE
와FALSE
등의 문자열 형태이다. - 문자열 데이터
c("TRUE", "FALSE", "NA")
가parse_logical()
함수에 의해 논리형(logical
) 벡터로 변환된다.
1.3.2.2 숫자형 벡터로 변환
parse_integer()
함수를 이용하면, 1
, 2
등의 숫자를 문자열 요소로 구성하는 문자형 벡터를 인수로 하여, 숫자형 벡터로 변환할 수 있다. 예를 들면 다음과 갇다.
<- parse_integer(c("1", "2", "3"))
b b
## [1] 1 2 3
class(b)
## [1] "integer"
str(b)
## int [1:3] 1 2 3
parse_integer()
함수의 인수는 “문자열 벡터”이다.- 문자열 벡터의 각 요소가
1
,2
,3
등의 숫자 형태이다. - 문자열 데이터
c("1", "2", "3")
가parse_integer()
함수에 의해 정수형(integer
) 벡터로 변환된다.
1.3.2.3 na
인수의 사용
tidyverse
의 모든 함수와 마찬가지로, parse_*()
함수도 동일한 형식을 취한다.
즉, parse_*()
함수의 첫 번째 인수는 파싱할 문자형 벡터이고, na =
인수를 추가할 수 있는데 이 인수는 결측값으로 처리되어야 하는 문자열을 지정한다.
예를 들어, 다음의 스크립트는 문자형 벡터의 요소 중 "."
을 NA
로 처리하는 것을 보여 주고 있다.
parse_integer(c("1", "231", ".", "456"), na = ".")
## [1] 1 231 NA 456
na = "."
인수를 추가하지 않으면, “.” 인수가 문자로 처리되어 경고 메시지가 출력된다.
1.3.2.4 복합 형태의 변환
<- parse_integer(c("123", "345", "abc", "123.45")) x
## Warning: 2 parsing failures.
## row col expected actual
## 3 -- an integer abc
## 4 -- no trailing characters 123.45
3번째 요소(
3
)의 경우 정수형이어야 하는데 “abc
”로 입력되었음을 경고함.4번째 요소(
4
)의 경우 허락되지 않는 문자가 따라와서.45
를 경고함.이런 경우에는 출력에서 누락될 것이다.
x
## [1] 123 345 NA NA
## attr(,"problems")
## # A tibble: 2 x 4
## row col expected actual
## <int> <int> <chr> <chr>
## 1 3 NA an integer abc
## 2 4 NA no trailing characters 123.45
3
번째와4
번째 행의 요소의 경우, 결측치(NA
)로 처리됨을 알 수 있다.
problem() 함수의 활용
파싱에 실패한 경우가 많으면 problems()
를 사용하여 확인할 수 있다. problems()
이 반환한 티블(tibble)을 나중에 학습할 dplyr
로 작업할 수도도 있다.
problems(x)
## # A tibble: 2 x 4
## row col expected actual
## <int> <int> <chr> <chr>
## 1 3 NA an integer abc
## 2 4 NA no trailing characters 123.45
1.3.2.5 문자열의 ASCII 코드 변환
parse_character()
함수를 사용하여 문자열을 다양한 코드로 변환할 수 있다. 이 함수의 사용은 정말 단순해 보인다. 그런데 같은 문자열을 나타내는 방법에도 여러 가지 방법이 있다.
R의 base
패키지에서는 charToRaw()
함수를 사용하여 문자열의 ASCII 코드를 확인할 수 있다. 예를 들면 다음과 같다.
charToRaw("Hadley")
## [1] 48 61 64 6c 65 79
charToRaw("대한민국")
## [1] b4 eb c7 d1 b9 ce b1 b9
- 각 문자에 대한 16진수값은 해당 문자의 바이트 코드를 나타낸다.
- 예를 들면
48
은 H의 ASCII 코드를 나타내고,61
은 a의 ASCII 코드를 나타낸다. - 영문은 글자 하나가 1 바이트 :
H
의 ASCII 코드는48
- 한글은 글자 하나가 2 바이트 :
대
의 ASCII 코드는b4 eb
가 된다.
1.3.2.6 16진수 코드의 인코딩
16진수를 문자로 매핑하는 것을 인코딩이라고 한다. 앞의 문자를 16진수의 숫자로 인코딩하는 것을 ASCII 변환이라고 한다. ASCII는 정보 교환을 위한 미국 표준 코드(American Standard Code for Information Interchange)의 줄임말이며 따라서 영문자를 잘 표현한다.
영어가 아닌 다른 언어의 경우 더욱 복잡해진다. 컴퓨터 시대 초창기에는 비영어권 문자의 인코딩을 위한 여러 표준 규격이 있었다. 즉, 문자열을 정확하게 해석하기 위해서는 값과 인코딩을 모두 알아야 했다. 예를 들어 두 가지 일반적인 인코딩은 Latin1 (ISO-8859-1, 서유럽 언어들에서 사용)과 Latin2 (ISO-8859-2, 동유럽 언어들에서 사용) 등이다. Latin1
에서 바이트 b1
은 ‘±’이지만, Latin2
에서는 ‘ą’이다!
다행히 오늘날에는 거의 모든 곳에서 지원되는 하나의 표준인 UTF-8
이 있다. UTF-8
은 오늘날 인간이 사용하는 거의 모든 문자와 기타 기호들(예: 이모티콘)을 인코딩할 수 있게 해준다.
readr
패키지는 모든 곳에서 UTF-8
을 사용한다. 데이터를 읽을 때 UTF-8
이라고 가정하며, 저장할 때는 항상 사용한다. UTF-8
은 좋은 기본값이지만, 이를 인식하지 못하는 구형 시스템에서 생성된 데이터에는 사용할 수 없다. 이런 상황이면 문자열을 화면 출력할 때 이상하게 보이게 된다. 한 두 개의 문자만 엉망이 될 수도 있고, 완전히 외계어를 보는 것과 같이 보일 수 있다. 다음의 예를 보자.
<- "El Ni\xf1o was particularly bad this year"
x1 x1
## [1] "El Ni\xf1o was particularly bad this year"
<- "\x82\xb1\x82\xf1\x82\xc9\x82\xbf\x82\xcd"
x2 x2
## [1] "궞귪궸궭궼"
<- "\x48\x61\x64\x6c\x65\x79"
x3 x3
## [1] "Hadley"
<- "\xb4\xeb\xc7\xd1\xb9\xce\xb1\xb9"
x4 x4
## [1] "대한민국"
x1
의 경우 일부 문자의 파싱이 안되었음.x2
의 경우 파싱이 제대로 되지 않았음. 즉, 코드가 불일치함을 보여줌.
이러한 문제를 해결하려면 parse_character()
함수의 인수에서 사용하고 있는 각각의 인코딩 방식을 알아서 일일이 지정해 주어야 한다.
parse_character(x1, locale = locale(encoding = "Latin1"))
## [1] "El Nino was particularly bad this year"
parse_character(x2, locale = locale(encoding = "Shift-JIS"))
## [1] "こんにちは"
parse_character(x3)
## [1] "Hadley"
parse_character(x4, locale = locale(encoding = "EUC-KR"))
## [1] "대한민국"
encoding =
인수를 이용하여 코드를 지정해 줌.- 영문의 경우는 특별히 로캐일에
encoding
을 지정하지 않아도 된다.
1.3.2.7 인코딩 방식의 추출
올바른 인코딩을 어떻게 찾을 수 있을까? 운이 좋다면 데이터 문서의 어딘가에 포함되어 있을 것이다. 하지만 불행하게도 그런 경우는 거의 없으므로, readr
패키지는 guess_encoding()
함수를 제공하여 사용자가 알아낼 수 있도록 도와주고 있다.
guess_encoding(charToRaw(x1))
## # A tibble: 2 x 2
## encoding confidence
## <chr> <dbl>
## 1 ISO-8859-1 0.46
## 2 ISO-8859-9 0.23
guess_encoding(charToRaw(x2))
## # A tibble: 1 x 2
## encoding confidence
## <chr> <dbl>
## 1 KOI8-R 0.42
guess_encoding(charToRaw(x3))
## # A tibble: 1 x 2
## encoding confidence
## <chr> <dbl>
## 1 ASCII 1
guess_encoding(charToRaw(x4))
## # A tibble: 4 x 2
## encoding confidence
## <chr> <dbl>
## 1 IBM420_ltr 0.5
## 2 ISO-8859-6 0.42
## 3 windows-1256 0.37
## 4 IBM420_rtl 0.25
guess_encoding()
의 첫 번째 인수로는 파일의 경로, 혹은 이 예제와 같이 원시 벡터 (문자열이 이미 R에 있는 경우 유용함)가 될 수 있다.인코딩은 방대하고 복잡한 주제이다. 자세한 사항은 Encoding을 참고하기 바란다.
1.3.3 팩터형 변환
R 은 factor 형을 사용하여, 가질 수 있는 값을 미리 알고 있는 범주형 변수를 나타낸다. 예상치 못한 값이 있을 때마다 경고를 생성하려면 parse_factor()
함수를 이용하여 레벨 벡터를 지정하면 된다.
다음은 문자열 벡터 fruit
를 “apple,” “banana” 등의 두 가지 levels로 구성되는 factor 형으로 변환하는 스크립트를 보여주고 있다.
<- c("apple", "banana", "banana", "apple")
fruit <- parse_factor(fruit)
fac_fruit fac_fruit
## [1] apple banana banana apple
## Levels: apple banana
1.3.4 날짜형, 날짜-시간형, 시간형 파싱
parse_date()
함수를 이용하면, “2010-01-01,” “1979-10-14” 등과 같은 날짜형의 문자열 요소로 구성하는 문자형 벡터를 인수로 하여, 날짜형 벡터로 변환할 수 있다. 예를 들면 다음과 갇다.
<- parse_date(c("2010-01-01", "1979-10-14"))
c c
## [1] "2010-01-01" "1979-10-14"
class(c)
## [1] "Date"
str(c)
## Date[1:2], format: "2010-01-01" "1979-10-14"
parse_date()
함수의 인수는 “문자열 벡터”이다.- 문자열 벡터의 각 요소가 “2010-01-01,” “1979-10-14” 등의 날짜 형태이다.
- 문자열 데이터
c("2010-01-01", "1979-10-14")
가parse_date()
함수에 의해 날짜형(Date
) 벡터로 변환된다.
parse_date() 함수와 함께 readr
패키지에는 parse_datetime()
함수와 parse_time()
함수가 있다. 이들 함수는 date
(1970-01-01 이후의 일 수), date-time
(1970-01-01 자정 이후의 초), time
(자정 이후의 초) 등에 따라 선택하면 된다. 추가적인 인수가 없는 각 파싱 함수의 사용 방법에 대하여 알아본다.
1.3.4.1 날짜형 벡터로 변환
parse_date()
함수를 이용하면, “2010-01-01,” “1979-10-14” 등과 같은 날짜형의 문자열 요소로 구성하는 문자형 벡터를 인수로 하여, 날짜형 벡터로 변환할 수 있다. 예를 들면 다음과 갇다.
<- parse_date(c("2010-01-01", "1979-10-14"))
c c
## [1] "2010-01-01" "1979-10-14"
class(c)
## [1] "Date"
str(c)
## Date[1:2], format: "2010-01-01" "1979-10-14"
parse_date()
함수의 인수는 “문자열 벡터”이다.- 문자열 벡터의 각 요소가 “2010-01-01,” “1979-10-14” 등의 날짜 형태이다.
- 문자열 데이터
c("2010-01-01", "1979-10-14")
가parse_date()
함수에 의해 날짜형(Date
) 벡터로 변환된다.
parse_date()
는 4 자리의 연도, -
또는 /
, 2 자리의 월, -
또는 /
, 그리고 2 자리의 날짜를 인수로 입력받는다. 예를 들면 다음과 같다.
parse_datetime("20101010")
## [1] "2010-10-10 UTC"
parse_date("2010-10-01")
## [1] "2010-10-01"
1.3.4.2 날짜-시간형 변환
parse_datetime()
은 ISO 8601 date-time
을 인수로 입력한다. ISO 8601
은 국제 표준인데 날짜가 가장 큰 것부터 가장 작은 것(즉, 년, 월, 일, 시, 분, 초)으로 구성된다. 예를 들면 다음과 같다.
parse_datetime("2010-10-01T2010")
## [1] "2010-10-01 20:10:00 UTC"
ISO 8601
은 가장 중요한 날짜/시간 표준이며, 날짜와 시간을 자주 다루는 경우 ISO 8601을 읽어볼 것을 추천한다.
1.3.4.3 시간형 변환
parse_time()
은 시 :
분 그리고 선택적으로 :
, 초, 선택적 a.m.
/p.m.
표시를 입력으로 한다.
base
R에는 시간 데이터를 위한 내장 클래스가 없기 때문에, 우리는hms
패키지에서 제공하는 클래스를 사용하기도 한다.
# install.packages("hms")
library(hms)
parse_time("01:10 am")
## 01:10:00
parse_time("20:10:01")
## 20:10:01
1.3.4.4 format
인수의 활용
날짜형, 날짜-시간형, 시간형 데이터를 앞에서 살펴 본 기본 형식으로 처리하지 못하는 경우, 다음과 같은 요소들로 이루어진 자신만의 날짜-시간 형식(format
)을 만들어 쓸 수 있다.
- Year
%Y
(4 자리).%y
(2 자리); 00-69 -> 2000-2069, 70-99 -> 1970-1999.
- Month
%m
(2 자리).%b
(“Jan”과 같이 축약된 명칭).%B
(전체 명칭, “January”).
- Day
%d
(2 자리).%e
(선택적 선행 공백).
- Time
%H
0-23 시간.%I
0-12,%p
와 함께 사용해야 함.%p
AM/PM 구분자.%M
분.%S
정수 초.%OS
실수 초.%Z
시간대 (이름, 예America/Chicago
).%z
(UTC 와의 오프셋, 예:+0800
).
- 숫자가 아닌 문자
%.
숫자가 아닌 문자 하나를 건너뛴다.%*
숫자가 아닌 문자 모두를 건너뛴다.
참고: 줄임말에 주의하라. ‘
EST
’는 일광 절약 시간제가 없는 캐나다 표준 시간대임을 주의하라. 그것은 동부 표준시가 아니다! 시간대에서 이를 다시 살펴보겠다.
1.3.4.5 날짜 형식의 지정 (숫자형 날짜)
올바른 포맷을 파악하는 가장 좋은 방법은 문자형 벡터로 몇 가지 예제를 만들고, 파싱 함수 중 하나로 테스트하는 것이다.예를 들면 다음과 같다.
parse_date("01/02/15", "%m/%d/%y")
## [1] "2015-01-02"
parse_date("01/02/15", "%d/%m/%y")
## [1] "2015-02-01"
parse_date("01/02/15", "%y/%m/%d")
## [1] "2001-02-15"
parse_date("2020년 06월 17일", "%Y년 %m월 %d일")
## Warning: 1 parsing failure.
## row col expected actual
## 1 -- date like %Y년 %m월 %d일 2020<U+00B3><e2> 06<U+00BF><f9> 17<c0><cf>
## [1] NA
1.3.4.6 날짜 형식의 지정 (알파벳 날짜명)
비영어권의 월 이름에 %b
또는 %B
를 사용하는 경우, locale()
의 lang
인수를 설정해야 한다. 이를 위해 date_names_langs()
를 콘솔에 입력하면 내장된 언어 목록을 확인할 수 있다.
date_names_langs()
## [1] "af" "agq" "ak" "am" "ar" "as" "asa" "az" "bas" "be" "bem" "bez"
## [13] "bg" "bm" "bn" "bo" "br" "brx" "bs" "ca" "cgg" "chr" "cs" "cy"
## [25] "da" "dav" "de" "dje" "dsb" "dua" "dyo" "dz" "ebu" "ee" "el" "en"
## [37] "eo" "es" "et" "eu" "ewo" "fa" "ff" "fi" "fil" "fo" "fr" "fur"
## [49] "fy" "ga" "gd" "gl" "gsw" "gu" "guz" "gv" "ha" "haw" "he" "hi"
## [61] "hr" "hsb" "hu" "hy" "id" "ig" "ii" "is" "it" "ja" "jgo" "jmc"
## [73] "ka" "kab" "kam" "kde" "kea" "khq" "ki" "kk" "kkj" "kl" "kln" "km"
## [85] "kn" "ko" "kok" "ks" "ksb" "ksf" "ksh" "kw" "ky" "lag" "lb" "lg"
## [97] "lkt" "ln" "lo" "lt" "lu" "luo" "luy" "lv" "mas" "mer" "mfe" "mg"
## [109] "mgh" "mgo" "mk" "ml" "mn" "mr" "ms" "mt" "mua" "my" "naq" "nb"
## [121] "nd" "ne" "nl" "nmg" "nn" "nnh" "nus" "nyn" "om" "or" "os" "pa"
## [133] "pl" "ps" "pt" "qu" "rm" "rn" "ro" "rof" "ru" "rw" "rwk" "sah"
## [145] "saq" "sbp" "se" "seh" "ses" "sg" "shi" "si" "sk" "sl" "smn" "sn"
## [157] "so" "sq" "sr" "sv" "sw" "ta" "te" "teo" "th" "ti" "to" "tr"
## [169] "twq" "tzm" "ug" "uk" "ur" "uz" "vai" "vi" "vun" "wae" "xog" "yav"
## [181] "yi" "yo" "zgh" "zh" "zu"
- 한국은
ko
임을 알 수 있다.
자신의 언어가 아직 포함되어 있지 않았으면 date_names()
를 사용하여 생성하라.
parse_date("1 janvier 2015", "%d %B %Y", locale = locale("fr"))
## [1] "2015-01-01"
parse_date("20-06-17", "%y-%m-%d")
## [1] "2020-06-17"
parse_date("2020-06-17", "%Y-%m-%d")
## [1] "2020-06-17"
parse_date("2020년 06월 17일", "%Y년 %m월 %d일")
## Warning: 1 parsing failure.
## row col expected actual
## 1 -- date like %Y년 %m월 %d일 2020<U+00B3><e2> 06<U+00BF><f9> 17<c0><cf>
## [1] NA
1.3.5 숫자형 벡터의 변환
숫자형 벡터를 파싱하는 것은 간단한 것처럼 보이지만, 다음과 같은 까다로운 세 가지 문제가 있다.
- 세계 여러 지역에서 사람들은 숫자를 다르게 쓴다. 예를 들어, 어떤 국가에서는 실수의 정수 부분과 소수 부분 사이에
.
를 쓰고, 다른 국가에서는,
를 쓴다. (decimal_mark
의 사용) - 숫자는 ‘$1000,’ ‘10%’ 와 같이 단위를 나타내는 기호가 붙어있을 때가 많다.
- 숫자는 ‘1,000,000’ 과 같이 쉽게 읽을 수 있도록 ‘그룹화’ 문자가 포함되는 경우가 많다. 이러한 그룹화 문자는 국가마다 다르다. (
grouping_mark
의 사용)
1.3.5.1 천 단위와 소숫점의 처리
첫 번째 문제를 해결하기 위해서 readr
패키지는 지역에 따라 파싱 옵션을 지정하는 객체로 ‘로캐일(locale)
’이라는 개념을 사용한다. 숫자를 파싱할 때 가장 중요한 옵션은 소수점으로 사용하는 문자이다. 새로운 로캐일을 생성하고 decimal_mark
인수를 설정하여 기본값인 .
를 다른 값으로 재정의할 수 있다.
숫자의 파싱에 있어서, 천 단위(grouping mark)의 표시와 소숫점(decimal mark)의 표시가 지역에 따라 다름을 잘 알고 있어야 한다. 예를 들어, 일반적으로 소숫점은 .
을 기호로 사용하는데, 어떤 경우에는 ,
를 소숫점 기호로 사용하는 경우도 있다. 이떄 locale 인수를 다음과 같이 설정하면 .
으로 변환할 수 있다.
parse_double("1.23")
## [1] 1.23
parse_double("1,23", locale = locale(decimal_mark = ","))
## [1] 1.23
readr
의 기본 로캐일은 미국식이다.
다른 방법은 운영체제의 기본값을 추측하여 시도하는 것이다. 이러한 방법은 잘 동작하지 않고, 더 중요한 것은 코드가 취약하게 된다. 자신의 컴퓨터에서 동작하더라도 코드를 다른 국가의 동료에게 이메일로 보낼 때 오류가 발생할 수 있다.
1.3.5.2 화폐 기호, 백분율(%) 기호, 그리고 문자열의 처리
두 번째 문제를 처리하는 parse_number()
는 숫자 앞뒤에 숫자가 아닌 문자(non-numeric character) 를 무시하는 것이다. 통화 기호와 백분율에 특히 유용하지만, 텍스트에 포함된 숫자를 추출하는 데에도매우 효과적으로 사용할 수 있다.
다음의 경우는 parse_number()
함수의 인수에 포함되어 있는 화폐 단위의 기호($
), %
, 그리고 문자열 등을 모두 제거하고 숫자만 반환하는 예이다.
parse_number("$100")
## [1] 100
parse_number("20%")
## [1] 20
parse_number("It cost $123.45")
## [1] 123.45
1.3.5.3 국가와 대륙별 차이의 처리
마지막 문제는 parse_number()
와 locale=
인수를 조합하여, parse_number()
가 “.
”을 무시하게(locale(grouping_mark = ".")
함으로써 해결할 수 있다.
1.3.5.3.1 미주 방식
미주방식에서는 grouping mark
를 ,
로 그리고 decimal mark
로는 .
를 사용하고 있는데, 이는 다음과 같이 처리한다.
parse_number("$123,456,789")
## [1] 123456789
1.3.5.3.2 유럽의 많은 국가 방식
한편 유럽의 많은 국가들은 grouping mark
로 .
를 그리고 decimal mark
로 ,
를 사용하는데 이는 다음과 같이 처리한다.
parse_number("123.456.789", locale = locale(grouping_mark = "."))
## [1] 123456789
1.3.5.3.3 스위스 방식
특히 스위스는 grouping mark
로 '
또는 (공란)을 그리고
decimal mark
로는 .
을 사용한다.
parse_number("123'456'789", locale = locale(grouping_mark = "'"))
## [1] 123456789
1.3.5.4 decimal_mark
와 grouping_mark
의 관련성
소숫점 표시(decimal mark)와 그루핑 마크(grouping mark)를 같은 문자를 설정하면, locale
은 에러를 발생하게 된다.
locale(decimal_mark = ".", grouping_mark = ".") #
## Error: `decimal_mark` and `grouping_mark` must be different
- decimal mark와 grouping mark는 같은 부호를 사용하면 안됨.
현재 설정되어 있는 locale을 확인하는 방법은 다음과 같다.
locale()
## <locale>
## Numbers: 123,456.78
## Formats: %AD / %AT
## Timezone: UTC
## Encoding: UTF-8
## <date_names>
## Days: Sunday (Sun), Monday (Mon), Tuesday (Tue), Wednesday (Wed), Thursday
## (Thu), Friday (Fri), Saturday (Sat)
## Months: January (Jan), February (Feb), March (Mar), April (Apr), May (May),
## June (Jun), July (Jul), August (Aug), September (Sep), October
## (Oct), November (Nov), December (Dec)
## AM/PM: AM/PM
Numbers
에 숫자의 표현형식이 표시되어 있다.- 그 밖에도
Formats
,Timezone
,Encoding
,Days
,Months
,AM/PM
등이 있음을 알 수 있다.
이제 decima mark
를 .
로 지정해 보자. 그러면 자동적으로 grouping mark는 .
으로 설정됨을 알 수 있다.
locale(grouping_mark = ".")
## <locale>
## Numbers: 123.456,78
## Formats: %AD / %AT
## Timezone: UTC
## Encoding: UTF-8
## <date_names>
## Days: Sunday (Sun), Monday (Mon), Tuesday (Tue), Wednesday (Wed), Thursday
## (Thu), Friday (Fri), Saturday (Sat)
## Months: January (Jan), February (Feb), March (Mar), April (Apr), May (May),
## June (Jun), July (Jul), August (Aug), September (Sep), October
## (Oct), November (Nov), December (Dec)
## AM/PM: AM/PM
locale
## function (date_names = "en", date_format = "%AD", time_format = "%AT",
## decimal_mark = ".", grouping_mark = ",", tz = "UTC", encoding = "UTF-8",
## asciify = FALSE)
## {
## if (is.character(date_names)) {
## date_names <- date_names_lang(date_names)
## }
## stopifnot(is.date_names(date_names))
## if (asciify) {
## date_names[] <- lapply(date_names, stringi::stri_trans_general,
## id = "latin-ascii")
## }
## if (missing(grouping_mark) && !missing(decimal_mark)) {
## grouping_mark <- if (decimal_mark == ".")
## ","
## else "."
## }
## else if (missing(decimal_mark) && !missing(grouping_mark)) {
## decimal_mark <- if (grouping_mark == ".")
## ","
## else "."
## }
## stopifnot(decimal_mark %in% c(".", ","))
## stopifnot(is.character(grouping_mark), length(grouping_mark) ==
## 1)
## if (decimal_mark == grouping_mark) {
## stop("`decimal_mark` and `grouping_mark` must be different",
## call. = FALSE)
## }
## check_tz(tz)
## check_encoding(encoding)
## structure(list(date_names = date_names, date_format = date_format,
## time_format = time_format, decimal_mark = decimal_mark,
## grouping_mark = grouping_mark, tz = tz, encoding = encoding),
## class = "locale")
## }
## <bytecode: 0x000000001b8ccbd8>
## <environment: namespace:readr>
Numbers
에 숫자의 표현형식이 변경되었음을 확인할 수 있다.
다시 grouping mark를 “,”로 변경해 보자. 그런데 이번에는 decimal mark를 .
으로 변경해 보기로 한다.
locale(decimal_mark = ".")
## <locale>
## Numbers: 123,456.78
## Formats: %AD / %AT
## Timezone: UTC
## Encoding: UTF-8
## <date_names>
## Days: Sunday (Sun), Monday (Mon), Tuesday (Tue), Wednesday (Wed), Thursday
## (Thu), Friday (Fri), Saturday (Sat)
## Months: January (Jan), February (Feb), March (Mar), April (Apr), May (May),
## June (Jun), July (Jul), August (Aug), September (Sep), October
## (Oct), November (Nov), December (Dec)
## AM/PM: AM/PM
locale
## function (date_names = "en", date_format = "%AD", time_format = "%AT",
## decimal_mark = ".", grouping_mark = ",", tz = "UTC", encoding = "UTF-8",
## asciify = FALSE)
## {
## if (is.character(date_names)) {
## date_names <- date_names_lang(date_names)
## }
## stopifnot(is.date_names(date_names))
## if (asciify) {
## date_names[] <- lapply(date_names, stringi::stri_trans_general,
## id = "latin-ascii")
## }
## if (missing(grouping_mark) && !missing(decimal_mark)) {
## grouping_mark <- if (decimal_mark == ".")
## ","
## else "."
## }
## else if (missing(decimal_mark) && !missing(grouping_mark)) {
## decimal_mark <- if (grouping_mark == ".")
## ","
## else "."
## }
## stopifnot(decimal_mark %in% c(".", ","))
## stopifnot(is.character(grouping_mark), length(grouping_mark) ==
## 1)
## if (decimal_mark == grouping_mark) {
## stop("`decimal_mark` and `grouping_mark` must be different",
## call. = FALSE)
## }
## check_tz(tz)
## check_encoding(encoding)
## structure(list(date_names = date_names, date_format = date_format,
## time_format = time_format, decimal_mark = decimal_mark,
## grouping_mark = grouping_mark, tz = tz, encoding = encoding),
## class = "locale")
## }
## <bytecode: 0x000000001b8ccbd8>
## <environment: namespace:readr>
- decima mark를
.
으로 지정하면, 자동으로 grouping mark는,
으로 바뀜을 알 수 있다.
연습문제
locale()
에서 가장 중요한 인수들은 무엇인가?locale()
함수는 다음과 같은 인수들이 있다:- 날짜와 시간 형식 :
date_names
,date_format
, 그리고time_format
- 시간대 :
tz
- 숫자 :
decimal_mark
,grouping_mark
- 인코딩 :
encoding
- 날짜와 시간 형식 :
decimal_mark
와grouping_mark
를 동일 문자로 설정하려고 하면 어떻게 되는가?decimal_mark
를 ‘,’로 설정하면grouping_mark
의 기본값은 어떻게 되는가?소숫점 표시와 그루핑 마크가 같은 문자로 설정되어 있으면
locale
은 에러를 발생시킨다:# locale(decimal_mark = ".", grouping_mark = ".")
소숫점 표시(
decimal_mark
)가 컴마(","
)로 설정되어 잇으면, 그루핑 마크(grouping_mark
)는 점("."
)으로 설정된다.locale(decimal_mark = ",")
## <locale> ## Numbers: 123.456,78 ## Formats: %AD / %AT ## Timezone: UTC ## Encoding: UTF-8 ## <date_names> ## Days: Sunday (Sun), Monday (Mon), Tuesday (Tue), Wednesday (Wed), Thursday ## (Thu), Friday (Fri), Saturday (Sat) ## Months: January (Jan), February (Feb), March (Mar), April (Apr), May (May), ## June (Jun), July (Jul), August (Aug), September (Sep), October ## (Oct), November (Nov), December (Dec) ## AM/PM: AM/PM
그루핑 마크(
grouping_mark
)가 컴마(","
)으로 설정되어 있으면, 소숫점 표시(decimal_mark
)는 점("."
)으로 설정된다:locale(grouping_mark = ",")
## <locale> ## Numbers: 123,456.78 ## Formats: %AD / %AT ## Timezone: UTC ## Encoding: UTF-8 ## <date_names> ## Days: Sunday (Sun), Monday (Mon), Tuesday (Tue), Wednesday (Wed), Thursday ## (Thu), Friday (Fri), Saturday (Sat) ## Months: January (Jan), February (Feb), March (Mar), April (Apr), May (May), ## June (Jun), July (Jul), August (Aug), September (Sep), October ## (Oct), November (Nov), December (Dec) ## AM/PM: AM/PM
locale()
의date_format
및time_format
옵션에 대해서는 논의하지 않았다. 이 들이 하는 일은 무엇인가? 이들이 유용할 수 있는 경우를 보여주는 예제를 작성해보라.- 이것들은 디폴트의 날짜와 시간 형식을 제공한다. readr vignette 는 날짜를 파싱하기 위해 이 함수들을 이용하는 것에 대하여 다루고 있다: 날짜는 언어 특유의 요일과 월 이름 그리고 AM/PM에 대한 서로 다른 표기법을 가지고 있을 수 있기 때문이다.
locale()
## <locale> ## Numbers: 123,456.78 ## Formats: %AD / %AT ## Timezone: UTC ## Encoding: UTF-8 ## <date_names> ## Days: Sunday (Sun), Monday (Mon), Tuesday (Tue), Wednesday (Wed), Thursday ## (Thu), Friday (Fri), Saturday (Sat) ## Months: January (Jan), February (Feb), March (Mar), April (Apr), May (May), ## June (Jun), July (Jul), August (Aug), September (Sep), October ## (Oct), November (Nov), December (Dec) ## AM/PM: AM/PM
- 프랑스 날짜를 파싱한
readr vignette
의 예를 들면 다음과 같다:
parse_date("1 janvier 2015", "%d %B %Y", locale = locale("fr"))
## [1] "2015-01-01"
parse_date("14 oct. 1979", "%d %b %Y", locale = locale("fr"))
## [1] "1979-10-14"
- 확실히 시간 형식은 사용되지 않지만, 날짜 형식은 열의 데이터 형식을 파악하는데 사용된다.
가장 많이 읽는 파일 형식에 대한 설정을 압축한 새로운 로캐일 객체를 만들어 보라.
설정될 수 있는 상이한 변수들에 대해 알고 싶으면
?locale()
를 이용하여locale()
도움말을 참조한다.호주를 예를 들어 보겠다.
02/02/2007
으로 ‘January 2, 2006’을 의미하는 날짜 형식이 “(d)d/mm/yyyy”라는 것을 제외하면, 대부분의 디폴트 값이 유효하다.그러나, 드폴트 locale은 날짜를 February 1, 2006으로 파싱할 것이다.
parse_date("02/01/2006")
## Warning: 1 parsing failure. ## row col expected actual ## 1 -- date like 02/01/2006
## [1] NA
호주의 날짜를 정확히 파싱하기 위해서는 새로운
locale
오브젝트를 정의해야 한다:<- locale(date_format = "%d/%m/%Y") au_locale
locale을 au_locale로 하고
parse_date()
를 사용하면 날짜를 정확히 파싱할 것이다:parse_date("02/01/2006", locale = au_locale)
## [1] "2006-01-02"
read_csv()
와read_csv2()
은 무엇이 다른가?- 구분자의 차이이다.
read_csv()
함수는 컴마를 구분자로 사용하면 반면에read_csv2()
함수는 세미콜론(;
)을 사용한다. 세미콜론을 사용하는 것은 컴마가 소숫점으로 사용(예를 들어 유럽에서 처럼)될 때 유용하다.
- 구분자의 차이이다.
유럽에서 사용되는 가장 일반적인 인코딩은 무엇인가? 아시아에서 가장 많이 사용되는 인코딩은 무엇인가? 구글 검색해서 알아보라.
- 아랍어와 베트남어는 ISO와 윈도우즈 표준을 가지고 있다. 다른 주요 아시어 언어는 그들 자신만의 표준을 가지고 있다:
- 일본어 : JIS X 0208, Shift JIS, ISO-2022-JP
- 중국어 : GB 2312, GBK, GB 18030
- 한국어 : KS X 1001, EUC-KR, ISO-2022-KR
stringi::stri_enc_detect
의 문서에 있는 목록은 가장 보통의 인코딩을 지원하기 때문에 인코딩 목록을 잘 보여주고 있다.- 서유럽 라틴 언어 : ISO-8859-1, Windows-1250 (also CP-1250 for code-point)
- 동유럽 라틴 언어 : ISO-8859-2, Windows-1252
- 그리스어 : ISO-8859-7
- 터키어 : ISO-8859-9, Windows-1254
- 히브리어 : ISO-8859-8, IBM424, Windows 1255
- 러시아어 : Windows 1251
- 일본어 : Shift JIS, ISO-2022-JP, EUC-JP
- 한국어 : ISO-2022-KR, EUC-KR
- 중국어 : GB18030, ISO-2022-CN (Simplified), Big5 (Traditional)
- 아랍어 : ISO-8859-6, IBM420, Windows 1256
문자열 인코딩에 대한 보다 상세한 내용은 다음의 사이트를 참고하라.
- Wikipedia 페이지 Character encoding
- Unicode CLDR 프로젝트
- What is the most common encoding of each language (Stack Overflow)
- “What Every Programmer Absolutely, Positively Needs To Know About Encodings And Character Sets To Work With Text,” http://kunststube.net/encoding/.
텍스트 인코딩을 다루는 프로그램들은 다음과 같다:
- 아랍어와 베트남어는 ISO와 윈도우즈 표준을 가지고 있다. 다른 주요 아시어 언어는 그들 자신만의 표준을 가지고 있다:
올바른 형식 문자열을 생성하여 다음 날짜와 시간을 파싱하라.
<- "January 1, 2010" d1 <- "2015-Mar-07" d2 <- "06-Jun-2017" d3 <- c("August 19 (2015)", "July 1 (2015)") d4 <- "12/30/14" # Dec 30, 2014 d5 <- "1705" t1 <- "11:15:10.12 PM" t2
- The correct formats are:
parse_date(d1, "%B %d, %Y")
## [1] "2010-01-01"
parse_date(d2, "%Y-%b-%d")
## [1] "2015-03-07"
parse_date(d3, "%d-%b-%Y")
## [1] "2017-06-06"
parse_date(d4, "%B %d (%Y)")
## [1] "2015-08-19" "2015-07-01"
parse_date(d5, "%m/%d/%y")
## [1] "2014-12-30"
parse_time(t1, "%H%M")
## 17:05:00
parse_time(t2, "%H:%M:%OS %p")
## 23:15:10.12