R/Exploratory data analysis

R for Data Science::tibbles and data import

Abokadoh 2023. 6. 8. 18:03

1. tibble ?

tibble은 dataframe이라고 할 수 있다. 데이터프레임을 여러 과정에서 유리하도록 수정한 것이다. 기존에 df에서 as_tibble()로 변환이 가능하다.

 

library(tidyverse)
as_tibble(iris)

그렇다면 tibble과 dataframe은 어떠한 것이 다른가? 살펴보도록 하겠다.

 

우선 tibble은 직전에 정의했던 변수로 새로운 변수를 정의하는 것이 가능하다. 이게 뭔 소린지 모르겠다면 예제 코드로 이해해 보자! 

tibble(
  x = 1:5, 
  y = 1, 
  z = x ^ 2 + y
)

 

이렇게 직전에 정의한 x, y를 이용하여 z변수를 정의할 수 있다는 말이다. 이게 data frame에서는 안되냐고? 

data.frame(
  x = 1:5, 
  y = 1, 
  z = x ^ 2 + y
)

응 안돼

 

tibble은 또한 tibble을 생성했을 때 생성된 tibble의 10행과 사용자의 스크린이 허용하는(스크린사이즈에 맞게) 열의 개수를 설정하여 보여준다. 

요런식으로 님의 console창의 크기에 맞게 적당한 열의 개수를 자동으로 파악해 뽑아서 보여준다. dataframe은 만들어보면 알겠지만 전체 데이터를 다 보여줘서 보기에 불편한 경우가 있었던 경험이 있다. 

의미 없이 다 보여줌. 이런 식의 return은 솔직히 의미가 읍다.( 자료를 파악하기 힘듦 ) 

 

또 tibble은 위에서 보이듯 str() 함수에서 따온 feature의 정보 dttm, date, int... 같은 것도 알려준다. 개꿀! 

 

tilbble에서 출력됐는지 행의 개수와 열의 개수는 커스텀이 가능하다.

nycflights13::flights %>% 
  print(n = 10,width = Inf)

nycflights13 패키지의 flights data는 tibbledle 이다. Inf는 infinity의 약어로 열의 개수를 끝까지 다 보이도록 한다.

요렇게 생략 없이 column을 다 보여준다.

 

- tibble subsetting

tibble은 다양한 방법으로 subset이 가능하다. 예제로 공부해 보자.

df <- tibble(
  x = runif(5),
  y = rnorm(5),
  )

df$x
df[["x"]]
df[[1]]

모두 같은 값을 반환한다. 

근데 이 기능은 data.frame에서도 똑같이 작동한다. 안 되는 줄  ㅎㅎ

Extract by position은 안 될 줄 알았음.

 

파이프 연산을 통해서도 가능하다. 파이프 연산을 이런 경우에는 처음 써봤다.

df %>% .$x
df %>% .[['x']]

 

- Data import ( readr:: read_csv)

우리는 앞서 R에 데이터를 불러오기 위해 readr 패키지를 사용한 경험이 있다. tidyverse 패키지만 열어도 readr은 불러진다.

데이터를 열어보장.

   - read_csv(data, comment = ) 

library(tidyverse)

heights <- read_csv('/Users/username/Desktop/heights.csv',comment = '#')

heights.csv
0.05MB

   - read_csv(data, skip = n ) 

heights <- read_csv('/Users/choehyeogjae/Desktop/heights.csv',skip=1)

comment = 옵션에 대해서 설명하자면 heights.csv를 text편집기로 열어보면 최상단에 'this is heights.csv' 라는 타이틀이 있는데, 이걸 데이터로 취급 안 하겠다는 말이다. '#'이 붙은 내용은 데이터가 아니다!~! 요런 기능이다. 

 

물론 첫 줄은 skip하겠다~는 의미로 skip argument를 사용하는 것도 가능하다.

 

 

   - read_csv(data, col_names = FALSE ) 

read_delim("a|b|c\n1|2|3",delim ="|",col_names = FALSE )

 

read_delim은 구분자  설정도 가능하다.!

 

 

heights 데이터의 경우 2번째에 column names이 제공되지만 colmn name이 제공되지 않은 위와 같은 dataset의 경우 col_names = FALSE를 지정해 주거나, col_names = c('칼럼 1', '칼럼 2', '칼럼 3',...)와 같이 컬럼이름 벡터를 사용해 컬럼명을 설정해 줄 수 있다.

 

코드로 익혀보자.!

 

