Tại sao câu lệnh ifelse của R không thể trả về vectơ?


118

Tôi thấy các câu lệnh ifelse của R đôi khi khá hữu ích. Ví dụ:

ifelse(TRUE,1,2)
# [1] 1
ifelse(FALSE,1,2)
# [1] 2

Nhưng tôi hơi bối rối trước hành vi sau đây.

ifelse(TRUE,c(1,2),c(3,4))
# [1] 1
ifelse(FALSE,c(1,2),c(3,4))
# [1] 3

Đây có phải là một lựa chọn thiết kế cao hơn mức lương của tôi không?


1
thiết kế hơi lạ cho ifelse với thực tế là if else đơn giản hoạt động.
2sb

4
ifelse là một hàm được vector hóa. Chúng nên được sử dụng cho các nhiệm vụ khác nhau.
marbel

Câu trả lời:


99

Tài liệu cho ifelsecác tiểu bang:

ifelsetrả về một giá trị có cùng hình dạng testđược lấp đầy bởi các phần tử được chọn từ một trong hai yeshoặc notùy thuộc vào việc phần tử của testTRUEhoặc FALSE.

Vì bạn đang vượt qua các giá trị kiểm tra có độ dài 1, bạn sẽ nhận được kết quả của độ dài 1. Nếu bạn vượt qua các vectơ kiểm tra dài hơn, bạn sẽ nhận được kết quả dài hơn:

> ifelse(c(TRUE, FALSE), c(1, 2), c(3, 4))
[1] 1 4

Vì vậy ifelseđược thiết kế cho mục đích cụ thể là kiểm tra một vectơ boolean và trả về một vectơ có cùng độ dài, chứa đầy các phần tử lấy từ (vectơ) yesvà các nođối số.

Đó là một sự nhầm lẫn phổ biến, vì tên của hàm, sử dụng nó khi bạn thực sự muốn chỉ là một if () {} else {}công trình bình thường .


16
Có lẽ điều bạn thực sự muốn đối với nhóm câu lệnh thứ hai là if (TRUE) c(1,2) else c(3,4).
Jonathan Chang

69

Tôi cá là bạn muốn một ifcâu lệnh đơn giản thay vì ifelse- trong R, ifkhông chỉ là cấu trúc luồng điều khiển, nó có thể trả về một giá trị:

> if(TRUE) c(1,2) else c(3,4)
[1] 1 2
> if(FALSE) c(1,2) else c(3,4)
[1] 3 4

@Ken, điều này phù hợp với tôi, mặc dù tôi nhận được những gì tôi cần cảnh báo liên tục. " Warning in if (req(inputval) == "All") { : the condition has length > 1 and only the first element will be used"Tôi nên làm gì để thoát khỏi cảnh báo này?
user5249203

1
@ user5249203, câu hỏi và câu trả lời của Ken đề cập đến trường hợp điều kiện là một giá trị đơn lẻ, tức là vectơ có độ dài 1. Cảnh báo cho biết req(inputval)có nhiều phần tử hơn. Để nhận một giá trị duy nhất, các hàm any()hoặc all()có thể hữu ích.
Uwe,

12

Lưu ý rằng bạn có thể giải quyết vấn đề nếu bạn gán kết quả bên trong ifelse:

ifelse(TRUE, a <- c(1,2), a <- c(3,4))
a
# [1] 1 2

ifelse(FALSE, a <- c(1,2), a <- c(3,4))
a
# [1] 3 4

3
IMHO, điều này được khuyến khích sử dụng sai ifelse()chức năng vector hóa thay if ... else ...cho luồng điều khiển để phân công. Nếu điều kiện là một TRUEhoặc một FALSEgiá trị, tôi muốn viết a <- if (TRUE) c(1,2) else c(3,4)hoặcif (TRUE) a <- c(1,2) else a <- c(3,4)
Uwe

1
@ Chúng tôi mặc dù tôi không nghĩ sự khác biệt về hiệu suất khi sử dụng ifelsethay vì if... elsetrong trường hợp một điều kiện thực sự có thể là một vấn đề và ifelsecó thể được ưu tiên hơn trong một số trường hợp bên trong mã (đoán đơn giản ở đây), tôi không thể không đồng ý với bạn ;-). Tôi chỉ muốn chỉ một cách với ifelse.
Cath

9

vâng, tôi nghĩ ifelse () thực sự được thiết kế cho khi bạn có một vectơ thử nghiệm dài lớn và muốn ánh xạ mỗi thứ đến một trong hai tùy chọn. Ví dụ, tôi thường tô màu cho plot () theo cách này:

plot(x,y, col = ifelse(x>2,  'red', 'blue'))

Nếu bạn có một vector dài các bài kiểm tra nhưng muốn có các cặp cho đầu ra, có lẽ bạn có thể sử dụng sapply()or plyr's llply()hoặc một cái gì đó.


4

Đôi khi người dùng chỉ cần một switchcâu lệnh thay vì một ifelse. Trong trường hợp đó:

condition <- TRUE
switch(2-condition, c(1, 2), c(3, 4))
#### [1] 1 2

(là một tùy chọn cú pháp khác của câu trả lời của Ken Williams)


4

Đây là một cách tiếp cận tương tự như cách được Cath đề xuất, nhưng nó có thể hoạt động với các vectơ được chỉ định trước hiện có

Nó dựa trên việc sử dụng những thứ get()tương tự như vậy:

a <- c(1,2)
b <- c(3,4)
get(ifelse(TRUE, "a", "b"))
# [1] 1 2

4

sử dụng `if`, ví dụ:

> `if`(T,1:3,2:4)
[1] 1 2 3

Đây là câu trả lời duy nhất ở đây thực sự có thể cung cấp chức năng mong đợi của ifelse.
sus_mlm

2

Trong trường hợp của bạn, việc sử dụng if_elsefrom dplyrsẽ hữu ích: if_elsenghiêm ngặt hơn ifelsevà tạo ra một lỗi cho trường hợp của bạn:

library(dplyr)
if_else(TRUE,c(1,2),c(3,4))
#> `true` must be length 1 (length of `condition`), not 2

0

Tìm thấy trên everydropr :

ifelse(rep(TRUE, length(c(1,2))), c(1,2),c(3,4))
#>[1] 1 2

Có thể sao chép kết quả của điều kiện của bạn để trả về độ dài mong muốn

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.