R for Data Science::tibbles and data import
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 = '#')
- 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파일로 내보내는 함수.
이 정도는 쉬우니까 간단히 넘어가겠다.