1. Về môi trường của R

Trước khi tìm hiểu về cách thức hoạt động của hàm attach(), sẽ dễ dàng hơn nếu bạn hiểu sơ lược về môi trường (environment) của R và cách mà R truy xuất các đối tượng (objects).

Về cơ bản, environment có nhiệm vụ liên kết hay gán (bind) tên/biếngiá trị. Tất cả các đối tượng trong environment phải có tên là duy nhất (unique).

e <- new.env()                          # tạo environment e

## gán giá trị cho 2 biến x và y
e$x <- "a"
e$y <- 10

ls(e)                                   # hiển thị các đối tượng trong environment e
## [1] "x" "y"

Một đặc điểm của environment là luôn có 1 environment khác chứa lâý nó, thường gọi là parent environment. Như trong trường hợp của environment e bên trên, parent environment là globalenv() hay global environment.

parent.env(e)
## <environment: R_GlobalEnv>

Global environment là 1 trường hợp đặc biệt (còn 1 số trường hợp khác không được nêu ra ở đây), thường là nơi mà bạn sẽ làm việc chủ yếu. Tất cả các đôí tượng (hàm, biến, môi trường, …) do người dùng tạo ra đều chứa trong global environment. Khi bạn goị hàm ls() hoặc ls.str()thì phương án mặc định là hiển thị các đối tượng trong global environment.

a <- "this is a sample string"
b <- rnorm(100)
ls.str()                                    # gồm biến a, b và environment e
## a :  chr "this is a sample string"
## b :  num [1:100] 0.743 0.171 1.564 -1.408 1.984 ...
## e : <environment: 0x34abde0>

Ok, chúng ta đã biết được các đối tượng được “lưu giữ” ở đâu, bây giờ là cách mà R “truy tìm” các đối tượng đó, thông qua hàm search(). Hàm search() sẽ cho biết tất cả parent (gồm packages mặc định của R và các packages được gọi thông qua library() hoặc require(), và có thể bạn chưa biết các objects được attached) của global environment, nguyên tắc “truy tìm” sẽ là đi từ trong ra ngoài (top-level), thuật ngữ gọi là search path.

search()
## [1] ".GlobalEnv"        "package:stats"     "package:graphics" 
## [4] "package:grDevices" "package:utils"     "package:datasets" 
## [7] "package:methods"   "Autoloads"         "package:base"

Ví dụ, khi bạn gọi biến a, R sẽ tìm truớc tiên trong global environment, nếu không có, R sẽ tìm trong môi truờng kế tiếp, như trường hợp cụ thể ở đây là package stats, tiếp tục như vậy đến base package.

2. Attach() hoạt động như nào?

Attach(), đúng như mô tả cuả hàm này, là gán đối tượng (thường là data frame) vào search path của R.

The database is attached to the R search path. This means that the database is searched by R when evaluating a variable, so objects in the database can be accessed by simply giving their names.

Điều quan trọng mà bạn cần phải lưu ý ở đây là, đối tượng được attached là parent của global environment.

my_df <- data.frame(v1 = letters, v2 = LETTERS, stringsAsFactors = FALSE)
attach(my_df)
search()
##  [1] ".GlobalEnv"        "my_df"             "package:stats"    
##  [4] "package:graphics"  "package:grDevices" "package:utils"    
##  [7] "package:datasets"  "package:methods"   "Autoloads"        
## [10] "package:base"
parent.env(.GlobalEnv)
## <environment: 0x2e72c60>
## attr(,"name")
## [1] "my_df"

v1, v2 giờ như 2 đối tượng độc lập (nằm trong 1 environment mới là my_df), đã nằm trong search path của R và là duy nhất, nên tuân theo nguyên tắc “truy tìm” bên trên, có thể dễ dàng goị ra bằng tên

print(v1)
##  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q"
## [18] "r" "s" "t" "u" "v" "w" "x" "y" "z"
print(v2)
##  [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q"
## [18] "R" "S" "T" "U" "V" "W" "X" "Y" "Z"

Tuy nhiên, khi có đối tượng cùng tên khác được tạo ra, đối tượng này sẽ được ưu tiên hơn trong search path (vì nằm trong global environment). Còn đối tượng không được ưu tiên (do nằm ngoài global environment) sẽ bị masked.

v1 <- "R is a powerful language"

print(v1)
## [1] "R is a powerful language"

Nói ngắn gọn, attach() sẽ tiện lợi khi bạn làm interactive work, đặc biệt khi có ít data frame và tên của data frame dài_lê_thê_như_thế_này. Hiểu cách R “truy tìm” đối tượng như bên trên trình bày, bạn sẽ khó gặp sai sót. Còn trong môi trường lập trình (production), tốt nhất không nên dùng attach() nếu bạn không muốn ngồi debug cả ngày :).