Sự khác biệt giữa request () và library () là gì?


565

Sự khác biệt giữa require()và là library()gì?



7
Thêm một liên kết đến bài đăng trên blog của @ Yihui trừ khi anh ấy muốn đăng một phiên bản của nó như một câu trả lời. yihui.name/vi/2014/07/l Library
MichaelChirico

4
Tóm tắt bài đăng trên blog của @ Yihui: "Thưa quý vị, tôi đã nói điều này trước đây: request () là cách sai để tải gói R; thay vào đó hãy sử dụng thư viện ()"
De Novo

1
@DanHall ... vì library()ngay lập tức thất bại lớn, sớm và với thông báo lỗi có liên quan (nếu gói không được cài đặt hoặc không thể tải), trong khi require()không gây ra lỗi, chỉ cần âm thầm trả về FALSE boolean bị vứt đi, và khiến mã bị lỗi sau đó và nhiều mật mã hơn với dòng Error: object “bar” not foundtrên (nói) 175.
smci

1
@KonradRudolph: Xong rồi! Cảm ơn phản hôi của bạn.
Marco

Câu trả lời:


86

Ngoài những lời khuyên tốt đã được đưa ra, tôi sẽ thêm vào đây:

Có lẽ tốt nhất là tránh sử dụng require() trừ khi bạn thực sự sẽ sử dụng giá trị mà nó trả về, ví dụ như trong một số vòng kiểm tra lỗi, chẳng hạn như được đưa ra bởi thierry.

Trong hầu hết các trường hợp khác, tốt hơn là sử dụng library(), bởi vì điều này sẽ đưa ra thông báo lỗi tại thời điểm tải gói nếu gói không có sẵn. require()sẽ chỉ thất bại mà không có lỗi nếu gói không có ở đó. Đây là thời điểm tốt nhất để tìm hiểu xem gói cần phải được cài đặt (hoặc có lẽ thậm chí không tồn tại vì nó đánh vần sai). Nhận phản hồi lỗi sớm và vào thời điểm thích hợp sẽ tránh được các vấn đề đau đầu có thể xảy ra với việc theo dõi lý do tại sao mã sau đó thất bại khi nó cố gắng sử dụng các thói quen của thư viện


356

Không có nhiều thứ trong công việc hàng ngày.

Tuy nhiên, theo tài liệu cho cả hai chức năng (được truy cập bằng cách đặt ?trước tên hàm và nhấn enter), requiređược sử dụng bên trong các hàm, vì nó đưa ra cảnh báo và tiếp tục nếu không tìm thấy gói, trong khi đó librarysẽ xuất hiện lỗi.


1
#richiemorrisroe: Cảm ơn bạn. Điều đó có nghĩa là nếu tôi tải các gói tôi cần ngay từ đầu mã R của mình thì tôi chọn cái nào không quan trọng?
Marco

6
miễn là bạn không tải các gói bên trong một hàm, nó thực sự không có gì khác biệt. Tôi tải tất cả các gói của mình bằng cách sử dụng yêu cầu và không biết sự khác biệt là gì cho đến khi tôi đọc trợ giúp sau khi thấy câu hỏi của bạn.
richiemorrisroe

45
Một lý do khác mà tôi sử dụng requirelà nó khiến tôi không đề cập đến các gói như libraries, một thực tế thúc đẩy R-cognoscenti lên tường. Đây librarylà vị trí thư mục nơi các gói ngồi.
IRTFM

22
Họ có sự khác biệt rất phù hợp. Không sử dụng require, trừ khi bạn kiểm tra giá trị trả về (và trong trường hợp đó thường có các lựa chọn thay thế tốt hơn, ví dụ loadNamespace).
Konrad Rudolph

256

Một lợi ích khác require()là nó trả về một giá trị logic theo mặc định. TRUEnếu các gói được tải, FALSEnếu nó không.

