Menu

Package trong R: install.packages(), library() và CRAN

Cách package trong R hoạt động: cài từ CRAN bằng install.packages(), nạp bằng library(), require() và library(), pkg::fun(), và những package đáng biết.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Package là gì

Package là một gói gồm các hàm, tài liệu và đôi khi cả dữ liệu, giúp mở rộng R. Base R cho bạn vector, mô hình và biểu đồ; package cho bạn mọi thứ còn lại, và "mọi thứ còn lại" đó rất khổng lồ. CRAN (Comprehensive R Archive Network) lưu trữ khoảng 20.000 package, mỗi package đều được kiểm tra bằng các bài test của CRAN trước khi được phát hành. Kho này là lý do chính giúp R luôn có sức cạnh tranh trong công việc dữ liệu: dù là phân tích gì, nhiều khả năng đã có người đóng gói sẵn.

CRAN không phải nguồn duy nhất: Bioconductor chứa hệ sinh thái tin sinh học, và rất nhiều package đang phát triển nằm trên GitHub (cài bằng remotes::install_github()). Nhưng khi mới bắt đầu, bạn có thể coi CRAN là mặc định, còn các nguồn khác là thứ bạn sẽ gặp khi một tệp README bảo bạn dùng chúng.

Một số package đi kèm sẵn với R (stats, utils, graphics và các package tương tự) và được nạp tự động; đó là lý do mean() và plot() dùng được ngay. Mọi package khác đều theo quy trình hai bước dưới đây.

install.packages() một lần, library() mỗi phiên

Đây là nhầm lẫn số 1 của người mới, nên hãy nói thật rõ ràng. Để một package hoạt động cần hai hành động khác nhau với hai vòng đời khác nhau:

install.packages("dplyr")   # ONCE per machine: downloads from CRAN and installs
library(dplyr)              # EVERY session: loads it so your code can use it
  • install.packages("dplyr") giống như mua một cuốn sách: bạn làm một lần, và từ đó nó nằm trên kệ (ổ đĩa của bạn). Để ý dấu ngoặc kép: bạn đang truyền tên package dưới dạng chuỗi.
  • library(dplyr) giống như lấy cuốn sách xuống khỏi kệ: bạn làm việc này đầu mỗi phiên R (trong thực tế là ở đầu mỗi script). Ở đây không cần dấu ngoặc kép: library() là hàm đặc biệt và chấp nhận tên viết trực tiếp (library("dplyr") cũng chạy được, nếu bạn thích sự nhất quán).

Hai kiểu lỗi cho bạn biết mình đã bỏ qua bước nào. Error: there is no package called 'dplyr' từ library() nghĩa là package chưa bao giờ được cài. Error: could not find function "filter" (hoặc "%>%") xuất hiện giữa chừng một script nghĩa là package đã cài nhưng phiên này chưa nạp nó. Đặt mọi lệnh library() ngay ở đầu script, thay vì rải rác khắp nơi, giúp lỗi thứ hai lộ ra ngay giây đầu tiên, đồng thời đóng vai trò danh sách các phụ thuộc của script. Cài tidyverse cũng theo cách tương tự: install.packages("tidyverse") một lần, library(tidyverse) mỗi phiên, lệnh này nạp dplyr, ggplot2 và các package cốt lõi còn lại chỉ trong một dòng.

Điều bạn không nên làm là để install.packages() bên trong một script bạn chạy nhiều lần hoặc chia sẻ cho người khác: nó sẽ tải lại mỗi lần chạy và có thể khiến người chạy bất ngờ. Cài đặt là việc làm ở console; nạp package là việc của script.

require() và pkg::fun()

require() trông như từ đồng nghĩa của library(), và dùng sai theo kiểu đó là chuyện thường gặp. Khác biệt nằm ở điều xảy ra khi thiếu package: library() dừng lại với một lỗi; require() in ra cảnh báo, trả về FALSE và để script chạy tiếp, thường là để rồi chết hai mươi dòng sau với thông báo khó hiểu "could not find function" thay vì thông báo thẳng thắn "no package called". Để nạp các phụ thuộc, hãy dùng library(): báo lỗi rõ ràng ngay từ đầu là một tính năng. require() chỉ thật sự có ích trong các phép kiểm tra điều kiện, nơi giá trị trả về của nó mới là điều quan trọng:

if (!require(praise)) {
    install.packages("praise")
    library(praise)
}

Còn có một cách dùng package mà không cần nạp nó: toán tử :: gọi một hàm theo địa chỉ đầy đủ, package::function(). Package phải được cài sẵn, nhưng không có gì được gắn vào phiên làm việc của bạn:

(stats vốn được nạp tự động, nên sd() đơn thuần cũng chạy được, nhưng cú pháp này giống nhau với mọi package đã cài.) :: phát huy tác dụng ở hai chỗ: những lần gọi một lần, nơi viết cả dòng library() là thừa, và khi cần phân biệt hai package đã nạp cùng xuất ra một tên hàm: dplyr::filter() và stats::filter() là ví dụ trùng tên kinh điển.

Cập nhật package

Package phát triển độc lập với R, nên việc cập nhật là trách nhiệm của bạn:

