DS Study/R4DS(R언어)

[R4DS] [5] readr로 하는 데이터 불러오기

23학번이수현 2024. 4. 5. 13:49

1. Introduce

- R 패키지가 제공하는 데이터를 이용하여 데이터 과학 도구를 익히는 것은 좋은 방법이다.

- 이번 챕터에서는 일반 텍스트 직사각형 파일을 R로 불러오는 방법을 배운다.

 

-tidyverse 패키지에 존재하는 readr패키지를 사용하여 flat파일을 불러오는 방법을 학습할것이다.

cf) flat file : 구조화 되어 있지 않은 파일

 

2. 시작하기

- readr 함수 대부분은 플랫 파일을 데이터프레임으로 바꾸는 것과 연관이 있다.

- read_csv() : 쉼표로 구분된 파일을 읽음

- read_csv2() : 세미콜론으로 구분된 파일

- read_tsv() : tap으로 구분된 파일

- read_delim() : 임의의 구분자로 된 파일

 

- 해당 함수들은 문법이 모두 비슷함 

 

- read_csv()의 첫 번째 인수가 11081가장 중요한데 바로 읽으려고 하는 파일의 경로임.

ex)

heights <- read_csv("/Users/isuhyeon/Desktop/Data/heights.csv")

 

heights
# A tibble: 1,192 × 6
    earn height sex       ed   age race    
   <dbl>  <dbl> <chr>  <dbl> <dbl> <chr>   
 1 50000   74.4 male      16    45 white   
 2 60000   65.5 female    16    58 white   
 3 30000   63.6 female    16    29 white   
 4 50000   63.1 female    16    91 other   
 5 51000   63.4 female    17    39 white   
 6  9000   64.4 female    15    26 white   
 7 29000   61.7 female    12    49 white   
 8 32000   72.7 male      17    46 white   
 9  2000   72.0 male      15    21 hispanic
10 27000   72.2 male      12    26 white   
# ℹ 1,182 more rows
# ℹ Use `print(n = ...)` to see more rows

 

- 인라인 CSV파일을 넣을 수도 있다. 

ex)

a <- read_csv("a,b,c
              1,2,3
              4,5,6")
# A tibble: 2 × 3
      a     b     c
  <dbl> <dbl> <dbl>
1     1     2     3
2     4     5     6

 

- read_csv()는 데이터의 첫 번째 줄을 열 이름으로 사용한다.

- 근데 이 규칙을 조정해야 하는 경우가 두 가지가 존재한다

 

1) 파일 앞 부분에 메타데이터(다른 데이터를 설명해주는 데이터 ex: 주석) n 줄이 있는 경우이다.

- skip = n 을 사용하여 첫 n줄을 건너 뛸 수 있다. 

a <- read_csv("메타데이터 1
              메타데이터 2
              x,y,z
              1,2,3",skip = 2)
# A tibble: 1 × 3
      x     y     z
  <dbl> <dbl> <dbl>
1     1     2     3

 

- commnet = "#"을 사용하여 #으로 시작하는 모든 줄을 무시할 수 있다.

 

a <- read_csv("#건너뛰고싶은 주석
              x,y,z
              1,2,3",commnet = "#")
# A tibble: 1 × 3
      x     y     z
  <dbl> <dbl> <dbl>
1     1     2     3

 

2) 데이터에 열 이름이 없을 수 있다. 

- col_names = FALSE를 사용하면 X1~Xn 까지 순차적으로 이름을 붙임

a <- read_csv("1,2,3\n4,5,6",col_names= FALSE)
# A tibble: 2 × 3
     X1    X2    X3
  <dbl> <dbl> <dbl>
1     1     2     3
2     4     5     6

- 문자형 벡터를 전달할 수도 있다.

a <- read_csv("1,2,3\n4,5,6",col_names= c('a','b','c'))
# A tibble: 2 × 3
      a     b     c
  <dbl> <dbl> <dbl>
1     1     2     3
2     4     5     6

 

- 결측값 조정하는 방법

read_csv("a,b,c\n1,2,.",na='.')
# A tibble: 1 × 3
      a     b c    
  <dbl> <dbl> <lgl>
1     1     2 NA

 

2.1.베이스 R과 비교

i) 일반적으로 베이스 함수보다 10배 더 빠르다.

ii) tibble 을 생성한다.

 

2.2 연습문제

Q1) 필드가 "|"로 분리된 파일을 읽으려면 어떤 함수를 사용하겠는가?

data <- read_delim("file.txt", delim = "|")

- read_delin("file", delim = "|")

 

Q2) read_fwf()에서 가장 중요한 인수는 무엇인가? 

- read_fwf()는 고정 너비 파일을 읽는다.

- 필드 너비는 fwf_widths()를 이용하여,
- 필드 위치는 fwf_positions() 이용

 

3. 벡터 파싱하기 

- parse_*() : 문자형 벡터를 입력으로 하여 논리형, 정수형 또는 날짜형과 같은 좀 더 특수화된 벡터를 반환함

> str(parse_logical(c("TRUE","FALSE","NA")))
 logi [1:3] TRUE FALSE NA
> str(parse_integer(c("1","2","3")))
 int [1:3] 1 2 3