> test <- library("abc")
Error in library("abc") : there is no package called 'abc'
> test
Error: object 'test' not found
> test <- require("abc")
Loading required package: abc
Warning message:
In library(package, lib.loc = lib.loc, character.only = TRUE, logical.return = TRUE,  :
  there is no package called 'abc'
> test
[1] FALSE

Vì vậy, bạn có thể sử dụng require()trong các công trình như dưới đây. Điều này chủ yếu hữu ích nếu bạn muốn phân phối mã của mình để cài đặt R của chúng tôi là các gói có thể không được cài đặt.

if(require("lme4")){
    print("lme4 is loaded correctly")
} else {
    print("trying to install lme4")
    install.packages("lme4")
    if(require(lme4)){
        print("lme4 installed and loaded")
    } else {
        stop("could not install lme4")
    }
}

65

Bạn có thể sử dụng require()nếu bạn muốn cài đặt các gói nếu và chỉ khi cần thiết, chẳng hạn như:

if (!require(package, character.only=T, quietly=T)) {
    install.packages(package)
    library(package, character.only=T)
}

Đối với nhiều gói bạn có thể sử dụng

for (package in c('<package1>', '<package2>')) {
    if (!require(package, character.only=T, quietly=T)) {
        install.packages(package)
        library(package, character.only=T)
    }
}

Mẹo chuyên nghiệp:

  • Khi được sử dụng bên trong tập lệnh, bạn có thể tránh màn hình hộp thoại bằng cách chỉ định repostham số install.packages(), chẳng hạn như

    install.packages(package, repos="http://cran.us.r-project.org")
  • Bạn có thể gói require()library()vào suppressPackageStartupMessages(), tốt, chặn các thông báo khởi động gói và cũng có thể sử dụng các tham số require(..., quietly=T, warn.conflicts=F)nếu cần để giữ cho các cài đặt yên lặng.


46

Luôn luôn sử dụng library. Không bao giờ 1 lần sử dụng require.

( 1 Hầu như không bao giờ. Có lẽ .)

Tóm lại, điều này là do, khi sử dụng require, mã của bạn có thể mang lại kết quả sai, khác nhau, mà không báo hiệu lỗi . Điều này là hiếm nhưng không phải là giả thuyết! Xem xét mã này, mang lại kết quả khác nhau tùy thuộc vào việc {dplyr} có thể được tải hay không:

require(dplyr)

x = data.frame(y = seq(100))
y = 1
filter(x, y == 1)

Điều này có thể dẫn đến kết quả sai tinh tế. Sử dụng librarythay vì requireném một lỗi ở đây, báo hiệu rõ ràng rằng có gì đó không đúng. Điều này là tốt .

Nó cũng làm cho việc gỡ lỗi tất cả các lỗi khác trở nên khó khăn hơn: Nếu bạn requiređóng gói khi bắt đầu tập lệnh của mình và sử dụng bản xuất của nó trong dòng 500, bạn sẽ nhận được thông báo lỗi đối tượng 'foo' không tìm thấy trong dòng 500, thay vì một lỗi không có gói gọi là 'bla'.

Trường hợp sử dụng duy nhất được chấp nhận requirelà khi giá trị trả về của nó được kiểm tra ngay lập tức, như một số câu trả lời khác hiển thị. Đây là một mẫu khá phổ biến nhưng ngay cả trong những trường hợp này, tốt hơn là (và được khuyến nghị, xem bên dưới) để thay vào đó tách biệt kiểm tra tồn tại và tải gói.

Về mặt kỹ thuật hơn, requirethực sự gọi librarynội bộ (nếu gói chưa được đính kèm - requiredo đó thực hiện kiểm tra dự phòng, vì library cũng kiểm tra xem gói đã được tải chưa). Đây là một triển khai đơn giản hóa requiređể minh họa những gì nó làm:

require = function (package) {
    already_attached = paste('package:', package) %in% search()
    if (already_attached) return(TRUE)
    maybe_error = try(library(package, character.only = TRUE)) 
    success = ! inherits(maybe_error, 'try-error')
    if (! success) cat("Failed")
    success
}

Các nhà phát triển R có kinh nghiệm đồng ý:

Yihui Xie , tác giả của {đanr}, {bookdown} và nhiều gói khác nói :

Thưa quý vị, tôi đã nói điều này trước đây: Yêu cầu () là cách sai để tải gói R; sử dụng thư viện () thay thế

Hadley Wickham , tác giả của các gói R phổ biến hơn bất kỳ ai khác, nói

Sử dụng library(x)trong các kịch bản phân tích dữ liệu. [V]] Bạn không bao giờ cần sử dụng require()( requireNamespace()hầu như luôn luôn tốt hơn)


