7 Nhập dữ liệu
7.1 Giới thiệu
Làm việc với dữ liệu được cung cấp bởi các package R là một cách tuyệt vời để học các công cụ khoa học dữ liệu, nhưng đến một lúc nào đó bạn sẽ muốn áp dụng những gì đã học vào dữ liệu của chính mình. Trong chương này, bạn sẽ học những kiến thức cơ bản về việc đọc các file dữ liệu vào R.
Cụ thể, chương này sẽ tập trung vào việc đọc các file văn bản thuần (plain-text) dạng hình chữ nhật (rectangular). Chúng ta sẽ bắt đầu với các lời khuyên thực tế để xử lý các đặc điểm như tên column, kiểu dữ liệu và dữ liệu khuyết. Sau đó bạn sẽ học cách đọc dữ liệu từ nhiều file cùng lúc và ghi dữ liệu từ R ra file. Cuối cùng, bạn sẽ học cách tạo data frame thủ công trong R.
7.1.1 Điều kiện tiên quyết
Trong chương này, bạn sẽ học cách tải các file phẳng (flat file) vào R với package readr, là một phần của tidyverse cốt lõi.
7.2 Đọc dữ liệu từ file
Để bắt đầu, chúng ta sẽ tập trung vào loại file dữ liệu hình chữ nhật phổ biến nhất: CSV, viết tắt của comma-separated values (giá trị phân tách bằng dấu phẩy). Đây là một file CSV đơn giản trông như thế nào. Hàng đầu tiên, thường được gọi là row tiêu đề (header row), chứa tên các column, và sáu row tiếp theo cung cấp dữ liệu. Các column được phân tách, hay còn gọi là phân cách (delimited), bằng dấu phẩy.
Student ID,Full Name,favourite.food,mealPlan,AGE
1,Sunil Huffmann,Strawberry yoghurt,Lunch only,4
2,Barclay Lynn,French fries,Lunch only,5
3,Jayendra Lyne,N/A,Breakfast and lunch,7
4,Leon Rossini,Anchovies,Lunch only,
5,Chidiegwu Dunkel,Pizza,Breakfast and lunch,five
6,Güvenç Attila,Ice cream,Lunch only,6
Bảng 7.1 hiển thị biểu diễn của cùng dữ liệu đó dưới dạng bảng.
| Student ID | Full Name | favourite.food | mealPlan | AGE |
|---|---|---|---|---|
| 1 | Sunil Huffmann | Strawberry yoghurt | Lunch only | 4 |
| 2 | Barclay Lynn | French fries | Lunch only | 5 |
| 3 | Jayendra Lyne | N/A | Breakfast and lunch | 7 |
| 4 | Leon Rossini | Anchovies | Lunch only | NA |
| 5 | Chidiegwu Dunkel | Pizza | Breakfast and lunch | five |
| 6 | Güvenç Attila | Ice cream | Lunch only | 6 |
Chúng ta có thể đọc file này vào R bằng read_csv(). Đối số đầu tiên là quan trọng nhất: đường dẫn (path) đến file. Bạn có thể hình dung đường dẫn như địa chỉ của file: file có tên students.csv và nằm trong thư mục data.
students <- read_csv("data/students.csv")
#> Rows: 6 Columns: 5
#> ── Column specification ─────────────────────────────────────────────────────
#> Delimiter: ","
#> chr (4): Full Name, favourite.food, mealPlan, AGE
#> dbl (1): Student ID
#>
#> ℹ Use `spec()` to retrieve the full column specification for this data.
#> ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Đoạn mã trên sẽ hoạt động nếu bạn có file students.csv trong thư mục data của dự án. Bạn có thể tải file students.csv từ https://pos.it/r4ds-students-csv hoặc bạn có thể đọc trực tiếp từ URL đó với:
students <- read_csv("https://pos.it/r4ds-students-csv")Khi bạn chạy read_csv(), nó in ra một thông báo cho bạn biết số row và column dữ liệu, ký tự phân cách được sử dụng, và thông số kỹ thuật của các column (tên các column được tổ chức theo kiểu dữ liệu mà column chứa). Nó cũng in ra một số thông tin về cách lấy thông số kỹ thuật đầy đủ của column và cách tắt thông báo này. Thông báo này là một phần không thể thiếu của readr, và chúng ta sẽ quay lại nó trong Phần 7.3.
7.2.1 Lời khuyên thực tế
Sau khi đọc dữ liệu vào, bước đầu tiên thường liên quan đến việc biến đổi nó theo cách nào đó để dễ dàng làm việc hơn trong phần còn lại của phân tích. Hãy xem lại dữ liệu students với suy nghĩ đó.
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 6Trong column favourite.food, có một loạt các món ăn, và sau đó là string (string) N/A, đáng lẽ phải là một NA thực sự mà R sẽ nhận ra là “không có sẵn” (not available). Đây là điều chúng ta có thể xử lý bằng argument na. Theo mặc định, read_csv() chỉ nhận dạng string rỗng ("") trong tập dữ liệu này là NA, và chúng ta muốn nó cũng nhận dạng string "N/A".
students <- read_csv("data/students.csv", na = c("N/A", ""))
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 <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 6Bạn cũng có thể nhận thấy rằng các column Student ID và Full Name được bao quanh bởi dấu backtick. Đó là vì chúng chứa dấu cách, vi phạm các quy tắc thông thường của R cho tên biến (variable); chúng là các tên không hợp cú pháp (non-syntactic). Để tham chiếu đến các biến này, bạn cần bao quanh chúng bằng dấu backtick, `:
students |>
rename(
student_id = `Student ID`,
full_name = `Full Name`
)
#> # 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 <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 6Một cách tiếp cận khác là sử dụng janitor::clean_names() để dùng một số phương pháp heuristic chuyển tất cả thành dạng snake case cùng lúc1.
students |> janitor::clean_names()
#> # 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 6Một tác vụ phổ biến khác sau khi đọc dữ liệu vào là xem xét các kiểu biến. Ví dụ, meal_plan là một biến phân loại (categorical variable) với một tập hợp các giá trị có thể đã biết, mà trong R nên được biểu diễn dưới dạng factor (factor):
students |>
janitor::clean_names() |>
mutate(meal_plan = factor(meal_plan))
#> # A tibble: 6 × 5
#> student_id full_name favourite_food meal_plan age
#> <dbl> <chr> <chr> <fct> <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 6Lưu ý rằng các giá trị trong biến meal_plan vẫn giữ nguyên, nhưng kiểu biến được hiển thị bên dưới tên biến đã thay đổi từ ký tự (<chr>) sang factor (<fct>). Bạn sẽ tìm hiểu thêm về factor trong Chương 16.
Trước khi phân tích dữ liệu này, bạn có thể sẽ muốn sửa column age. Hiện tại, age là một biến ký tự vì một trong các quan sát được nhập là five thay vì số 5. Chúng ta sẽ thảo luận chi tiết về cách khắc phục vấn đề này trong Chương 20.
students <- students |>
janitor::clean_names() |>
mutate(
meal_plan = factor(meal_plan),
age = parse_number(if_else(age == "five", "5", age))
)
students
#> # A tibble: 6 × 5
#> student_id full_name favourite_food meal_plan age
#> <dbl> <chr> <chr> <fct> <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 6Một function mới ở đây là if_else(), có ba argument. Đối số đầu tiên test phải là một vector logic (logical vector). Kết quả sẽ chứa giá trị của argument thứ hai, yes, khi test là TRUE, và giá trị của argument thứ ba, no, khi nó là FALSE. Ở đây chúng ta đang nói rằng nếu age là string "five", hãy biến nó thành "5", và nếu không thì giữ nguyên age. Bạn sẽ tìm hiểu thêm về if_else() và các vector logic trong Chương 12.
7.2.2 Các argument khác
Có một vài argument quan trọng khác mà chúng ta cần đề cập, và chúng sẽ dễ minh họa hơn nếu trước tiên chúng tôi cho bạn thấy một mẹo tiện lợi: read_csv() có thể đọc các string văn bản mà bạn đã tạo và định dạng như một file CSV:
read_csv(
"a,b,c
1,2,3
4,5,6"
)
#> Warning: The `file` argument of `read_csv()` should use `I()` for literal data as of
#> readr 2.2.0.
#>
#> # Bad (for example):
#> read_csv("x,y\n1,2")
#>
#> # Good:
#> read_csv(I("x,y\n1,2"))
#> # A tibble: 2 × 3
#> a b c
#> <dbl> <dbl> <dbl>
#> 1 1 2 3
#> 2 4 5 6Thông thường, read_csv() sử dụng dòng đầu tiên của dữ liệu làm tên column, đây là một quy ước rất phổ biến. Nhưng không phải là hiếm khi có một vài dòng siêu dữ liệu (metadata) được đặt ở đầu file. Bạn có thể sử dụng skip = n để bỏ qua n dòng đầu tiên hoặc sử dụng comment = "#" để loại bỏ tất cả các dòng bắt đầu bằng (ví dụ) #:
Trong các trường hợp khác, dữ liệu có thể không có tên column. Bạn có thể sử dụng col_names = FALSE để yêu cầu read_csv() không coi row đầu tiên là tiêu đề và thay vào đó đặt tên tuần tự từ X1 đến Xn:
read_csv(
"1,2,3
4,5,6",
col_names = FALSE
)
#> # A tibble: 2 × 3
#> X1 X2 X3
#> <dbl> <dbl> <dbl>
#> 1 1 2 3
#> 2 4 5 6Ngoài ra, bạn có thể truyền cho col_names một vector ký tự sẽ được sử dụng làm tên column:
Những argument này là tất cả những gì bạn cần biết để đọc phần lớn các file CSV mà bạn sẽ gặp trong thực tế. (Đối với phần còn lại, bạn sẽ cần kiểm tra cẩn thận file .csv của mình và đọc tài liệu về nhiều argument khác của read_csv().)
7.2.3 Các loại file khác
Khi bạn đã thành thạo read_csv(), việc sử dụng các function khác của readr rất đơn giản; chỉ là vấn đề biết nên dùng function nào:
read_csv2()đọc các file phân tách bằng dấu chấm phẩy. Chúng sử dụng;thay vì,để phân tách các trường và phổ biến ở các quốc gia sử dụng,làm dấu thập phân.read_tsv()đọc các file phân tách bằng tab.read_delim()đọc các file với bất kỳ ký tự phân cách nào, cố gắng tự động đoán ký tự phân cách nếu bạn không chỉ định.read_fwf()đọc các file có độ rộng cố định (fixed-width). Bạn có thể chỉ định các trường theo độ rộng vớifwf_widths()hoặc theo vị trí vớifwf_positions().read_table()đọc một biến thể phổ biến của file có độ rộng cố định trong đó các column được phân tách bằng khoảng trắng.read_log()đọc các file log kiểu Apache.
7.2.4 Bài tập
Bạn sẽ sử dụng function nào để đọc một file trong đó các trường được phân tách bằng “|”?
Ngoài
file,skip, vàcomment, những argument nào khác màread_csv()vàread_tsv()có chung?Những argument quan trọng nhất của
read_fwf()là gì?-
Đôi khi các string trong file CSV chứa dấu phẩy. Để ngăn chúng gây ra vấn đề, chúng cần được bao quanh bởi một ký tự trích dẫn (quoting character), như
"hoặc'. Theo mặc định,read_csv()giả định rằng ký tự trích dẫn sẽ là". Để đọc đoạn văn bản sau vào một data frame, bạn cần chỉ định argument nào choread_csv()?"x,y\n1,'a,b'" -
Xác định điều gì sai với mỗi file CSV nội tuyến (inline) sau đây. Điều gì xảy ra khi bạn chạy đoạn mã?
-
Thực hành tham chiếu đến các tên không hợp cú pháp trong data frame sau bằng cách:
- Trích xuất biến có tên
1. - Vẽ biểu đồ phân tán (scatterplot) của
1so với2. - Tạo một column mới có tên
3, bằng2chia cho1. - Đổi tên các column thành
one,two, vàthree.
- Trích xuất biến có tên
7.3 Kiểm soát kiểu column
Một file CSV không chứa bất kỳ thông tin nào về kiểu của mỗi biến (tức là liệu nó là logic, số, string, v.v.), vì vậy readr sẽ cố gắng đoán kiểu. Phần này mô tả cách quá trình đoán hoạt động, cách giải quyết một số vấn đề phổ biến khiến nó thất bại, và nếu cần, cách tự cung cấp kiểu column. Cuối cùng, chúng ta sẽ đề cập đến một vài chiến lược chung hữu ích khi readr thất bại nghiêm trọng và bạn cần hiểu rõ hơn về cấu trúc file của mình.
7.3.1 Đoán kiểu dữ liệu
readr sử dụng phương pháp heuristic để xác định kiểu column. Với mỗi column, nó lấy các giá trị của 1.000 hàng2 được phân bố đều từ row đầu tiên đến row cuối cùng, bỏ qua các missing value. Sau đó nó kiểm tra qua các câu hỏi sau:
- Nó chỉ chứa
F,T,FALSE, hoặcTRUE(không phân biệt chữ hoa chữ thường)? Nếu vậy, đó là kiểu logic (logical). - Nó chỉ chứa các số (ví dụ,
1,-4.5,5e6,Inf)? Nếu vậy, đó là kiểu số (number). - Nó có khớp với chuẩn ISO8601 không? Nếu vậy, đó là ngày (date) hoặc ngày-giờ (date-time). (Chúng ta sẽ quay lại ngày-giờ chi tiết hơn trong Phần 17.2).
- Nếu không, nó phải là string.
Bạn có thể thấy hành vi đó trong thực tế qua ví dụ đơn giản này:
read_csv("
logical,numeric,date,string
TRUE,1,2021-01-15,abc
false,4.5,2021-02-15,def
T,Inf,2021-02-16,ghi
")
#> # A tibble: 3 × 4
#> logical numeric date string
#> <lgl> <dbl> <date> <chr>
#> 1 TRUE 1 2021-01-15 abc
#> 2 FALSE 4.5 2021-02-15 def
#> 3 TRUE Inf 2021-02-16 ghiPhương pháp heuristic này hoạt động tốt nếu bạn có một tập dữ liệu sạch, nhưng trong thực tế, bạn sẽ gặp nhiều trường hợp thất bại kỳ lạ và đa dạng.
7.3.2 Giá trị khuyết, kiểu column, và các vấn đề
Cách phổ biến nhất mà việc phát hiện kiểu column thất bại là khi một column chứa các giá trị không mong đợi, và bạn nhận được một column ký tự thay vì một kiểu cụ thể hơn. Một trong những nguyên nhân phổ biến nhất cho điều này là missing value, được ghi bằng thứ gì đó khác với NA mà readr mong đợi.
Lấy file CSV đơn giản 1 column này làm ví dụ:
simple_csv <- "
x
10
.
20
30"Nếu chúng ta đọc nó mà không có bất kỳ argument bổ sung nào, x trở thành một column ký tự:
read_csv(simple_csv)
#> # A tibble: 4 × 1
#> x
#> <chr>
#> 1 10
#> 2 .
#> 3 20
#> 4 30Trong trường hợp rất nhỏ này, bạn có thể dễ dàng nhìn thấy missing value .. Nhưng điều gì xảy ra nếu bạn có row nghìn row với chỉ một vài missing value được biểu diễn bằng . rải rác trong đó? Một cách tiếp cận là yêu cầu readr rằng x là một column số, và sau đó xem nó thất bại ở đâu. Bạn có thể làm điều đó với argument col_types, nhận một list có tên (named list) trong đó các tên khớp với tên column trong file CSV:
df <- read_csv(
simple_csv,
col_types = list(x = col_double())
)
#> Warning: One or more parsing issues, call `problems()` on your data frame for
#> details, e.g.:
#> dat <- vroom(...)
#> problems(dat)Bây giờ read_csv() báo cáo rằng có một vấn đề, và cho chúng ta biết có thể tìm hiểu thêm với problems():
problems(df)
#> # A tibble: 1 × 5
#> row col expected actual file
#> <int> <int> <chr> <chr> <chr>
#> 1 3 1 a double . /private/var/folders/ty/sykxy97538dgq4gwn7s7qx…Điều này cho chúng ta biết rằng có một vấn đề ở row 3, column 1, nơi readr mong đợi một số thực (double) nhưng nhận được .. Điều đó gợi ý rằng tập dữ liệu này sử dụng . cho các missing value. Vì vậy chúng ta đặt na = ".", việc đoán tự động thành công, cho chúng ta column số mà chúng ta muốn:
read_csv(simple_csv, na = ".")
#> # A tibble: 4 × 1
#> x
#> <dbl>
#> 1 10
#> 2 NA
#> 3 20
#> 4 307.3.3 Kiểu cột
readr cung cấp tổng cộng chín kiểu column để bạn sử dụng:
-
col_logical()vàcol_double()đọc giá trị logic và số thực. Chúng hiếm khi cần thiết (ngoại trừ như trên), vì readr thường sẽ đoán chúng cho bạn. -
col_integer()đọc số nguyên. Chúng ta hiếm khi phân biệt số nguyên và số thực trong cuốn sách này vì chúng tương đương về mặt chức năng, nhưng đọc số nguyên một cách tường minh đôi khi có thể hữu ích vì chúng chiếm một nửa bộ nhớ so với số thực. -
col_character()đọc string. Điều này có thể hữu ích khi chỉ định tường minh khi bạn có một column là mã định danh số (numeric identifier), tức là string dài các chữ số dùng để xác định một đối tượng nhưng không có ý nghĩa khi áp dụng các phép toán. Ví dụ bao gồm số điện thoại, số an sinh xã hội, số thẻ tín dụng, v.v. -
col_factor(),col_date(), vàcol_datetime()tạo factor, ngày, và ngày-giờ tương ứng; bạn sẽ tìm hiểu thêm về chúng khi chúng ta đến các kiểu dữ liệu đó trong Chương 16 và Chương 17. -
col_number()là một bộ phân tích số linh hoạt (permissive numeric parser) sẽ bỏ qua các thành phần không phải số, và đặc biệt hữu ích cho tiền tệ. Bạn sẽ tìm hiểu thêm về nó trong Chương 13. -
col_skip()bỏ qua một column để nó không được bao gồm trong kết quả, điều này có thể hữu ích để tăng tốc việc đọc dữ liệu nếu bạn có một file CSV lớn và bạn chỉ muốn sử dụng một số column.
Cũng có thể ghi đè phương pháp heuristic mặc định để đoán kiểu bằng cách chuyển từ list() sang cols() và chỉ định .default:
another_csv <- "
x,y,z
1,2,3"
read_csv(
another_csv,
col_types = cols(.default = col_character())
)
#> # A tibble: 1 × 3
#> x y z
#> <chr> <chr> <chr>
#> 1 1 2 3Một function trợ giúp hữu ích khác là cols_only(), chỉ đọc vào các column mà bạn chỉ định:
read_csv(
another_csv,
col_types = cols_only(x = col_character())
)
#> # A tibble: 1 × 1
#> x
#> <chr>
#> 1 17.4 Đọc dữ liệu từ nhiều file
Đôi khi dữ liệu của bạn được chia thành nhiều file thay vì nằm trong một file duy nhất. Ví dụ, bạn có thể có dữ liệu bán row cho nhiều tháng, với dữ liệu của mỗi tháng trong một file riêng: 01-sales.csv cho tháng Một, 02-sales.csv cho tháng Hai, và 03-sales.csv cho tháng Ba. Với read_csv() bạn có thể đọc các dữ liệu này cùng lúc và xếp chồng chúng lên nhau trong một data frame duy nhất.
sales_files <- c("data/01-sales.csv", "data/02-sales.csv", "data/03-sales.csv")
read_csv(sales_files, id = "file")
#> # A tibble: 19 × 6
#> file month year brand item n
#> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 data/01-sales.csv January 2019 1 1234 3
#> 2 data/01-sales.csv January 2019 1 8721 9
#> 3 data/01-sales.csv January 2019 1 1822 2
#> 4 data/01-sales.csv January 2019 2 3333 1
#> 5 data/01-sales.csv January 2019 2 2156 9
#> 6 data/01-sales.csv January 2019 2 3987 6
#> # ℹ 13 more rowsMột lần nữa, đoạn mã trên sẽ hoạt động nếu bạn có các file CSV trong thư mục data của dự án. Bạn có thể tải các file này từ https://pos.it/r4ds-01-sales, https://pos.it/r4ds-02-sales, và https://pos.it/r4ds-03-sales hoặc bạn có thể đọc chúng trực tiếp với:
Đối số id thêm một column mới có tên file vào data frame kết quả, xác định file mà dữ liệu đến từ đó. Điều này đặc biệt hữu ích trong các trường hợp mà các file bạn đang đọc vào không có column nhận dạng có thể giúp bạn truy nguyên các quan sát về nguồn gốc ban đầu của chúng.
Nếu bạn có nhiều file muốn đọc vào, việc viết tên của chúng dưới dạng list có thể trở nên cồng kềnh. Thay vào đó, bạn có thể sử dụng function cơ sở list.files() để tìm các file cho bạn bằng cách khớp một mẫu (pattern) trong tên file. Bạn sẽ tìm hiểu thêm về các mẫu này trong Chương 15.
sales_files <- list.files("data", pattern = "sales\\.csv$", full.names = TRUE)
sales_files
#> [1] "data/01-sales.csv" "data/02-sales.csv" "data/03-sales.csv"7.5 Ghi ra file
readr cũng đi kèm với hai function hữu ích để ghi dữ liệu trở lại ổ đĩa: write_csv() và write_tsv(). Các argument quan trọng nhất của những function này là x (data frame cần lưu) và file (vị trí lưu). Bạn cũng có thể chỉ định cách ghi các missing value với na, và liệu bạn có muốn append (nối thêm) vào một file hiện có hay không.
write_csv(students, "students.csv")Bây giờ hãy đọc lại file csv đó. Lưu ý rằng thông tin kiểu biến mà bạn vừa thiết lập sẽ bị mất khi bạn lưu thành CSV vì bạn đang bắt đầu lại với việc đọc từ một file văn bản thuần:
students
#> # A tibble: 6 × 5
#> student_id full_name favourite_food meal_plan age
#> <dbl> <chr> <chr> <fct> <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
write_csv(students, "students-2.csv")
read_csv("students-2.csv")
#> # 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Điều này khiến CSV hơi không đáng tin cậy cho việc lưu trữ tạm (caching) các kết quả trung gian—bạn cần tái tạo thông số kỹ thuật column mỗi khi tải vào. Có hai lựa chọn thay thế chính:
-
write_rds()vàread_rds()là các function bọc (wrapper) thống nhất xung quanh các function cơ sởreadRDS()vàsaveRDS(). Chúng lưu trữ dữ liệu trong định dạng nhị phân tùy chỉnh của R gọi là RDS. Điều này có nghĩa là khi bạn tải lại đối tượng, bạn đang tải chính xác cùng một đối tượng R mà bạn đã lưu.write_rds(students, "students.rds") read_rds("students.rds") #> # A tibble: 6 × 5 #> student_id full_name favourite_food meal_plan age #> <dbl> <chr> <chr> <fct> <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 -
Gói arrow cho phép bạn đọc và ghi các file parquet, một định dạng file nhị phân nhanh có thể được chia sẻ giữa các ngôn ngữ lập trình. Chúng ta sẽ quay lại arrow chi tiết hơn trong Chương 22.
library(arrow) write_parquet(students, "students.parquet") read_parquet("students.parquet") #> # A tibble: 6 × 5 #> student_id full_name favourite_food meal_plan age #> <dbl> <chr> <chr> <fct> <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
Parquet có xu hướng nhanh hơn nhiều so với RDS và có thể sử dụng được ngoài R, nhưng yêu cầu package arrow.
7.6 Nhập dữ liệu thủ công
Đôi khi bạn sẽ cần tạo một tibble “bằng tay” bằng cách nhập một ít dữ liệu trong script R của mình. Có hai function hữu ích để giúp bạn làm điều này, khác nhau ở chỗ bạn bố trí tibble theo column hay theo row. tibble() hoạt động theo column:
Bố trí dữ liệu theo column có thể khiến việc thấy mối quan hệ giữa các row trở nên khó khăn, vì vậy một lựa chọn thay thế là tribble(), viết tắt của transposed tibble (tibble chuyển vị), cho phép bạn bố trí dữ liệu theo từng row. tribble() được tùy chỉnh cho việc nhập dữ liệu trong mã: tiêu đề column bắt đầu bằng ~ và các mục được phân tách bằng dấu phẩy. Điều này giúp có thể bố trí lượng dữ liệu nhỏ ở dạng dễ đọc:
tribble(
~x, ~y, ~z,
1, "h", 0.08,
2, "m", 0.83,
5, "g", 0.60
)
#> # A tibble: 3 × 3
#> x y z
#> <dbl> <chr> <dbl>
#> 1 1 h 0.08
#> 2 2 m 0.83
#> 3 5 g 0.67.7 Tóm tắt
Trong chương này, bạn đã học cách tải các file CSV với read_csv() và tự nhập dữ liệu với tibble() và tribble(). Bạn đã tìm hiểu cách các file csv hoạt động, một số vấn đề bạn có thể gặp phải, và cách khắc phục chúng. Chúng ta sẽ quay lại theme nhập dữ liệu vài lần trong cuốn sách này: Chương 20 từ Excel và Google Sheets, Chương 21 sẽ chỉ cho bạn cách tải dữ liệu từ database, Chương 22 từ các file parquet, Chương 23 từ JSON, và Chương 24 từ các trang web.
Chúng ta gần như đã đến cuối phần này của cuốn sách, nhưng có một theme quan trọng cuối cùng cần đề cập: cách tìm kiếm sự giúp đỡ. Vì vậy trong chương tiếp theo, bạn sẽ tìm hiểu một số nơi tốt để tìm kiếm sự giúp đỡ, cách tạo một reprex để tối đa hóa cơ hội nhận được sự giúp đỡ tốt, và một số lời khuyên chung về việc theo kịp thế giới R.