read_csv("The first line of metadata
  The second line of metadata
  x,y,z
  1,2,3", skip = 2)

위 코드에서 inline에 넣은 csv형식의 데이터가 잇다. csv는 뭐 대단한 게 아니라 , <- 쉼표로 data unit이 나뉘어 있는 데이터를 의미한다. (..혹시 모르실 분들을 위해. )

 

우리 눈엔 보이지 않겠지만 컴퓨터는 이 csv data를 The first line of metadata \n, The second line of metadata \n, .. 이런 식으로 문장 바뀜을 인식하고 있다. 때문에 skip =2 옵션을 추가해 주면 2번째 줄까지인 타이틀 The second line of metadata' 까지는 skip하도록 한다. 그리고 default값으로 첫 번째 줄을 column names으로 인식하기 때문에 반환되는 값은?

1행 3열 칼럼으로 인식하고 delimiter는 read_csv이기 때문에 자동으로 ', '으로 설정되어 있음을 확인할 수 있다. 

read_csv("# A comment I want to skip
  x,y,z
  1,2,3", comment = "#")

이번엔 comment argument도 사용해 보자.

 

이 csv 파일의 첫단은 # A comment I want to skip\n 이다. comment ='#'을 사용하여 생략이 가능하다.

 

 

read_csv("1,2,3\n4,5,6", col_names = FALSE)

앞에서 언급했다시피 col name이 없는 데이터는 read_csv로 열어줄 때 col_names = FALSE를 입력해줘야 한다.

col_names =FALSE를 해주면 자동으로 컬럼명에 X1, X2, X3를 순차적으로 라벨링해준다. 이게 싫다면 col_names에 피쳐개수에 맞는 vector를 넣어주면 된다.

read_csv("1,2,3\n4,5,6", col_names = c("x", "y", "z"))

 

요런식으로

 

   - read_csv(data, na = ) 

read_csv("a,b,c\n1,2,.", na = ".")
read_csv("a,b,c\n1,2,.")

na argument는 특정 값에 대해서 NA취급을 하는 것을 명령한다.

첫 번째 코드에 대한 결과는 '.' 에대해서 '.'에 대해서 NA값으로 반환했지만 두 번째 코드는 na argument를 사용하지 않아.

'.'을 value로 취급한 것을 확인할 수 있다.

 

Exercise 11.2.2

What function would you use to read a file where fields were separated with '|' ?

 

구분자가 '|' 인 파일을 읽을 때 어떤 함수를 사용할거냐?! 

매우 쉽다. readr 패키지의 read_csv가 아님 뤼드 대림을 사용하면 된다. delim, delim, delim 기억해 두자..

 

read_delim("a|b|c\n|1|2|3", delim = '|', col_names = FALSE)

Parsing a vector

vector를 parsing 하는 게 뭔말인진 모르겠으나 코드로 보면서 받아들이도록 하자.

str(parse_logical(c('TRUE','FALSE','NA')))

음..  문자열인 vector를 의미에 맞게 logi type으로 바꿔준다는 말인가?... 좀 더 보도록 하자. 아직은 확신이 없다.

str(parse_integer(c("1","2","3")))

아. character vector를 특정 type으로 변환해 주는 개념인 것 같다. ! 

str(parse_date(c('2020-01-01', '1979-10-14')))
parse_integer(c("1", "231", ".", "456"), na = ".")

이렇게 다양한 parse_*() 함수가 있다.

 

이제 예제 코드를 통해 parse_*()함수에 대해서 더 공부해 보자.

 

parse_double('1.23')

어떤 국가에서는 소수 1.23을 다음과 같이 쓴다.

하지만 또 다른 특정 국가에서는 소수를 1,23으로 쓴다. 이런 경우 1.23을 어떻게 표준으로 변환할 것인가.

 

parse_double('1,23', locale = locale(decimal_mark = ","))

기적이 일어났다.

 

세상에는 다양한 기호가 있다. 달러($), 퍼센트(%), 원(won) 이런 단위가 당장 불필요할 때 또한 parse_*()함수가 사용될 수 있다.

parse_number('$100')
parse_number('20%')
parse_number("30원")

많이 쓰게 될 것 같은 느낌이 든다.

 

parse_number("$123,456,789")
parse_number("$123,456,789", locale = locale(grouping_mark = ','))
parse_number("123.456.789", locale = locale(grouping_mark = '.'))
parse_number("123'456'789", locale = locale(grouping_mark = "'"))

-parse_factor()  -> 여기에 있으면 안 되는 데이터 찾기.

fruit <- c("apple", "banana")
parse_factor(c("apple", "banana", "bananana"), levels = fruit)

level로 지정된 apple, banana 외에 값들에 대해서는 모두 NA값을 반환한다. 

이를 통해 parse_factor() 함수는 입력값이 주어진 팩터 수준에 부합하지 않을 경우 이를 잡아내는 유용한 방법을 제공한다.  이러한 기능은 데이터 클리닝 과정에서 특히 유용하게 사용될 수 있을 것이라고 할 수 있겠다.

 

-parse_datetime()

우리가 앞으로 데이터를 받을 때 다양한 표시로 날짜 데이터를 받게 될 것이다. 그게 뭔 말이냐고? 사람들마다 날짜를 적는 방식이 매우 다양하기 때문에 우리는 이에 대비하여 그러한 날짜 데이터를 표준화된 데이터로 바꾸는 방법을 알고 있을 필요가 있다. 

parse_datetime("2010-10-01T2010")
"2010-10-01 20:10:00 UTC"

 

parse_datetime('20101010')
"2010-10-10 UTC"
parse_date('2010-10-01')
"2010-10-01"
parse_date('01/02/15', '%m/%d/%y')
"2015-02-01"

월/일/연 순으로 기입된 날짜 데이터를 표준으로 바꿀 때는 위치에 맞게 %로 각각 position을 지정할 수 있다.

parse_date('01/02/15', '%y/%m/%d')
"2001-02-15"

- guess_parser()

guess_parser()는 데이터가 어떤 데이터일지 나름의 룰에서 결과를 추출해 우리에게 반환해 준다.

guess_parser('2020-10-10')
"date"
guess_parser(c(T,F))
guess_parser(c('T','F'))
guess_parser(c('T','S'))

솔직히 언제 사용되는지 감은 잘 안 온다. ㅎㅎ

 

 

- write_csv(), write_rds()

write_csv(iris, 'iris.csv')
write_rds(list(iris,cars), 'iris_car.rds')

iris데이터를 csv파일로 내보내는 함수.

iris데이터의 cars column vector를 rds파일로 내보내는 함수. 

이 정도는 쉬우니까 간단히 넘어가겠다.