20  스프레드시트

20.1 소개

Chapter 7 에서 .csv.tsv와 같은 일반 텍스트 파일에서 데이터를 가져오는 방법에 대해 배웠습니다. 이제 Excel 스프레드시트나 Google 스프레드시트에서 데이터를 가져오는 방법을 배울 때입니다. 이는 Chapter 7 에서 배운 내용을 기반으로 하지만 스프레드시트의 데이터로 작업할 때의 추가 고려 사항과 복잡성에 대해서도 논의할 것입니다.

본인이나 공동 작업자가 데이터 정리를 위해 스프레드시트를 사용하고 있다면 Karl Broman과 Kara Woo의 논문 “Data Organization in Spreadsheets”(https://doi.org/10.1080/00031305.2017.1375989)를 읽어보는 것을 강력히 추천합니다. 이 논문에 제시된 모범 사례는 스프레드시트에서 R로 데이터를 가져와 분석하고 시각화할 때 많은 골칫거리를 덜어줄 것입니다.

20.2 엑셀(Excel)

Microsoft Excel은 데이터가 스프레드시트 파일 내의 워크시트에 구성되는 널리 사용되는 스프레드시트 소프트웨어 프로그램입니다.

20.2.1 선수 지식

이 섹션에서는 readxl 패키지를 사용하여 R에서 Excel 스프레드시트의 데이터를 로드하는 방법을 배웁니다. 이 패키지는 핵심 tidyverse는 아니므로 명시적으로 로드해야 하지만 tidyverse 패키지를 설치할 때 자동으로 설치됩니다. 나중에 Excel 스프레드시트를 생성할 수 있게 해주는 writexl 패키지도 사용할 것입니다.

library(readxl)
library(tidyverse)
#> Warning: package 'ggplot2' was built under R version 4.5.2
#> Warning: package 'readr' was built under R version 4.5.2
library(writexl)

20.2.2 시작하기

readxl 함수의 대부분은 Excel 스프레드시트를 R로 로드할 수 있게 해줍니다:

  • read_xls()xls 형식의 Excel 파일을 읽습니다.
  • read_xlsx()xlsx 형식의 Excel 파일을 읽습니다.
  • read_excel()xlsxlsx 형식의 파일을 모두 읽을 수 있습니다. 입력에 따라 파일 유형을 추측합니다.

이러한 함수들은 이전에 다른 유형의 파일(예: read_csv(), read_table() 등)을 읽기 위해 소개한 다른 함수들과 마찬가지로 유사한 구문을 가지고 있습니다. 이 장의 나머지 부분에서는 read_excel() 사용에 초점을 맞출 것입니다.

20.2.3 엑셀 스프레드시트 읽기

Figure 20.1 은 우리가 R로 읽어들일 스프레드시트가 Excel에서 어떻게 보이는지 보여줍니다. 이 스프레드시트는 https://docs.google.com/spreadsheets/d/1V1nPp1tzOuutXFLb3G9Eyxi3qxeEhnOXUzL5_BcCQ0w/에서 Excel 파일로 다운로드할 수 있습니다.

Excel의 students 스프레드시트 살펴보기. 스프레드시트에는 6명의 학생에  대한 정보, 즉 ID, 이름, 좋아하는 음식, 식사 계획, 나이가 포함되어 있습니다.
Figure 20.1: Excel의 students.xlsx라는 스프레드시트.

read_excel()의 첫 번째 인수는 읽을 파일의 경로입니다.

students <- read_excel("data/students.xlsx")

read_excel()은 파일을 티블로 읽어들입니다.

students
#> # A tibble: 6 × 5
#>   `Student ID` `Full Name`      favourite.food     mealPlan            AGE  
#>          <dbl> <chr>            <chr>              <chr>               <chr>
#> 1            1 Sunil Huffmann   Strawberry yoghurt Lunch only          4    
#> 2            2 Barclay Lynn     French fries       Lunch only          5    
#> 3            3 Jayendra Lyne    N/A                Breakfast and lunch 7    
#> 4            4 Leon Rossini     Anchovies          Lunch only          <NA> 
#> 5            5 Chidiegwu Dunkel Pizza              Breakfast and lunch five 
#> 6            6 Güvenç Attila    Ice cream          Lunch only          6

데이터에는 6명의 학생이 있고 각 학생에 대해 5개의 변수가 있습니다. 그러나 이 데이터셋에서 해결하고 싶은 몇 가지 사항이 있습니다:

  1. 열 이름이 제각각입니다. col_names 인수를 사용하여 snake_case와 같이 일관된 형식을 따르는 열 이름을 제공할 수 있습니다.

    read_excel(
      "data/students.xlsx",
      col_names = c("student_id", "full_name", "favourite_food", "meal_plan", "age")
    )
    #> # A tibble: 7 × 5
    #>   student_id full_name        favourite_food     meal_plan           age  
    #>   <chr>      <chr>            <chr>              <chr>               <chr>
    #> 1 Student ID Full Name        favourite.food     mealPlan            AGE  
    #> 2 1          Sunil Huffmann   Strawberry yoghurt Lunch only          4    
    #> 3 2          Barclay Lynn     French fries       Lunch only          5    
    #> 4 3          Jayendra Lyne    N/A                Breakfast and lunch 7    
    #> 5 4          Leon Rossini     Anchovies          Lunch only          <NA> 
    #> 6 5          Chidiegwu Dunkel Pizza              Breakfast and lunch five 
    #> 7 6          Güvenç Attila    Ice cream          Lunch only          6

    불행히도 이것은 완벽하게 작동하지 않았습니다. 이제 우리가 원하는 변수 이름을 얻었지만 이전에 헤더 행이었던 것이 이제 데이터의 첫 번째 관측값으로 나타납니다. skip 인수를 사용하여 해당 행을 명시적으로 건너뛸 수 있습니다.

    read_excel(
      "data/students.xlsx",
      col_names = c("student_id", "full_name", "favourite_food", "meal_plan", "age"),
      skip = 1
    )
    #> # A tibble: 6 × 5
    #>   student_id full_name        favourite_food     meal_plan           age  
    #>        <dbl> <chr>            <chr>              <chr>               <chr>
    #> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only          4    
    #> 2          2 Barclay Lynn     French fries       Lunch only          5    
    #> 3          3 Jayendra Lyne    N/A                Breakfast and lunch 7    
    #> 4          4 Leon Rossini     Anchovies          Lunch only          <NA> 
    #> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch five 
    #> 6          6 Güvenç Attila    Ice cream          Lunch only          6
  2. favourite_food 열에서 관측값 중 하나가 N/A인데, 이는 “사용할 수 없음(not available)”을 의미하지만 현재 NA로 인식되지 않습니다(이 N/A와 목록의 네 번째 학생 나이 사이의 대조를 확인하세요). na 인수를 사용하여 NA로 인식되어야 하는 문자열을 지정할 수 있습니다. 기본적으로 ""(빈 문자열, 또는 스프레드시트에서 읽는 경우 빈 셀이나 =NA() 수식이 있는 셀)만 NA로 인식됩니다.

    read_excel(
      "data/students.xlsx",
      col_names = c("student_id", "full_name", "favourite_food", "meal_plan", "age"),
      skip = 1,
      na = c("", "N/A")
    )
    #> # A tibble: 6 × 5
    #>   student_id full_name        favourite_food     meal_plan           age  
    #>        <dbl> <chr>            <chr>              <chr>               <chr>
    #> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only          4    
    #> 2          2 Barclay Lynn     French fries       Lunch only          5    
    #> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch 7    
    #> 4          4 Leon Rossini     Anchovies          Lunch only          <NA> 
    #> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch five 
    #> 6          6 Güvenç Attila    Ice cream          Lunch only          6
  3. 남아있는 또 다른 문제는 age가 문자 변수로 읽혔지만 실제로는 숫자여야 한다는 것입니다. 플랫 파일에서 데이터를 읽기 위한 read_csv() 및 친구들과 마찬가지로 read_excel()col_types 인수를 제공하고 읽어들이는 변수의 열 유형을 지정할 수 있습니다. 하지만 구문은 약간 다릅니다. 옵션은 "skip", "guess", "logical", "numeric", "date", "text" 또는 "list"입니다.

    read_excel(
      "data/students.xlsx",
      col_names = c("student_id", "full_name", "favourite_food", "meal_plan", "age"),
      skip = 1,
      na = c("", "N/A"),
      col_types = c("numeric", "text", "text", "text", "numeric")
    )
    #> Warning: Expecting numeric in E6 / R6C5: got 'five'
    #> # A tibble: 6 × 5
    #>   student_id full_name        favourite_food     meal_plan             age
    #>        <dbl> <chr>            <chr>              <chr>               <dbl>
    #> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only              4
    #> 2          2 Barclay Lynn     French fries       Lunch only              5
    #> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch     7
    #> 4          4 Leon Rossini     Anchovies          Lunch only             NA
    #> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch    NA
    #> 6          6 Güvenç Attila    Ice cream          Lunch only              6

    그러나 이것도 원하는 결과를 정확하게 생성하지는 못했습니다. age가 숫자여야 한다고 지정함으로써 숫자가 아닌 항목(값 five를 가짐)이 있는 하나의 셀을 NA로 만들었습니다. 이 경우 나이를 "text"로 읽은 다음 데이터가 R에 로드되면 변경해야 합니다.

    students <- read_excel(
      "data/students.xlsx",
      col_names = c("student_id", "full_name", "favourite_food", "meal_plan", "age"),
      skip = 1,
      na = c("", "N/A"),
      col_types = c("numeric", "text", "text", "text", "text")
    )
    
    students <- students |> 
      mutate(
        age = if_else(age == "five", "5", age),
        age = parse_number(age)
      )
    
    students
    #> # A tibble: 6 × 5
    #>   student_id full_name        favourite_food     meal_plan             age
    #>        <dbl> <chr>            <chr>              <chr>               <dbl>
    #> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only              4
    #> 2          2 Barclay Lynn     French fries       Lunch only              5
    #> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch     7
    #> 4          4 Leon Rossini     Anchovies          Lunch only             NA
    #> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch     5
    #> 6          6 Güvenç Attila    Ice cream          Lunch only              6

우리가 원하는 형식으로 데이터를 로드하는 데 여러 단계와 시행착오가 필요했으며 이는 예상치 못한 일이 아닙니다. 데이터 과학은 반복적인 프로세스이며, 인간이 스프레드시트에 데이터를 입력하고 데이터 저장뿐만 아니라 공유 및 통신에도 사용하는 경향이 있기 때문에 스프레드시트에서 데이터를 읽어오는 반복 프로세스는 다른 일반 텍스트, 사각형 데이터 파일에 비해 훨씬 더 지루할 수 있습니다.

데이터를 로드하고 살펴볼 때까지 데이터가 어떻게 생겼는지 정확히 알 수 있는 방법은 없습니다. 음, 사실 한 가지 방법이 있습니다. Excel에서 파일을 열어 엿볼 수 있습니다. 그렇게 하려면 원본 데이터 파일은 그대로 두고 R로 읽어오는 동안 대화식으로 열어보고 탐색할 Excel 파일의 사본을 만드는 것이 좋습니다. 이렇게 하면 검사하는 동안 실수로 스프레드시트의 내용을 덮어쓰지 않도록 할 수 있습니다. 또한 우리가 여기서 한 것처럼 데이터를 로드하고, 엿보고, 코드를 조정하고, 다시 로드하고, 결과에 만족할 때까지 반복하는 것을 두려워해서는 안 됩니다.

20.2.4 워크시트 읽기

스프레드시트와 플랫 파일을 구별하는 중요한 기능은 워크시트라고 하는 여러 시트의 개념입니다. Figure 20.2 는 여러 워크시트가 있는 Excel 스프레드시트를 보여줍니다. 데이터는 palmerpenguins 패키지에서 가져왔으며 https://docs.google.com/spreadsheets/d/1aFu8lnD_g0yjF5O-K6SFgSEWiHPpgvFCF0NY9D6LXnY/에서 이 스프레드시트를 Excel 파일로 다운로드할 수 있습니다. 각 워크시트에는 데이터가 수집된 서로 다른 섬의 펭귄 정보가 포함되어 있습니다.

Excel의 penguins 스프레드시트 살펴보기. 스프레드시트에는 Torgersen Island,  Biscoe Island, Dream Island의 세 가지 워크시트가 있습니다.
Figure 20.2: 세 개의 워크시트가 포함된 Excel의 penguins.xlsx라는 스프레드시트.

read_excel()sheet 인수를 사용하여 스프레드시트에서 단일 워크시트를 읽을 수 있습니다. 지금까지 의존해 온 기본값은 첫 번째 시트입니다.

read_excel("data/penguins.xlsx", sheet = "Torgersen Island")
#> # A tibble: 52 × 8
#>   species island    bill_length_mm     bill_depth_mm      flipper_length_mm
#>   <chr>   <chr>     <chr>              <chr>              <chr>            
#> 1 Adelie  Torgersen 39.1               18.7               181              
#> 2 Adelie  Torgersen 39.5               17.399999999999999 186              
#> 3 Adelie  Torgersen 40.299999999999997 18                 195              
#> 4 Adelie  Torgersen NA                 NA                 NA               
#> 5 Adelie  Torgersen 36.700000000000003 19.3               193              
#> 6 Adelie  Torgersen 39.299999999999997 20.6               190              
#> # ℹ 46 more rows
#> # ℹ 3 more variables: body_mass_g <chr>, sex <chr>, year <dbl>

숫자 데이터가 포함된 것으로 보이는 일부 변수는 문자열 "NA"가 실제 NA로 인식되지 않아 문자로 읽힙니다.

penguins_torgersen <- read_excel("data/penguins.xlsx", sheet = "Torgersen Island", na = "NA")

penguins_torgersen
#> # A tibble: 52 × 8
#>   species island    bill_length_mm bill_depth_mm flipper_length_mm
#>   <chr>   <chr>              <dbl>         <dbl>             <dbl>
#> 1 Adelie  Torgersen           39.1          18.7               181
#> 2 Adelie  Torgersen           39.5          17.4               186
#> 3 Adelie  Torgersen           40.3          18                 195
#> 4 Adelie  Torgersen           NA            NA                  NA
#> 5 Adelie  Torgersen           36.7          19.3               193
#> 6 Adelie  Torgersen           39.3          20.6               190
#> # ℹ 46 more rows
#> # ℹ 3 more variables: body_mass_g <dbl>, sex <chr>, year <dbl>

또는 excel_sheets()를 사용하여 Excel 스프레드시트의 모든 워크시트에 대한 정보를 얻은 다음 관심 있는 워크시트를 읽을 수 있습니다.

excel_sheets("data/penguins.xlsx")
#> [1] "Torgersen Island" "Biscoe Island"    "Dream Island"

워크시트의 이름을 알게 되면 read_excel()로 개별적으로 읽을 수 있습니다.

penguins_biscoe <- read_excel("data/penguins.xlsx", sheet = "Biscoe Island", na = "NA")
penguins_dream  <- read_excel("data/penguins.xlsx", sheet = "Dream Island", na = "NA")

이 경우 전체 펭귄 데이터셋은 스프레드시트의 세 워크시트에 분산되어 있습니다. 각 워크시트에는 동일한 수의 열이 있지만 행 수는 다릅니다.

dim(penguins_torgersen)
#> [1] 52  8
dim(penguins_biscoe)
#> [1] 168   8
dim(penguins_dream)
#> [1] 124   8

bind_rows()로 합칠 수 있습니다.

penguins <- bind_rows(penguins_torgersen, penguins_biscoe, penguins_dream)
penguins
#> # A tibble: 344 × 8
#>   species island    bill_length_mm bill_depth_mm flipper_length_mm
#>   <chr>   <chr>              <dbl>         <dbl>             <dbl>
#> 1 Adelie  Torgersen           39.1          18.7               181
#> 2 Adelie  Torgersen           39.5          17.4               186
#> 3 Adelie  Torgersen           40.3          18                 195
#> 4 Adelie  Torgersen           NA            NA                  NA
#> 5 Adelie  Torgersen           36.7          19.3               193
#> 6 Adelie  Torgersen           39.3          20.6               190
#> # ℹ 338 more rows
#> # ℹ 3 more variables: body_mass_g <dbl>, sex <chr>, year <dbl>

Chapter 26 에서는 반복적인 코드 없이 이러한 종류의 작업을 수행하는 방법에 대해 이야기할 것입니다.

20.2.5 시트의 일부 읽기

많은 사람들이 데이터 저장뿐만 아니라 프레젠테이션용으로도 Excel 스프레드시트를 사용하기 때문에 스프레드시트에서 R로 읽으려는 데이터의 일부가 아닌 셀 항목을 찾는 것은 매우 일반적입니다. Figure 20.3 은 그러한 스프레드시트를 보여줍니다. 시트 중간에 데이터 프레임처럼 보이는 것이 있지만 데이터 위와 아래의 셀에 관련 없는 텍스트가 있습니다.

Excel의 deaths 스프레드시트 살펴보기. 스프레드시트 상단에는 데이터가 아닌  정보가 포함된 4개의 행이 있습니다. 'For the same of consistency in the  data layout, which is really a beautiful thing, I will keep making notes  up here.'라는 텍스트가 이 상단 4개 행의 셀에 걸쳐 있습니다. 그런 다음  이름, 직업, 나이, 자녀 유무, 생년월일 및 사망일을 포함하여 10명의 유명인  사망에 대한 정보가 포함된 데이터 프레임이 있습니다. 하단에는 데이터가 아닌  정보가 포함된 4개의 행이 더 있습니다. 'This has been really fun, but  we're signing off now!'라는 텍스트가 이 하단 4개 행의 셀에 걸쳐 있습니다.
Figure 20.3: Excel의 deaths.xlsx라는 스프레드시트.

이 스프레드시트는 readxl 패키지에서 제공하는 예제 스프레드시트 중 하나입니다. readxl_example() 함수를 사용하여 패키지가 설치된 디렉터리에서 시스템의 스프레드시트를 찾을 수 있습니다. 이 함수는 평소와 같이 read_excel()에서 사용할 수 있는 스프레드시트의 경로를 반환합니다.

deaths_path <- readxl_example("deaths.xlsx")
deaths <- read_excel(deaths_path)
#> New names:
#> • `` -> `...2`
#> • `` -> `...3`
#> • `` -> `...4`
#> • `` -> `...5`
#> • `` -> `...6`
deaths
#> # A tibble: 18 × 6
#>   `Lots of people`    ...2       ...3  ...4     ...5          ...6           
#>   <chr>               <chr>      <chr> <chr>    <chr>         <chr>          
#> 1 simply cannot resi… <NA>       <NA>  <NA>     <NA>          some notes     
#> 2 at                  the        top   <NA>     of            their spreadsh…
#> 3 or                  merging    <NA>  <NA>     <NA>          cells          
#> 4 Name                Profession Age   Has kids Date of birth Date of death  
#> 5 David Bowie         musician   69    TRUE     17175         42379          
#> 6 Carrie Fisher       actor      60    TRUE     20749         42731          
#> # ℹ 12 more rows

상위 3개 행과 하위 4개 행은 데이터 프레임의 일부가 아닙니다. skipn_max 인수를 사용하여 이러한 관련 없는 행을 제거할 수 있지만 셀 범위(cell ranges)를 사용하는 것이 좋습니다. Excel에서 왼쪽 상단 셀은 A1입니다. 열을 따라 오른쪽으로 이동하면 셀 레이블이 알파벳 순으로 이동합니다. 즉, B1, C1 등입니다. 그리고 열을 따라 아래로 이동하면 셀 레이블의 숫자가 증가합니다. 즉, A2, A3 등입니다.

여기서 우리가 읽으려는 데이터는 셀 A5에서 시작하여 셀 F15에서 끝납니다. 스프레드시트 표기법으로 이것은 A5:F15이며 range 인수에 제공합니다:

read_excel(deaths_path, range = "A5:F15")
#> # A tibble: 10 × 6
#>   Name          Profession   Age `Has kids` `Date of birth`    
#>   <chr>         <chr>      <dbl> <lgl>      <dttm>             
#> 1 David Bowie   musician      69 TRUE       1947-01-08 00:00:00
#> 2 Carrie Fisher actor         60 TRUE       1956-10-21 00:00:00
#> 3 Chuck Berry   musician      90 TRUE       1926-10-18 00:00:00
#> 4 Bill Paxton   actor         61 TRUE       1955-05-17 00:00:00
#> 5 Prince        musician      57 TRUE       1958-06-07 00:00:00
#> 6 Alan Rickman  actor         69 FALSE      1946-02-21 00:00:00
#> # ℹ 4 more rows
#> # ℹ 1 more variable: `Date of death` <dttm>

20.2.6 데이터 유형

CSV 파일에서 모든 값은 문자열입니다. 이것이 데이터에 대해 특별히 진실은 아니지만 단순합니다. 모든 것이 문자열입니다.

Excel 스프레드시트의 기본 데이터는 더 복잡합니다. 셀은 다음 네 가지 중 하나일 수 있습니다:

  • TRUE, FALSE 또는 NA와 같은 부울(boolean).

  • “10” 또는 “10.5”와 같은 숫자.

  • 날짜시간(datetime), “11/1/21” 또는 “11/1/21 3:00 PM”과 같이 시간을 포함할 수도 있습니다.

  • “ten”과 같은 텍스트 문자열.

스프레드시트 데이터로 작업할 때 기본 데이터가 셀에 표시되는 것과 매우 다를 수 있음을 명심하는 것이 중요합니다. 예를 들어 Excel에는 정수 개념이 없습니다. 모든 숫자는 부동 소수점으로 저장되지만 사용자 정의 가능한 소수점 자릿수로 데이터를 표시하도록 선택할 수 있습니다. 마찬가지로 날짜는 실제로 숫자로 저장되며, 구체적으로는 1900년 1월 1일 이후의 초 수입니다. Excel에서 서식을 적용하여 날짜 표시 방식을 사용자 정의할 수 있습니다. 혼란스럽게도 숫자처럼 보이지만 실제로는 문자열인 것을 가질 수도 있습니다(예: Excel 셀에 '10 입력).

기본 데이터가 저장되는 방식과 표시되는 방식 간의 이러한 차이점은 데이터가 R로 로드될 때 놀라움을 유발할 수 있습니다. 기본적으로 readxl은 주어진 열의 데이터 유형을 추측합니다. 권장되는 워크플로우는 readxl이 열 유형을 추측하게 하고, 추측된 열 유형에 만족하는지 확인한 다음, 그렇지 않은 경우 돌아가서 Section 20.2.3 에 표시된 대로 col_types를 지정하여 다시 가져오는 것입니다.

또 다른 과제는 Excel 스프레드시트의 열에 이러한 유형이 혼합되어 있는 경우입니다(예: 일부 셀은 숫자, 다른 셀은 텍스트, 다른 셀은 날짜). R로 데이터를 가져올 때 readxl은 몇 가지 결정을 내려야 합니다. 이 경우 이 열의 유형을 "list"로 설정할 수 있으며, 그러면 벡터의 각 요소 유형이 추측되는 길이 1 벡터의 리스트로 열을 로드합니다.

때로는 데이터가 셀 배경색이나 텍스트가 굵게 표시되었는지 여부와 같이 더 이국적인 방식으로 저장되기도 합니다. 이런 경우 tidyxl 패키지가 유용할 수 있습니다. Excel의 표가 아닌 데이터로 작업하는 전략에 대한 자세한 내용은 https://nacnudus.github.io/spreadsheet-munging-strategies/를 참조하세요.

20.2.7 엑셀로 쓰기

그런 다음 쓸 수 있는 작은 데이터 프레임을 만들어 보겠습니다. item은 팩터이고 quantity는 정수라는 점에 유의하세요.

bake_sale <- tibble(
  item     = factor(c("brownie", "cupcake", "cookie")),
  quantity = c(10, 5, 8)
)

bake_sale
#> # A tibble: 3 × 2
#>   item    quantity
#>   <fct>      <dbl>
#> 1 brownie       10
#> 2 cupcake        5
#> 3 cookie         8

writexl 패키지write_xlsx() 함수를 사용하여 데이터를 Excel 파일로 디스크에 다시 쓸 수 있습니다:

write_xlsx(bake_sale, path = "data/bake-sale.xlsx")

Figure 20.4 은 Excel에서 데이터가 어떻게 보이는지 보여줍니다. 열 이름이 포함되어 있고 굵게 표시되어 있음을 주목하세요. col_namesformat_headers 인수를 FALSE로 설정하여 끌 수 있습니다.

앞서 생성한 빵 판매 데이터 프레임이 Excel에 있습니다.
Figure 20.4: Excel의 bake-sale.xlsx라는 스프레드시트.

CSV에서 읽는 것과 마찬가지로 데이터를 다시 읽을 때 데이터 유형에 대한 정보가 손실됩니다. 이로 인해 Excel 파일은 중간 결과를 캐싱하는 데에도 신뢰할 수 없습니다. 대안은 Section 7.5 을 참조하세요.

read_excel("data/bake-sale.xlsx")
#> # A tibble: 3 × 2
#>   item    quantity
#>   <chr>      <dbl>
#> 1 brownie       10
#> 2 cupcake        5
#> 3 cookie         8

20.2.8 서식이 지정된 출력

writexl 패키지는 간단한 Excel 스프레드시트를 작성하기 위한 가벼운 솔루션이지만 스프레드시트 내의 시트에 쓰기 및 스타일링과 같은 추가 기능에 관심이 있다면 openxlsx 패키지를 사용하고 싶을 것입니다. 여기서는 이 패키지를 사용하는 세부 사항에 대해 설명하지 않겠지만 openxlsx를 사용하여 R에서 Excel로 작성된 데이터에 대한 추가 서식 기능에 대한 광범위한 논의를 위해 https://ycphs.github.io/openxlsx/articles/Formatting.html을 읽는 것을 추천합니다.

이 패키지는 tidyverse의 일부가 아니므로 함수와 워크플로우가 낯설게 느껴질 수 있습니다. 예를 들어 함수 이름은 camelCase이고 여러 함수를 파이프라인으로 구성할 수 없으며 인수는 tidyverse에서 흔히 볼 수 있는 것과는 다른 순서입니다. 하지만 괜찮습니다. 이 책 밖으로 R 학습 및 사용이 확장됨에 따라 R에서 특정 목표를 달성하기 위해 사용할 수 있는 다양한 R 패키지에서 사용되는 다양한 스타일을 접하게 될 것입니다. 새 패키지에서 사용되는 코딩 스타일에 익숙해지는 좋은 방법은 함수 설명서에 제공된 예제를 실행하여 구문과 출력 형식에 대한 감을 잡고 패키지와 함께 제공될 수 있는 비네트를 읽는 것입니다.

20.2.9 연습문제

  1. Excel 파일에서 다음 데이터셋을 만들고 survey.xlsx로 저장하세요. 또는 여기에서 Excel 파일로 다운로드할 수 있습니다.

    3개의 열(group, subgroup, id)과 12개의 행이 있는 스프레드시트. group 열에는 1(병합된 7개 행에 걸쳐 있음)과 2(병합된 5개 행에 걸쳐 있음)의  두 가지 값이 있습니다. subgroup 열에는 A(병합된 3개 행), B(병합된 4개 행),  A(병합된 2개 행), B(병합된 3개 행)의 네 가지 값이 있습니다. id 열에는  1부터 12까지의 숫자인 12개의 값이 있습니다.

    그런 다음 survey_id는 문자 변수로, n_pets는 수치형 변수로 R로 읽어들입니다.

    #> # A tibble: 6 × 2
    #>   survey_id n_pets
    #>   <chr>      <dbl>
    #> 1 1              0
    #> 2 2              1
    #> 3 3             NA
    #> 4 4              2
    #> 5 5              2
    #> 6 6             NA
  2. 다른 Excel 파일에서 다음 데이터셋을 만들고 roster.xlsx로 저장하세요. 또는 여기에서 Excel 파일로 다운로드할 수 있습니다.

    3개의 열(group, subgroup, id)과 12개의 행이 있는 스프레드시트. group 열에는  1(병합된 7개 행에 걸쳐 있음)과 2(병합된 5개 행에 걸쳐 있음)의 두 가지  값이 있습니다. subgroup 열에는 A(병합된 3개 행), B(병합된 4개 행),  A(병합된 2개 행), B(병합된 3개 행)의 네 가지 값이 있습니다. id 열에는  1부터 12까지의 숫자인 12개의 값이 있습니다.

    그런 다음 R로 읽어들입니다. 결과 데이터 프레임의 이름은 roster여야 하며 다음과 같아야 합니다.

    #> # A tibble: 12 × 3
    #>    group subgroup    id
    #>    <dbl> <chr>    <dbl>
    #>  1     1 A            1
    #>  2     1 A            2
    #>  3     1 A            3
    #>  4     1 B            4
    #>  5     1 B            5
    #>  6     1 B            6
    #>  7     1 B            7
    #>  8     2 A            8
    #>  9     2 A            9
    #> 10     2 B           10
    #> 11     2 B           11
    #> 12     2 B           12
  3. 새 Excel 파일에서 다음 데이터셋을 만들고 sales.xlsx로 저장하세요. 또는 여기에서 Excel 파일로 다운로드할 수 있습니다.

    2개의 열과 13개의 행이 있는 스프레드시트. 처음 두 행에는 시트에 대한  정보가 포함된 텍스트가 있습니다. 1행에는 "This file contains  information on sales"라고 되어 있습니다. 2행에는 "Data are organized  by brand name, and for each brand, we have the ID number for the item  sold, and how many are sold."라고 되어 있습니다. 그런 다음 두 개의 빈  행이 있고 그 다음 9개의 데이터 행이 있습니다.

    a. sales.xlsx를 읽어서 sales로 저장합니다. 데이터 프레임은 idn이 열 이름이고 9개의 행이 있는 다음과 같아야 합니다.

    #> # A tibble: 9 × 2
    #>   id      n    
    #>   <chr>   <chr>
    #> 1 Brand 1 n    
    #> 2 1234    8    
    #> 3 8721    2    
    #> 4 1822    3    
    #> 5 Brand 2 n    
    #> 6 3333    1    
    #> 7 2156    3    
    #> 8 3987    6    
    #> 9 3216    5

    b. sales를 추가로 수정하여 3개의 열(brand, id, n)과 7개의 데이터 행이 있는 다음과 같은 깔끔한 형식으로 만드세요. idn은 숫자이고 brand는 문자 변수라는 점에 유의하세요.

    #> # A tibble: 7 × 3
    #>   brand      id     n
    #>   <chr>   <dbl> <dbl>
    #> 1 Brand 1  1234     8
    #> 2 Brand 1  8721     2
    #> 3 Brand 1  1822     3
    #> 4 Brand 2  3333     1
    #> 5 Brand 2  2156     3
    #> 6 Brand 2  3987     6
    #> 7 Brand 2  3216     5
  4. bake_sale 데이터 프레임을 다시 만들고 openxlsx 패키지의 write.xlsx() 함수를 사용하여 Excel 파일로 작성하세요.

  5. Chapter 7 에서 열 이름을 스네이크 케이스로 바꾸는 janitor::clean_names() 함수에 대해 배웠습니다. 이 섹션의 앞부분에서 소개한 students.xlsx 파일을 읽고 이 함수를 사용하여 열 이름을 “청소”하세요.

  6. read_xls().xlsx 확장자를 가진 파일을 읽으려고 하면 어떻게 됩니까?

20.3 구글 스프레드시트(Google Sheets)

Google 스프레드시트는 또 다른 널리 사용되는 스프레드시트 프로그램입니다. 무료이며 웹 기반입니다. Excel과 마찬가지로 Google 스프레드시트에서도 데이터는 스프레드시트 파일 내의 워크시트(시트라고도 함)에 구성됩니다.

20.3.1 선수 지식

이 섹션도 스프레드시트에 초점을 맞추지만 이번에는 googlesheets4 패키지로 Google 스프레드시트에서 데이터를 로드합니다. 이 패키지도 핵심 tidyverse가 아니므로 명시적으로 로드해야 합니다.

패키지 이름에 대한 간단한 참고: googlesheets4는 Sheets API v4의 v4를 사용하여 Google 스프레드시트에 대한 R 인터페이스를 제공하므로 이름이 그렇습니다.

20.3.2 시작하기

googlesheets4 패키지의 주요 함수는 read_sheet()이며, URL이나 파일 ID에서 Google 스프레드시트를 읽습니다. 이 함수는 range_read()라는 이름으로도 사용됩니다.

또한 gs4_create()로 새 시트를 만들거나 sheet_write() 및 친구들로 기존 시트에 쓸 수도 있습니다.

이 섹션에서는 Excel 섹션과 동일한 데이터셋으로 작업하여 Excel과 Google 스프레드시트에서 데이터를 읽는 워크플로우의 유사점과 차이점을 강조합니다. readxl 및 googlesheets4 패키지는 모두 Chapter 7 에서 본 read_csv() 함수를 제공하는 readr 패키지의 기능을 모방하도록 설계되었습니다. 따라서 read_excel()read_sheet()로 교체하는 것만으로 많은 작업을 수행할 수 있습니다. 그러나 Excel과 Google 스프레드시트가 정확히 같은 방식으로 작동하지 않으므로 다른 작업에는 함수 호출에 대한 추가 업데이트가 필요할 수 있습니다.

20.3.3 구글 스프레드시트 읽기

Figure 20.5 는 우리가 R로 읽어들일 스프레드시트가 Google 스프레드시트에서 어떻게 보이는지 보여줍니다. 이것은 Figure 20.1 과 동일한 데이터셋이지만 Excel 대신 Google 스프레드시트에 저장되어 있습니다.

Google 스프레드시트의 students 스프레드시트 살펴보기. 스프레드시트에는  6명의 학생에 대한 정보, 즉 ID, 이름, 좋아하는 음식, 식사 계획,  나이가 포함되어 있습니다.
Figure 20.5: 브라우저 창의 students라는 Google 스프레드시트.

read_sheet()의 첫 번째 인수는 읽을 파일의 URL이며 티블을 반환합니다:
https://docs.google.com/spreadsheets/d/1V1nPp1tzOuutXFLb3G9Eyxi3qxeEhnOXUzL5_BcCQ0w. 이러한 URL은 작업하기에 유쾌하지 않으므로 ID로 시트를 식별하고 싶을 때가 많습니다.

students_sheet_id <- "1V1nPp1tzOuutXFLb3G9Eyxi3qxeEhnOXUzL5_BcCQ0w"
students <- read_sheet(students_sheet_id)
#> ✔ Reading from students.
#> ✔ Range Sheet1.
students
#> # A tibble: 6 × 5
#>   `Student ID` `Full Name`      favourite.food     mealPlan            AGE   
#>          <dbl> <chr>            <chr>              <chr>               <list>
#> 1            1 Sunil Huffmann   Strawberry yoghurt Lunch only          <dbl> 
#> 2            2 Barclay Lynn     French fries       Lunch only          <dbl> 
#> 3            3 Jayendra Lyne    N/A                Breakfast and lunch <dbl> 
#> 4            4 Leon Rossini     Anchovies          Lunch only          <NULL>
#> 5            5 Chidiegwu Dunkel Pizza              Breakfast and lunch <chr> 
#> 6            6 Güvenç Attila    Ice cream          Lunch only          <dbl>

read_excel()에서 했던 것처럼 열 이름, NA 문자열, 열 유형을 read_sheet()에 제공할 수 있습니다.

students <- read_sheet(
  students_sheet_id,
  col_names = c("student_id", "full_name", "favourite_food", "meal_plan", "age"),
  skip = 1,
  na = c("", "N/A"),
  col_types = "dcccc"
)
#> ✔ Reading from students.
#> ✔ Range 2:10000000.

students
#> # A tibble: 6 × 5
#>   student_id full_name        favourite_food     meal_plan           age  
#>        <dbl> <chr>            <chr>              <chr>               <chr>
#> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only          4    
#> 2          2 Barclay Lynn     French fries       Lunch only          5    
#> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch 7    
#> 4          4 Leon Rossini     Anchovies          Lunch only          <NA> 
#> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch five 
#> 6          6 Güvenç Attila    Ice cream          Lunch only          6

여기서 열 유형을 짧은 코드를 사용하여 약간 다르게 정의했음에 유의하세요. 예를 들어 “dcccc”는 “double, character, character, character, character”를 나타냅니다.

Google 스프레드시트에서 개별 시트를 읽을 수도 있습니다. penguins Google 스프레드시트에서 “Torgersen Island” 시트를 읽어보겠습니다:

penguins_sheet_id <- "1aFu8lnD_g0yjF5O-K6SFgSEWiHPpgvFCF0NY9D6LXnY"
read_sheet(penguins_sheet_id, sheet = "Torgersen Island")
#> ✔ Reading from penguins.
#> ✔ Range ''Torgersen Island''.
#> # A tibble: 52 × 8
#>   species island    bill_length_mm bill_depth_mm flipper_length_mm
#>   <chr>   <chr>     <list>         <list>        <list>           
#> 1 Adelie  Torgersen <dbl [1]>      <dbl [1]>     <dbl [1]>        
#> 2 Adelie  Torgersen <dbl [1]>      <dbl [1]>     <dbl [1]>        
#> 3 Adelie  Torgersen <dbl [1]>      <dbl [1]>     <dbl [1]>        
#> 4 Adelie  Torgersen <chr [1]>      <chr [1]>     <chr [1]>        
#> 5 Adelie  Torgersen <dbl [1]>      <dbl [1]>     <dbl [1]>        
#> 6 Adelie  Torgersen <dbl [1]>      <dbl [1]>     <dbl [1]>        
#> # ℹ 46 more rows
#> # ℹ 3 more variables: body_mass_g <list>, sex <chr>, year <dbl>

sheet_names()를 사용하여 Google 스프레드시트 내의 모든 시트 목록을 얻을 수 있습니다:

sheet_names(penguins_sheet_id)
#> [1] "Torgersen Island" "Biscoe Island"    "Dream Island"

마지막으로 read_excel()과 마찬가지로 read_sheet()에서 range를 정의하여 Google 스프레드시트의 일부를 읽을 수 있습니다. 아래에서는 gs4_example() 함수를 사용하여 googlesheets4 패키지와 함께 제공되는 예제 Google 스프레드시트를 찾습니다.

deaths_url <- gs4_example("deaths")
deaths <- read_sheet(deaths_url, range = "A5:F15")
#> ✔ Reading from deaths.
#> ✔ Range A5:F15.
deaths
#> # A tibble: 10 × 6
#>   Name          Profession   Age `Has kids` `Date of birth`    
#>   <chr>         <chr>      <dbl> <lgl>      <dttm>             
#> 1 David Bowie   musician      69 TRUE       1947-01-08 00:00:00
#> 2 Carrie Fisher actor         60 TRUE       1956-10-21 00:00:00
#> 3 Chuck Berry   musician      90 TRUE       1926-10-18 00:00:00
#> 4 Bill Paxton   actor         61 TRUE       1955-05-17 00:00:00
#> 5 Prince        musician      57 TRUE       1958-06-07 00:00:00
#> 6 Alan Rickman  actor         69 FALSE      1946-02-21 00:00:00
#> # ℹ 4 more rows
#> # ℹ 1 more variable: `Date of death` <dttm>

20.3.4 구글 스프레드시트에 쓰기

write_sheet()를 사용하여 R에서 Google 스프레드시트로 쓸 수 있습니다. 첫 번째 인수는 쓸 데이터 프레임이고 두 번째 인수는 쓸 Google 스프레드시트의 이름(또는 다른 식별자)입니다:

write_sheet(bake_sale, ss = "bake-sale")

Google 스프레드시트 내의 특정 (워크)시트에 데이터를 쓰려면 sheet 인수로 지정할 수도 있습니다.

write_sheet(bake_sale, ss = "bake-sale", sheet = "Sales")

20.3.5 인증(Authentication)

Google 계정으로 인증하지 않고 gs4_deauth()를 사용하여 공개 Google 스프레드시트에서 읽을 수 있지만, 비공개 시트를 읽거나 시트에 쓰려면 googlesheets4가 여러분의 Google 스프레드시트를 보고 관리할 수 있도록 인증이 필요합니다.

인증이 필요한 시트를 읽으려고 시도하면 googlesheets4는 웹 브라우저로 안내하여 Google 계정에 로그인하고 Google 스프레드시트로 대신 작업할 수 있는 권한을 부여하라는 메시지를 표시합니다. 그러나 특정 Google 계정, 인증 범위 등을 지정하려면 gs4_auth()를 사용하여 수행할 수 있습니다. 예: gs4_auth(email = "mine@example.com")은 특정 이메일과 연결된 토큰을 강제로 사용합니다. 자세한 인증 정보는 googlesheets4 인증 비네트 https://googlesheets4.tidyverse.org/articles/auth.html을 읽어보는 것을 추천합니다.

20.3.6 연습문제

  1. 이 장의 앞부분에 있는 students 데이터셋을 Excel과 Google 스프레드시트에서 읽되 read_excel()read_sheet() 함수에 추가 인수를 제공하지 마세요. 결과 R 데이터 프레임이 정확히 동일합니까? 그렇지 않다면 어떻게 다릅니까?

  2. https://pos.it/r4ds-survey에서 survey라는 제목의 Google 스프레드시트를 읽되 survey_id는 문자 변수로, n_pets는 수치형 변수로 읽으세요.

  3. https://pos.it/r4ds-roster에서 roster라는 제목의 Google 스프레드시트를 읽으세요. 결과 데이터 프레임의 이름은 roster여야 하며 다음과 같아야 합니다.

    #> # A tibble: 12 × 3
    #>    group subgroup    id
    #>    <dbl> <chr>    <dbl>
    #>  1     1 A            1
    #>  2     1 A            2
    #>  3     1 A            3
    #>  4     1 B            4
    #>  5     1 B            5
    #>  6     1 B            6
    #>  7     1 B            7
    #>  8     2 A            8
    #>  9     2 A            9
    #> 10     2 B           10
    #> 11     2 B           11
    #> 12     2 B           12

20.4 요약

Microsoft Excel과 Google 스프레드시트는 가장 널리 사용되는 두 가지 스프레드시트 시스템입니다. R에서 Excel 및 Google 스프레드시트 파일에 저장된 데이터와 직접 상호 작용할 수 있는 것은 엄청난 능력입니다! 이 장에서는 readxl 패키지의 read_excel()을 사용하여 Excel에서, googlesheets4 패키지의 read_sheet()를 사용하여 Google 스프레드시트에서 R로 데이터를 읽는 방법을 배웠습니다. 이 함수들은 서로 매우 유사하게 작동하며 열 이름, NA 문자열, 읽어들이는 파일 상단에서 건너뛸 행 등을 지정하기 위한 유사한 인수를 가지고 있습니다. 또한 두 함수 모두 스프레드시트에서 단일 시트를 읽을 수 있게 해줍니다.

반면 Excel 파일에 쓰는 것은 다른 패키지와 함수(writexl::write_xlsx())가 필요한 반면, Google 스프레드시트에는 googlesheets4 패키지의 write_sheet()를 사용하여 쓸 수 있습니다.

다음 장에서는 다른 데이터 소스인 데이터베이스와 해당 소스에서 R로 데이터를 읽는 방법에 대해 배울 것입니다.