class: title-slide, left, bottom, animated, fadeIn # Sử dụng for loop để đọc nhiều file ---- ## **Khóa học: Hướng dẫn sử dụng R để xử lý dữ liệu** ### Biên soạn: Duc Nguyen (Tự học R chấm com) ### Đăng ký: tuhocr.com@gmail.com - Website: www.tuhocr.com --- class: animated, fadeIn # Đề bài Download file [diet_data.zip](https://tuhocr.netlify.app/diet_data.zip) về thư mục làm việc và giải nén ra. Bộ dữ liệu trong ví dụ này là kết quả theo dõi trọng lượng của từng người sau 30 ngày theo cùng 1 chế độ dinh dưỡng. Bạn có 5 file `.csv` trong folder `diet_data` ở thư mục làm việc. Nếu nhập riêng lẻ từng file `.csv` vào `R` thì sẽ dùng lệnh `read.csv()` lần lượt từng file sẽ khá mất công (tưởng tượng nếu bạn có trên 100 file `.csv` như vậy). Vậy cách nào để nhập hết dữ liệu này một lần cho tiện? ```r D:\garden> │ garden.Rproj │ diet_data.zip │ └───diet_data Andy.csv David.csv John.csv Mike.csv Steve.csv ``` --- background-image: url(img/diet-data.png) background-size: contain background-color: white class: inverse, middle, center, animated, fadeIn --- class: animated, fadeIn # Cách 1: Đưa hết file `.csv` vào 1 file `data.frame` Đầu tiên cần đưa vị trí các file `.csv` vào 1 vector để làm cơ sở cho lệnh `for` loop đọc một lượt các file này. ```r > getwd() [1] "D:/garden" > list.files() # Liệt kê toàn bộ file trong thư mục làm việc. Tương tự lệnh dir() [1] "diet_data" "diet_data.zip" "garden.Rproj" # ↑ Folder ↑ File ↑ File > list.files("diet_data") # ← Liệt kê file trong folder [1] "Andy.csv" "David.csv" "John.csv" "Mike.csv" "Steve.csv" # ↓ Liệt kê file và đường dẫn > list.files("diet_data", full.names = TRUE) [1] "diet_data/Andy.csv" "diet_data/David.csv" "diet_data/John.csv" [4] "diet_data/Mike.csv" "diet_data/Steve.csv" # Đưa giá trị đường dẫn này vào vector `files_full` > files_full <- list.files("diet_data", full.names = TRUE) ``` --- class: animated, fadeIn # Cách 1: Đưa hết file `.csv` vào 1 file `data.frame` Khi cần so sánh, tính toán giữa các bệnh nhân (Andy, David, John, Mike, Steve) thì chỉ cần subset từ file data frame chung này. Tuy vậy nếu gộp hết vào 1 file `data.frame` master như vậy sẽ khá chậm khi có nhiều file `.csv`. Do đó cách tiếp cận gộp vào `list` sẽ nhanh hơn. ```r dat <- data.frame() # Tạo data frame rỗng để chứa các file `.csv` con # ↓ Ứng với mỗi i từ 1 đến 5 (có 5 file `.csv`), hoặc dùng lệnh seq_along() for (i in 1:5) { dat <- rbind(dat, read.csv(files_full[i])) # ← Đọc lần lượt file theo thứ tự index } # ↑ Ghép theo hàng các file `.csv` vào data frame `dat` str(dat) # Kiểm tra kết quả cho thấy `dat` chứa đủ 5 file (tổng cộng 150 dòng) 'data.frame': 150 obs. of 4 variables: $ Patient.Name: chr "Andy" "Andy" "Andy" "Andy" ... $ Age : int 30 30 30 30 30 30 30 30 30 30 ... $ Weight : int 140 140 140 139 138 138 138 138 138 138 ... $ Day : int 1 2 3 4 5 6 7 8 9 10 ... ``` --- class: animated, fadeIn # Cách 2: Đưa hết file `.csv` vào 1 file `list` .pull-left[ ```r > tmp <- vector(mode = "list", length = length(files_full)) > tmp # Bản chất `tmp` là [[1]] # một list rỗng chứa NULL # sẵn 5 vị trí (component) # cho các file `.csv` [[2]] NULL [[3]] NULL [[4]] NULL [[5]] NULL ``` ] .pull-right[ ```r > summary(tmp) Length Class Mode [1,] 0 -none- NULL [2,] 0 -none- NULL [3,] 0 -none- NULL [4,] 0 -none- NULL [5,] 0 -none- NULL ``` ] --- class: animated, fadeIn # Cách 2: Đưa hết file `.csv` vào 1 file `list` Dùng lệnh `for` loop ```r # ↓ Tạo ra dãy số index trong vector `files_full` tương tự 1:5 for (i in seq_along(files_full)) { # ↓ Tương ứng từng component `i` trong list (chú ý subset bằng `[[`) tmp[[i]] <- read.csv(files_full[[i]]) # ← Đọc file `.csv` } # ↑ Có thể dùng files_full[i] cũng ra cùng kết quả str(tmp) # Xem cấu trúc của file list `tmp` sau khi combine theo cách trên ``` --- background-image: url(img/ket-qua-diet-data.png) background-size: contain background-color: white class: inverse, middle, center, animated, fadeIn --- class: animated, fadeIn # Cách 3: Đưa hết file `.csv` vào 1 file `list` Dùng lệnh `lapply`. Bản chất là lệnh `for` loop nhưng tiện hơn. ```r > files_full [1] "diet_data/Andy.csv" "diet_data/David.csv" "diet_data/John.csv" [4] "diet_data/Mike.csv" "diet_data/Steve.csv" # ↓ Vector chứa đường dẫn file `.csv` > yes <- lapply(files_full, read.csv) # ↑ Lệnh đọc file `.csv` > str(yes) # Kết quả y chang như cách 2 ``` --- background-image: url(img/ket-qua-diet-data-1.png) background-size: contain background-color: white class: inverse, middle, center, animated, fadeIn --- class: animated, fadeIn # Trích xuất data frame con trong `list` ```r > class(tmp) [1] "list" > tmp[[3]] -> john # Trích xuất thành phần trong list ra một data frame con > head(john) Patient.Name Age Weight Day 1 John 22 175 1 2 John 22 175 2 3 John 22 175 3 4 John 22 175 4 5 John 22 175 5 6 John 22 175 6 > class(john) [1] "data.frame" ``` --- class: inverse, middle, center # Câu hỏi Làm sao gộp lại các data frame trong list vào lại thành file data frame master như cách 1? --- class: animated, fadeIn # Lệnh `do.call()` ```r # ↓ Hàm dùng ghép hàng các file output <- do.call(rbind, tmp) # ← List chứa các data frame con cần ghép > str(output) # Kết quả data frame `output` 'data.frame': 150 obs. of 4 variables: $ Patient.Name: chr "Andy" "Andy" "Andy" "Andy" ... $ Age : int 30 30 30 30 30 30 30 30 30 30 ... $ Weight : int 140 140 140 139 138 138 138 138 138 138 ... $ Day : int 1 2 3 4 5 6 7 8 9 10 ... > identical(dat, output) # So sánh giữa `dat` (data frame master cách 1) và [1] TRUE # `output` cho thấy y chang nhau ```