เหตุใดคำสั่ง ifelse ของ R จึงไม่สามารถส่งคืนเวกเตอร์ได้


118

ฉันพบว่าคำสั่ง ifelse ของ R มีประโยชน์เป็นครั้งคราว ตัวอย่างเช่น:

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

แต่ฉันค่อนข้างสับสนกับพฤติกรรมต่อไปนี้

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

นี่เป็นตัวเลือกการออกแบบที่เหนือการจ่ายเงินของฉันหรือไม่


1
การออกแบบที่แปลกเล็กน้อยสำหรับ ifelse เนื่องจากความเรียบง่ายถ้าอย่างอื่นได้ผล
2sb

4
ifelse เป็นฟังก์ชัน vectorized ควรใช้สำหรับงานต่างๆ
marbel

คำตอบ:


99

เอกสารสำหรับifelseรัฐ:

ifelseส่งกลับค่าที่มีรูปร่างเช่นเดียวกับที่testซึ่งเต็มไปด้วยองค์ประกอบที่เลือกจากทั้งสองyesหรือ noขึ้นอยู่กับว่าองค์ประกอบของการtestเป็นหรือTRUEFALSE

เนื่องจากคุณผ่านค่าการทดสอบของความยาว 1 คุณจึงได้ผลลัพธ์ของความยาว 1 หากคุณผ่านเวกเตอร์ทดสอบที่ยาวขึ้นคุณจะได้ผลลัพธ์ที่ยาวขึ้น:

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

ดังนั้นifelseมีไว้เพื่อวัตถุประสงค์เฉพาะในการทดสอบเวกเตอร์ของบูลีนและส่งคืนเวกเตอร์ที่มีความยาวเท่ากันซึ่งเต็มไปด้วยองค์ประกอบที่นำมาจาก (เวกเตอร์) yesและnoอาร์กิวเมนต์

เป็นความสับสนที่พบบ่อยเนื่องจากชื่อของฟังก์ชันที่จะใช้สิ่งนี้เมื่อคุณต้องการเพียงโครงสร้างปกติif () {} else {}แทน


16
if (TRUE) c(1,2) else c(3,4)บางทีสิ่งที่คุณต้องการจริงๆสำหรับชุดที่สองของงบเป็น
Jonathan Chang

69

ฉันพนันได้เลยว่าคุณต้องการifคำสั่งง่ายๆแทนที่จะเป็นifelse- ใน R ifไม่ใช่แค่โครงสร้างโฟลว์การควบคุมเท่านั้น แต่สามารถคืนค่าได้:

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

@ เคนสิ่งนี้ใช้ได้ผลสำหรับฉันแม้ว่าฉันจะได้รับสิ่งที่ฉันต้องการคำเตือนตลอดเวลา" Warning in if (req(inputval) == "All") { : the condition has length > 1 and only the first element will be used"ฉันควรทำอย่างไรเพื่อกำจัดคำเตือนนี้?
user5249203

1
@ user5249203 คำถามและคำตอบของเคนอ้างถึงกรณีที่เงื่อนไขเป็นค่าเดียวคือเวกเตอร์ของความยาว 1 คำเตือนระบุว่าreq(inputval)มีองค์ประกอบมากกว่า เพื่อให้ได้ค่าเดียวฟังก์ชันany()หรือall()อาจเป็นประโยชน์
Uwe

12

โปรดทราบว่าคุณสามารถหลีกเลี่ยงปัญหาได้หากคุณกำหนดผลลัพธ์ภายใน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 นี่เป็นการสนับสนุนให้ใช้ifelse()ฟังก์ชันvectorized ในทางที่ผิดแทนโฟลว์ควบคุมif ... else ...สำหรับการมอบหมายงาน หากเงื่อนไขเป็นค่าเดียวTRUEหรือFALSEค่าฉันต้องการเขียนa <- if (TRUE) c(1,2) else c(3,4)หรือif (TRUE) a <- c(1,2) else a <- c(3,4)
Uwe

1
แม้ว่าฉันจะไม่คิดว่าความแตกต่างของประสิทธิภาพเมื่อใช้ifelseแทนif... elseในกรณีที่มีเงื่อนไขเดียวอาจเป็นปัญหาได้และifelseอาจเป็นที่ต้องการในบางกรณีภายในโค้ด (เดาง่ายๆที่นี่) ฉันไม่เห็นด้วยกับคุณ ;-) ifelseฉันแค่อยากจะแสดงวิธีด้วย
Cath

9

ใช่ฉันคิดว่า ifelse () ได้รับการออกแบบมาสำหรับเมื่อคุณมีเวกเตอร์การทดสอบที่ยาวมากและต้องการแมปแต่ละตัวเลือกกับหนึ่งในสองตัวเลือก ตัวอย่างเช่นฉันมักจะทำสีสำหรับ plot () ด้วยวิธีนี้:

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

ถ้าคุณมีเวกเตอร์ยาวใหญ่ของการทดสอบ แต่อยากคู่ผลคุณสามารถใช้sapply()หรือplyr's llply()หรือสิ่งที่อาจจะ


4

บางครั้งผู้ใช้เพียงแค่ต้องการswitchคำสั่งแทนที่จะเป็นifelseไฟล์. ในกรณีนั้น:

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

(ซึ่งเป็นอีกหนึ่งตัวเลือกไวยากรณ์ของคำตอบของ Ken Williams)


4

นี่คือแนวทางที่คล้ายกับที่ Cath แนะนำ แต่สามารถใช้ได้กับเวกเตอร์ที่กำหนดไว้ล่วงหน้าที่มีอยู่

มันขึ้นอยู่กับการใช้สิ่งget()นี้:

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

4

ใช้ "if" เช่น

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

นี่เป็นคำตอบเดียวที่สามารถให้ฟังก์ชันการทำงานที่คาดหวังของ ifelse ได้
sus_mlm

2

ในกรณีของคุณการใช้if_elsefrom dplyrจะมีประโยชน์: if_elseเข้มงวดกว่าifelseและแสดงข้อผิดพลาดสำหรับกรณีของคุณ:

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

0

พบในeverydropr :

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

สามารถจำลองผลลัพธ์ของเงื่อนไขของคุณเพื่อส่งคืนความยาวที่ต้องการ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.