dplyr กลายพันธุ์ด้วยค่าเงื่อนไข


88

ในดาต้าเฟรมขนาดใหญ่ ("myfile") ที่มีสี่คอลัมน์ฉันต้องเพิ่มคอลัมน์ที่ห้าโดยมีค่าตามเงื่อนไขตามสี่คอลัมน์แรก

ต้องการคำตอบที่มีdplyrและmutateส่วนใหญ่เป็นเพราะความเร็วในชุดข้อมูลขนาดใหญ่

ดาต้าเฟรมของฉันมีลักษณะดังนี้:

  V1 V2 V3 V4
1  1  2  3  5
2  2  4  4  1
3  1  4  1  1
4  4  5  1  3
5  5  5  5  4
...

ค่าของคอลัมน์ที่ห้า (V5) ขึ้นอยู่กับกฎเงื่อนไขบางประการ:

if (V1==1 & V2!=4) {
  V5 <- 1
} else if (V2==4 & V3!=1) {
  V5 <- 2
} else {
  V5 <- 0
}

ตอนนี้ฉันต้องการใช้mutateฟังก์ชันเพื่อใช้กฎเหล่านี้กับทุกแถว (เพื่อหลีกเลี่ยงการวนซ้ำที่ช้า) อะไรทำนองนี้ (และใช่ฉันรู้ว่ามันไม่ได้ผล!):

myfile <- mutate(myfile, if (V1==1 & V2!=4){V5 = 1}
    else if (V2==4 & V3!=1){V5 = 2}
    else {V5 = 0})

นี่ควรเป็นผลลัพธ์:

  V1 V2 V3 V4 V5
1  1  2  3  5  1
2  2  4  4  1  2
3  1  4  1  1  0
4  4  5  1  3  0
5  5  5  5  4  0

วิธีการทำในdplyr?


มีประโยชน์ในการระบุว่า V1..4 เป็นจำนวนเต็มทั้งหมด (ไม่ใช่ตัวประกอบตรรกะสตริงหรือลอย)? และคุณสนใจเกี่ยวกับการจัดการอย่างถูกต้องNA( NaN, +Inf, -Inf)?
smci

ถ้าความเร็วดูเหมือนว่าจะเป็นปัญหาสำหรับพอใจแล้วฉันจะดีกว่าการใช้งานdplyr data.table
Valentin

คำตอบ:


108

ลองสิ่งนี้:

myfile %>% mutate(V5 = (V1 == 1 & V2 != 4) + 2 * (V2 == 4 & V3 != 1))

การให้:

  V1 V2 V3 V4 V5
1  1  2  3  5  1
2  2  4  4  1  2
3  1  4  1  1  0
4  4  5  1  3  0
5  5  5  5  4  0

หรือสิ่งนี้:

myfile %>% mutate(V5 = ifelse(V1 == 1 & V2 != 4, 1, ifelse(V2 == 4 & V3 != 1, 2, 0)))

การให้:

  V1 V2 V3 V4 V5
1  1  2  3  5  1
2  2  4  4  1  2
3  1  4  1  1  0
4  4  5  1  3  0
5  5  5  5  4  0

บันทึก

แนะนำให้คุณตั้งชื่อเฟรมข้อมูลให้ดีขึ้น myfile ทำให้ดูเหมือนว่ามีชื่อไฟล์

ด้านบนใช้อินพุตนี้:

myfile <- 
structure(list(V1 = c(1L, 2L, 1L, 4L, 5L), V2 = c(2L, 4L, 4L, 
5L, 5L), V3 = c(3L, 4L, 1L, 1L, 5L), V4 = c(5L, 1L, 1L, 3L, 4L
)), .Names = c("V1", "V2", "V3", "V4"), class = "data.frame", row.names = c("1", 
"2", "3", "4", "5"))

อัปเดต 1 เนื่องจาก dplyr ที่โพสต์ครั้งแรกได้เปลี่ยน%.%ไป%>%จึงได้แก้ไขคำตอบตามนั้น

อัปเดต 2 dplyr ตอนนี้มีcase_whenโซลูชันอื่น:

myfile %>% 
       mutate(V5 = case_when(V1 == 1 & V2 != 4 ~ 1, 
                             V2 == 4 & V3 != 1 ~ 2,
                             TRUE ~ 0))

ฉันลองวิธีแก้ปัญหาที่สองของคุณแล้ว ฉันได้รับข้อผิดพลาดนี้: เกิดข้อผิดพลาดใน mutate_impl (.data, named_dots (... ), สภาพแวดล้อม ()): REAL () สามารถใช้ได้กับ 'ตัวเลข' เท่านั้นไม่ใช่ 'ตรรกะ' คุณรู้หรือไม่ว่าเกิดอะไรขึ้น?
rdatasculptor

5
ฉันค้นพบวิธีที่ช่วยให้คุณไม่ซ้อนifelseข้อความ:myfile %>% mutate(V5 = ifelse(V1 == 1 & V2 != 4, 1, 0), V5 = ifelse(V2 == 4 & V3 != 1, 2, V5))
อเล็กซ์

32

ด้วยdplyr 0.7.2คุณสามารถใช้case_whenฟังก์ชันที่มีประโยชน์มาก:

x=read.table(
 text="V1 V2 V3 V4
 1  1  2  3  5
 2  2  4  4  1
 3  1  4  1  1
 4  4  5  1  3
 5  5  5  5  4")
x$V5 = case_when(x$V1==1 & x$V2!=4 ~ 1,
                 x$V2==4 & x$V3!=1 ~ 2,
                 TRUE ~ 0)

แสดงออกด้วยdplyr::mutateมันให้:

x = x %>% mutate(
     V5 = case_when(
         V1==1 & V2!=4 ~ 1,
         V2==4 & V3!=1 ~ 2,
         TRUE ~ 0
     )
)

โปรดทราบNAว่าไม่ได้ปฏิบัติเป็นพิเศษเนื่องจากอาจทำให้เข้าใจผิดได้ ฟังก์ชันจะส่งคืนNAก็ต่อเมื่อไม่มีเงื่อนไขที่ตรงกัน ถ้าคุณวางสายด้วยเช่นผมในตัวอย่างของฉันค่าส่งกลับแล้วจะไม่เป็นTRUE ~ ...NA

ดังนั้นคุณต้องครุ่นคิดบอกcase_whenจะใส่ที่มันเป็นโดยการเพิ่มคำสั่งเช่นNA is.na(x$V1) | is.na(x$V3) ~ NA_integer_คำแนะนำ: dplyr::coalesce()บางครั้งฟังก์ชั่นนี้มีประโยชน์จริงๆ!

นอกจากนี้โปรดทราบว่าNAโดยปกติแล้วจะไม่ได้ผลเพียงอย่างเดียวคุณต้องใส่NAค่าพิเศษ: NA_integer_, NA_character_หรือNA_real_.


1
สิ่งนี้เร็วกว่าปัจจัยที่ได้รับอย่างมีนัยสำคัญ
Fato39

12

ดูเหมือนว่าderivedFactorจากmosaicแพ็คเกจถูกออกแบบมาเพื่อสิ่งนี้ ในตัวอย่างนี้จะมีลักษณะดังนี้:

library(mosaic)
myfile <- mutate(myfile, V5 = derivedFactor(
    "1" = (V1==1 & V2!=4),
    "2" = (V2==4 & V3!=1),
    .method = "first",
    .default = 0
    ))

(หากคุณต้องการให้ผลลัพธ์เป็นตัวเลขแทนที่จะเป็นตัวประกอบให้ปิดderivedFactorด้วยเครื่องหมายas.numeric)

โปรดทราบว่า.defaultตัวเลือกรวมกับ.method = "first"ชุด "อื่น" เงื่อนไข - derivedFactorวิธีการนี้ได้อธิบายไว้ในไฟล์วิธีใช้


คุณยังสามารถป้องกันไม่ให้ผลลัพธ์เป็นปัจจัยโดยใช้.asFactor = Fตัวเลือกหรือโดยใช้derivedVariableฟังก์ชัน(ที่คล้ายกัน) ในแพ็คเกจเดียวกัน
Jake Fisher

ดูเหมือนว่าrecodeจาก dplyr 0.5 จะทำสิ่งนี้ ฉันยังไม่ได้ตรวจสอบเลย ดูblog.rstudio.org/2016/06/27/dplyr-0-5-0
Jake Fisher

สิ่งนี้ช้าสำหรับข้อมูลของฉันที่มีแถว 1e6
Fato39

3
@ Fato39 ใช่mosaic::derivedFactorตระกูลของฟังก์ชั่นช้ามาก หากคุณคิดว่าทำไมโปรดตอบคำถาม SO ของฉันเกี่ยวกับเรื่องนี้: stackoverflow.com/questions/33787691/… . ฉันดีใจที่เห็นจากความคิดเห็นอื่น ๆ ของคุณที่dplyr::case_whenเร็วกว่า - ฉันจะต้องเปลี่ยนไปใช้ความคิดเห็นนั้น
Jake Fisher

ฉันกำลังลองคำสั่งต่อไปนี้ไลบรารี (ภาพโมเสค) VENEZ.FINAL2 <- กลายพันธุ์ (VENEZ, SEX = receivedFactor ("M" = (CATEGORY == "BULL" & CATEGORY! = "SIRE"), "F" = ( CATEGORY == "COW" & CATEGORY! = "HEIFER"), .method = "first", .default = "NA")) แต่ไม่ได้ผลเพียงแค่แก้เงื่อนไข VENEZ.FINAL2 <- กลายพันธุ์ (VENEZ, SEX = receivedFactor ("M" = (CATEGORY == "BULL คุณช่วยฉันได้ไหมขอบคุณมาก!
Johanna Ramirez
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.