> str(parse_date(c("2010-01-01","1979-10-14")))
 Date[1:2], format: "2010-01-01" "1979-10-14"

- python 에서 map과 비슷한 느낌이라고 생각하면 좋다.

 

-parse_logical() : 논리형을 파싱

-parse_integer() : 정수형 파싱

-parse_double() : 엄격한 수치형 파서

-parse_number() : 유연한 수치형 피사

-parse_character() : 문자 인코딩

-parse_factor() : 팩터형 파싱

-parse_datetime(), parse_date(),parse_time() : 다양한 날짜와 시간 데이터 파싱

 

3.1 숫자

- 숫자 파싱은 간단해 보이지만, 다음의 세 가지 문제 때문에 까다롭다.

i) 세계 여러 지역에서 사람들은 숫자를 다르게 쓴다.

ii) 숫자는 '$1000' '10%'와 같이 단위를 나타내는 다른 문자가 붙어있을 때가 많다.

iii)'1,000,000'과  같이 쉽게 읽을 수 있도록 '그룹화' 문자가 포함되는 경우가 많다.

 

- 첫 번째 문제를 해결하기 위해서 readr은 지역에 따라 파싱 옵션을 지정하는 객체인 '로캘(locale')이라는 개념을 사용한다.

- 숫자를 파싱할 때 가장 중요한 옵션은 소수점으로 사용하는 문자이다.

-decimal_mark인수를 설정하여 기본값인 . 를 다른 값으로 재정의할 수 있다.

parse_double("1.23")
[1] 1.23


parse_double("1,23",locale=locale(decimal_mark = ","))
[1] 1.23

 

 

- 두번째 문제를 해결하는 방법 parse_number()은 숫자 앞뒤의 비수치문자(non-numeric character)를 무시한다.

- 통화 및 백분율에 특히 유용하지만, 텍스트에 포함된 숫자를 추출하는 데도 효과적이다.

parse_number("당신의 숫자는 8입니다.")
[1] 8
parse_number("8$")
[1] 8

 

-마지막 문제는 parse_number()와 로캘을 조합하여 parse_number()가 '그룹화 마크'를 무시하도록 함으로써 해결할 수 있다.

parse_number("123.456.789",
+              locale = locale(grouping_mark = "."))
[1] 123456789

 

3.2 연습문제

Q1) locale()에서 가장 중요한 인수들은 무엇인가?

 - decimal_mark : 소수점 기호 지정

- grouping_mark: 숫자의 그룹 구분 기호 지정

 

Q2) decimal_mark & grouping_mark를 동일 문자로 설정하려고 하면 어떻게 되는가?

parse_number("123.456.789",
+              locale = locale(grouping_mark = ".",decimal_mark = "."))
Error: `decimal_mark` and `grouping_mark` must be different

- 다른 값으로 지정해주라는 오류가 뜬다.

 

Q3) 가장 많이 읽는 파일 형식에 대한 설정을 압축한 새로운 로컬 객체를 만들어 보라.

library(readr)

# 일반적으로 사용되는 파일 형식에 대한 로컬 객체 생성
common_locale <- locale(decimal_mark = ".", grouping_mark = ",", 
                        date_format = "%Y-%m-%d", time_format = "%H:%M:%S")

# 새로운 로컬 객체 확인
common_locale
<locale>
Numbers:  123,456.78
Formats:  %Y-%m-%d / %H:%M:%S
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

Q4) read_csv() 와 read_csv2()의 차이점은 무엇인가?

- read_csv() : , 을 기준으로 분리한다.

- read_csv2() : ; 을 기준으로 분리한다.

 

4. 파일 파싱하기

- 지금까지 개별 벡터를 파싱하는 방법을 배웠으니, readr이 파일을 파싱하는 방법에 대해 알아보자.

- 다음과 같이 두 방법을 배운다

 

i) readr이 각 열의 유형을 자동으로 추측하는 방법

ii) 기본 사양을 재정의하는 방법

 

4.1. 전략

- readr은 휴리스틱 방법을 사용하여 각 열의 유형을 파악한다.

- 첫 번째 1000행을 읽고 휴리스틱 방법을 사용하여 각 열의 유형을 찾는다.

 

-guess_parser() : readr의 추정을 반환

-parse_guess() : 앞의 추정을 사용하여 열을 파싱 

 

> guess_parser("2010-10-01")
[1] "date"
> guess_parser("15:01")
[1] "time"
> guess_parser(c("TRUE","FALSE"))
[1] "logical"
> guess_parser(c("1","2","3"))
[1] "double"
> guess_parser(c("12,352,561"))
[1] "number"

> str(parse_guess("2010-10-10"))
 Date[1:1], format: "2010-10-10"

 

- 이 휴리스틱 방법은 다음 유형들을 각각 시도하여 일치하는 항목을 찾으면 멈춘다.

 

논리형

- "F","T","FALSE","TRUE"

정수형

- 수치형 문자만 포함.

더블형

-유효한 더블형만 포함

수치형

- 내부에 그룹화 마크가 있는 유효한 더블형을 포함.

타임형

- time_format과 일치

데이트형

- date_format과 일치

데이트 타임형

- ISO 8601 날짜

 

- 이러한 규칙 중 어느 것도 적용되지 않으면 해당 열은 문자열 벡터로 그대로 남는다.