update.packages()          # offers to update everything outdated
update.packages(ask = FALSE)   # same, without prompting per package

Một quy tắc không hiển nhiên: package được build cho một phiên bản major.minor cụ thể của R. Khi bạn nâng cấp chính R (ví dụ từ 4.3 lên 4.4, xem cài đặt R), thư viện package cũ thường không được mang theo, và cách khắc phục đơn giản là cài lại các package bạn dùng trên phiên bản mới. Mười phút chạy install.packages(), không phải thảm họa, nhưng lần đầu ai cũng bất ngờ khi các script chào đón bản R mới cài bằng một loạt lỗi "no package called".

Xem bạn đang có gì

Ba hàm trả lời câu hỏi "đã cài những gì và nằm ở đâu":

installed.packages()[, "Version"]   # every installed package with its version
sessionInfo()                       # R version + what THIS session has loaded
.libPaths()                         # the folders where packages are installed

installed.packages() trả về một ma trận với mỗi hàng là một package; cột Version thường là thứ bạn cần. sessionInfo() là công cụ để tái tạo kết quả: dán kết quả của nó vào báo cáo lỗi, người đọc sẽ biết phiên bản R, hệ điều hành và phiên bản chính xác của mọi package đã nạp. .libPaths() cho thấy các thư mục thư viện mà R tìm kiếm; biết đến nó sẽ giúp bạn hiểu "package đó thực ra đã đi đâu?" và vì sao đôi khi cần quyền quản trị trên máy dùng chung.

Những package đáng biết

Hôm nay bạn chưa cần chúng, nhưng bạn sẽ gặp chúng liên tục; biết mỗi package dùng để làm gì sẽ giúp bạn đọc code của người khác:

  • dplyr: các động từ xử lý dữ liệu filter, mutate, group_by, summarize.
  • ggplot2: package vẽ biểu đồ tiêu chuẩn; phần lớn biểu đồ R bạn thấy trên mạng là ggplot2.
  • tidyr: chuyển đổi dữ liệu giữa dạng rộng và dạng dài (pivot_longer, pivot_wider).
  • readr / readxl: lần lượt là đọc CSV nhanh và đọc tệp Excel.
  • lubridate: làm việc với ngày tháng theo đúng cách bạn mong đợi.
  • stringr: xử lý chuỗi một cách nhất quán.
  • data.table: một hệ sinh thái data frame hiệu năng cao thay thế; một "phương ngữ" khác với tidyverse, được ưa chuộng cho dữ liệu lớn.
  • shiny: ứng dụng web tương tác viết hoàn toàn bằng R.

Sáu package đầu là phần cốt lõi của tidyverse và được cài cùng lúc bằng install.packages("tidyverse"). Bạn không bắt buộc phải dùng package nào trong số đó, vì base R làm được tất cả, nhưng phần lớn code R hiện đại sống trong hệ sinh thái này.

Những điều cần nhớ

  • CRAN lưu trữ khoảng 20.000 package đã được kiểm tra; Bioconductor và GitHub lo phần còn lại.
  • install.packages("name") một lần mỗi máy (bắt buộc có dấu ngoặc kép); library(name) một lần mỗi phiên, ở đầu script.
  • library() báo lỗi rõ ràng, điều đó tốt; require() trả về FALSE, chỉ hữu ích bên trong các phép kiểm tra.
  • pkg::fun() dùng một hàm mà không cần gắn package, và giải quyết chuyện trùng tên.
  • update.packages() giữ mọi thứ luôn mới; nâng cấp R lớn đồng nghĩa với cài lại package.
  • sessionInfo() là cách bạn cho người khác (hoặc chính bạn sau này) biết chính xác code đã chạy trên môi trường nào.

Tiếp theo: thư mục làm việc, nơi R tìm tệp, và vì sao đó là thứ đầu tiên cần kiểm tra khi đọc dữ liệu thất bại.

Câu hỏi thường gặp

Làm sao để cài một package trong R?

Chạy install.packages("name") với tên package đặt trong dấu ngoặc kép, ví dụ install.packages("dplyr"). R tải package từ CRAN và cài vào máy của bạn. Bạn chỉ cần làm việc này một lần trên mỗi máy; sau đó, nạp nó trong mỗi phiên bằng library(dplyr).

install.packages() và library() khác nhau thế nào?

install.packages("dplyr") tải package về máy tính của bạn, một lần trên mỗi máy. library(dplyr) nạp một package đã cài vào phiên làm việc hiện tại, một lần mỗi phiên, thường ở đầu mỗi script. Cài mà không nạp thì bạn chẳng dùng được gì; nạp mà chưa cài thì sẽ báo lỗi "there is no package called 'dplyr'".

library() và require() trong R khác nhau thế nào?

Cả hai đều nạp package, nhưng khi thất bại thì library() dừng lại với một lỗi, còn require() chỉ cảnh báo và trả về FALSE. Vì vậy library() phù hợp cho script, để báo lỗi rõ ràng và sớm, còn require() chỉ hữu ích bên trong các phép kiểm tra điều kiện như if (!require(pkg)) install.packages(pkg).

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu