4 Quy trình làm việc: phong cách mã
Phong cách mã tốt giống như dấu câu đúng: bạncóthểxoaysởkhôngnhưngnóchắcchắnlàmviệcdễđọchơn. Ngay cả khi là lập trình viên rất mới, bạn nên chú ý đến phong cách mã. Sử dụng phong cách nhất quán giúp người khác (bao gồm bạn-trong-tương-lai!) dễ đọc công việc của bạn hơn và đặc biệt quan trọng nếu bạn cần nhờ người khác giúp đỡ. Chương này sẽ giới thiệu các điểm quan trọng nhất của hướng dẫn phong cách tidyverse, được sử dụng xuyên suốt cuốn sách này.
Việc tạo phong cách cho mã sẽ hơi tẻ nhạt lúc đầu, nhưng nếu bạn thực hành, nó sẽ sớm trở thành bản năng. Ngoài ra, có một số công cụ tuyệt vời để nhanh chóng định dạng lại mã hiện có, như package styler của Lorenz Walthert. Sau khi cài đặt bằng install.packages("styler"), cách dễ nhất để sử dụng là qua bảng lệnh (command palette) của RStudio. Bảng lệnh cho phép bạn sử dụng bất kỳ lệnh RStudio tích hợp nào và nhiều tiện ích bổ sung từ các package. Mở bảng lệnh bằng cách nhấn Cmd/Ctrl + Shift + P, sau đó gõ “styler” để xem tất cả phím tắt do styler cung cấp. Hình 4.1 hiển thị kết quả.
Chúng ta sẽ sử dụng các package tidyverse và nycflights13 cho các ví dụ mã trong chương này.
4.1 Tên
Chúng ta đã nói ngắn gọn về tên trong Phần 2.3. Hãy nhớ rằng tên biến (những tên được tạo bởi <- và những tên được tạo bởi mutate()) chỉ nên sử dụng chữ cái viết thường, số, và _. Sử dụng _ để phân cách các từ trong tên.
Theo nguyên tắc chung, tốt hơn là nên ưu tiên tên dài, mang tính mô tả và dễ hiểu hơn là tên ngắn gọn, gõ nhanh. Tên ngắn tiết kiệm tương đối ít thời gian khi viết mã (đặc biệt vì tự động hoàn thành sẽ giúp bạn gõ xong), nhưng có thể tốn thời gian khi bạn quay lại mã cũ và phải giải mã một chữ viết tắt khó hiểu.
Nếu bạn có nhiều tên cho những thứ liên quan, hãy cố gắng nhất quán. Sự không nhất quán dễ phát sinh khi bạn quên quy ước trước đó, nên đừng cảm thấy tệ nếu phải quay lại và đổi tên. Nói chung, nếu bạn có nhiều biến là biến thể của một theme, tốt hơn là đặt tiền tố chung thay vì hậu tố chung vì tự động hoàn thành hoạt động tốt nhất ở đầu biến.
4.2 Dấu cách
Đặt dấu cách ở cả hai bên toán tử toán học ngoại trừ ^ (tức là +, -, ==, <, …), và xung quanh toán tử gán (<-).
# Nên
z <- (a + b)^2 / d
# Tránh
z<-( a + b ) ^ 2/dKhông đặt dấu cách bên trong hoặc bên ngoài dấu ngoặc cho lệnh gọi function thông thường. Luôn đặt dấu cách sau dấu phẩy, giống như trong tiếng Việt chuẩn.
Có thể thêm dấu cách phụ nếu nó cải thiện sự căn chỉnh. Ví dụ, nếu bạn đang tạo nhiều biến trong mutate(), bạn có thể muốn thêm dấu cách để tất cả các = thẳng row.1 Điều này giúp dễ dàng lướt qua mã hơn.
4.3 Pipe
|> luôn phải có dấu cách phía trước và thường nên là thứ cuối cùng trên dòng. Điều này giúp dễ dàng thêm bước mới, sắp xếp lại các bước hiện có, sửa đổi phần tử trong một bước, và có cái nhìn tổng quan bằng cách lướt qua các động từ ở phía bên trái.
Nếu function bạn đang dẫn vào có argument được đặt tên (như mutate() hoặc summarize()), đặt mỗi argument trên một dòng mới. Nếu function không có argument được đặt tên (như select() hoặc filter()), giữ mọi thứ trên một dòng trừ khi không vừa, trong trường hợp đó bạn nên đặt mỗi argument trên dòng riêng.
Sau bước đầu tiên của pipeline, thụt lề mỗi dòng hai dấu cách. RStudio sẽ tự động đặt dấu cách cho bạn sau khi xuống dòng theo sau |>. Nếu bạn đặt mỗi argument trên dòng riêng, thụt lề thêm hai dấu cách nữa. Đảm bảo ) nằm trên dòng riêng, và không thụt lề để khớp với vị trí ngang của tên function.
Có thể bỏ qua một số quy tắc này nếu pipeline của bạn vừa gọn trên một dòng. Nhưng theo kinh nghiệm chung của chúng tôi, các đoạn mã ngắn thường phát triển dài hơn, vì vậy bạn thường sẽ tiết kiệm thời gian lâu dài bằng cách bắt đầu với tất cả không gian dọc bạn cần.
Cuối cùng, hãy cẩn thận với việc viết pipe rất dài, ví dụ dài hơn 10-15 dòng. Hãy cố gắng chia chúng thành các tác vụ con nhỏ hơn, đặt cho mỗi tác vụ một tên mang tính mô tả. Tên sẽ giúp người đọc hiểu điều gì đang xảy ra và dễ dàng kiểm tra rằng kết quả trung gian đúng như mong đợi. Bất cứ khi nào bạn có thể đặt cho thứ gì đó một tên mang tính mô tả, bạn nên làm, ví dụ khi bạn thay đổi cơ bản cấu trúc dữ liệu, ví dụ sau khi xoay (pivot) hoặc tóm tắt (summarize). Đừng mong đợi làm đúng ngay lần đầu! Điều này có nghĩa là chia nhỏ pipeline dài nếu có các trạng thái trung gian có thể đặt tên tốt.
4.4 ggplot2
Các quy tắc cơ bản áp dụng cho pipe cũng áp dụng cho ggplot2; chỉ cần xử lý + giống như |>.
Một lần nữa, nếu bạn không thể đặt tất cả argument của function trên một dòng, đặt mỗi argument trên dòng riêng:
flights |>
group_by(dest) |>
summarize(
distance = mean(distance),
speed = mean(distance / air_time, na.rm = TRUE)
) |>
ggplot(aes(x = distance, y = speed)) +
geom_smooth(
method = "loess",
span = 0.5,
se = FALSE,
color = "white",
linewidth = 4
) +
geom_point()Chú ý sự chuyển đổi từ |> sang +. Chúng tôi ước sự chuyển đổi này không cần thiết, nhưng thật không may, ggplot2 được viết trước khi pipe được phát hiện.
4.5 Chú thích phân đoạn
Khi tập lệnh của bạn dài hơn, bạn có thể sử dụng comment phân đoạn để chia file thành các phần dễ quản lý:
# Tải dữ liệu --------------------------------------
# Vẽ biểu đồ dữ liệu --------------------------------------RStudio cung cấp phím tắt để tạo các tiêu đề này (Cmd/Ctrl + Shift + R), và sẽ hiển thị chúng trong menu điều hướng mã thả xuống ở góc dưới bên trái trình soạn thảo, như trong Hình 4.2.
4.6 Bài tập
-
Định dạng lại các pipeline sau theo hướng dẫn ở trên.
flights|>filter(dest=="IAH")|>group_by(year,month,day)|>summarize(n=n(), delay=mean(arr_delay,na.rm=TRUE))|>filter(n>10) flights|>filter(carrier=="UA",dest%in%c("IAH","HOU"),sched_dep_time> 0900,sched_arr_time<2000)|>group_by(flight)|>summarize(delay=mean( arr_delay,na.rm=TRUE),cancelled=sum(is.na(arr_delay)),n=n())|>filter(n>10)
4.7 Tóm tắt
Trong chương này, bạn đã học các nguyên tắc quan trọng nhất về phong cách mã. Ban đầu chúng có thể cảm thấy như một tập hợp các quy tắc tùy ý (vì đúng là vậy!) nhưng theo thời gian, khi bạn viết nhiều mã hơn và chia sẻ mã với nhiều người hơn, bạn sẽ thấy phong cách nhất quán quan trọng như thế nào. Và đừng quên package styler: đây là cách tuyệt vời để nhanh chóng cải thiện chất lượng mã có phong cách kém.
Trong chương tiếp theo, chúng ta quay lại các công cụ khoa học dữ liệu, học về tidy data (tidy data). Dữ liệu gọn gàng là cách nhất quán để tổ chức data frame được sử dụng xuyên suốt tidyverse. Sự nhất quán này giúp cuộc sống của bạn dễ dàng hơn vì khi bạn có tidy data, nó hoạt động với phần lớn các function tidyverse. Tất nhiên, cuộc sống không bao giờ dễ dàng, và hầu hết các tập dữ liệu bạn gặp ngoài thực tế sẽ chưa gọn gàng sẵn. Vì vậy chúng tôi cũng sẽ dạy bạn cách sử dụng package tidyr để sắp xếp dữ liệu chưa gọn gàng.
Vì
dep_timeở định dạngHMMhoặcHHMM, chúng ta sử dụng phép chia nguyên (%/%) để lấy giờ và phần dư (còn gọi là modulo,%%) để lấy phút.↩︎