Tôi sẽ chỉ chính xác như vậy, trừ khi bạn gọi TẤT CẢ các hàm bằng cú pháp class::function, sử dụng library()để tránh chính xác điều đó.
Ma

19
?library

và bạn sẽ thấy:

library(package)require(package)cả hai tải gói với tên packagevà đặt nó vào danh sách tìm kiếm. requiređược thiết kế để sử dụng bên trong các chức năng khác; nó trả về FALSEvà đưa ra cảnh báo (chứ không phải là lỗi như library()mặc định) nếu gói không tồn tại. Cả hai chức năng đều kiểm tra và cập nhật danh sách các gói hiện đang tải và không tải lại gói đã được tải. (Nếu bạn muốn tải lại gói đó, hãy gọi detach(unload = TRUE)hoặc unloadNamespacetrước.) Nếu bạn muốn tải gói mà không đưa nó vào danh sách tìm kiếm, hãy sử dụng requireNamespace.


9

Lý thuyết ban đầu của tôi về sự khác biệt là librarytải các gói cho dù nó đã được tải hay chưa, nghĩa là nó có thể tải lại một gói đã được tải, trong khi requirechỉ kiểm tra xem nó đã được tải hay tải chưa nếu không (do đó sử dụng các hàm mà dựa vào một gói nhất định). Tuy nhiên, tài liệu bác bỏ điều này và tuyên bố rõ ràng rằng không có chức năng nào sẽ tải lại một gói đã được tải.


18
Điều này thật thú vị, nhưng thực sự không phải là một câu trả lời cho câu hỏi ...?
Ben Bolker


3

Đây dường như là sự khác biệt trên một gói đã được tải. Mặc dù đúng là cả yêu cầu và thư viện đều không tải gói. Thư viện làm rất nhiều thứ khác trước khi nó kiểm tra và thoát ra.

Tôi sẽ khuyên bạn nên loại bỏ "yêu cầu" từ đầu một chức năng chạy 2 triệu lần dù sao, nhưng nếu, vì một số lý do tôi cần phải giữ nó. yêu cầu về mặt kỹ thuật là kiểm tra nhanh hơn.

microbenchmark(req = require(microbenchmark), lib = library(microbenchmark),times = 100000)
Unit: microseconds
 expr    min     lq      mean median     uq        max neval
  req  3.676  5.181  6.596968  5.655  6.177   9456.006 1e+05
  lib 17.192 19.887 27.302907 20.852 22.490 255665.881 1e+05

Tôi cho rằng đây là một lý do mạnh mẽ để sửa lỗi triển khai librarythay vào đó (cả hai chức năng, như hiện đang được vận chuyển với R, là một mớ hỗn độn rất lớn).
Konrad Rudolph

@KonradRudolph tốt, nếu ai đó sẽ sửa thư viện, có lẽ họ cũng có thể cho phép tải theo phiên bản một cách rõ ràng và làm cho tệp đính kèm trở thành một tùy chọn đối số
Hình dạng

Vâng, tôi hoàn toàn đồng ý nhưng những điều đó sẽ thay đổi ngữ nghĩa, không chỉ là hiệu suất. Dù sao, phiên bản sẽ không bao giờ hoạt động với các gói trong R, thật không may. Tôi đang làm việc để thay thế cho điều này (thực sự!). Đối với việc đính kèm, bạn có thể sử dụng loadNamespace, tải một gói và trả về không gian tên của nó, mà không cần đính kèm.
Konrad Rudolph
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.