ทำไม `['ดีกว่า` เซตย่อย'


400

เมื่อฉันต้องการกรอง data.frame เช่นแยกแถวที่ตรงตามเงื่อนไขฉันต้องการใช้subsetฟังก์ชั่น:

subset(airquality, Month == 8 & Temp > 90)

มากกว่า[ฟังก์ชั่น:

airquality[airquality$Month == 8 & airquality$Temp > 90, ]

มีสองเหตุผลหลักสำหรับการตั้งค่าของฉัน:

  1. ฉันพบว่ารหัสอ่านดีขึ้นจากซ้ายไปขวา แม้แต่คนที่ไม่รู้อะไรเลยเกี่ยวกับอาร์ก็สามารถบอกได้ว่าsubsetข้อความข้างต้นกำลังทำอะไรอยู่

  2. เนื่องจากคอลัมน์สามารถเรียกได้ว่าเป็นตัวแปรในselectนิพจน์ฉันสามารถบันทึกการกดแป้นบางครั้งได้ ในตัวอย่างของฉันข้างต้นผมมีเพียงพิมพ์airqualityครั้งด้วยแต่สามครั้งด้วยsubset[

ดังนั้นฉันจึงมีความสุขใช้กับsubsetทุกที่เพราะสั้นกว่าและอ่านได้ดีขึ้นแม้จะสนับสนุนความงามของมันให้กับนักเขียนโค้ด R ของฉัน แต่เมื่อวานโลกของฉันแตกสลาย ขณะอ่านsubsetเอกสารฉันสังเกตเห็นส่วนนี้:

คำเตือน

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

ใครช่วยอธิบายสิ่งที่ผู้แต่งหมายถึงได้บ้าง

ก่อนอื่นพวกเขาหมายถึง " เพื่อใช้แบบโต้ตอบ "? ฉันรู้ว่าเซสชันแบบโต้ตอบคืออะไรเมื่อเทียบกับสคริปต์ที่ทำงานในโหมดแบทช์ แต่ฉันไม่เห็นความแตกต่างที่ควรทำ

จากนั้นคุณช่วยอธิบาย " การประเมินผลที่ไม่ได้มาตรฐานของชุดย่อยของข้อโต้แย้ง " และทำไมมันอันตรายหรืออาจเป็นตัวอย่าง?


14
น้อยกว่าเล็กน้อย (แต่ใช้น็อตน้อยกว่าเซตย่อย)with(airquality, airquality[Month == 8 & Temp > 90, ])
Tyler Rinker

7
คุณอาจดู Cirlces 8.2.31 และ 8.2.32 ของ 'The R Inferno' burns-stat.com/pages/Tutor/R_inferno.pdf
Patrick Burns

9
ลองใช้ data.table แทนไวยากรณ์เริ่มต้นจะเหมือนกับ airquality [เดือน == 8 & Temp> 90,] - สามารถอ่านได้และเร็วกว่ามาก
Stian Håklev

3
ตกลง. ดังนั้นหากเซตย่อยไม่ถูกต้อง - แล้ว [vs. dplyr :: filter () คืออะไร
userJT

4
สำหรับผู้ที่สงสัยว่าdplyr::filterมีปัญหาเดียวกัน คือถ้าสภาพแวดล้อมมีตัวแปรที่มีชื่อนั้นมันจะใช้แทนตัวแปรใน data frame ทำให้การแก้จุดบกพร่องสับสน!
Deleet

คำตอบ:


241

คำถามนี้ได้รับการตอบในดีในการแสดงความคิดเห็นโดย @James ชี้ไปที่คำอธิบายที่ดีเยี่ยมโดย Hadley Wickham อันตรายของsubset(และฟังก์ชั่นชอบมัน) [ที่นี่] ไปอ่านมัน!

มันเป็นการอ่านที่ค่อนข้างยาวดังนั้นมันอาจจะเป็นประโยชน์ในการบันทึกที่นี่ตัวอย่างที่ Hadley ใช้ที่ตรงที่สุดคำถามของ "สิ่งที่ผิดพลาด":

Hadley แนะนำตัวอย่างต่อไปนี้: สมมติว่าเราต้องการเซ็ตย่อยแล้วจัดลำดับเฟรมข้อมูลใหม่โดยใช้ฟังก์ชั่นต่อไปนี้:

scramble <- function(x) x[sample(nrow(x)), ]

subscramble <- function(x, condition) {
  scramble(subset(x, condition))
}

subscramble(mtcars, cyl == 4)

สิ่งนี้จะส่งกลับข้อผิดพลาด:

ข้อผิดพลาดใน eval (expr, envir, enclos): ไม่พบวัตถุ 'cyl'

เพราะ R ไม่ "รู้" อีกต่อไปที่จะหาวัตถุที่เรียกว่า 'cyl' เขายังชี้ให้เห็นสิ่งที่แปลกประหลาดอย่างแท้จริงที่สามารถเกิดขึ้นได้หากบังเอิญมีวัตถุที่เรียกว่า 'cyl' ในสภาพแวดล้อมโลก:

cyl <- 4
subscramble(mtcars, cyl == 4)

cyl <- sample(10, 100, rep = T)
subscramble(mtcars, cyl == 4)

(เรียกใช้พวกเขาและดูด้วยตัวคุณเองมันค่อนข้างบ้า)


2
ฉันขอคำถามใหม่สำหรับการชี้แจงได้ไหม เมื่อเราเขียนsubset(mtcars, cyl == 4)(ที่ระดับบนสุด) R จะมองหากระบอกสูบที่ไหน? หากมองเข้าไปในmtcarsวัตถุที่ถูกส่งผ่านไปsubset()แล้วมันจะไม่สามารถค้นหาcylได้แม้ว่าscrambleจะอยู่ในฟังก์ชั่นอื่นเนื่องจากmtcarsยังคงถูกส่งต่อไปหรือไม่ หากคำถามของฉันไม่ได้ทำให้ความรู้สึกคุณก็สามารถอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับสาเหตุ R cylไม่สามารถหาได้ ขอบคุณ!
ไฮเซนเบิร์ก

4
@Anh ภายในสิ่งที่เรากำลังพยายามที่จะประเมินผลการศึกษาที่จุดนั้นเป็นเพียงsubset.data.frame แต่นั่นไม่ได้อยู่ในcondition mtcarsดังนั้นsubset.data.frameการใช้งานenclos = parent.frame()เพื่อให้มั่นใจว่าได้รับการประเมินอย่างถูกต้องตามcondition cyl == 4แต่แล้วเราได้โผล่กลับขึ้นไปกรอบล้อมรอบและตอนนี้เมื่อ R มองหามันไม่ได้มองภายในของcyl mtcarsหากเราไม่ได้ใช้enclosสิ่งที่ต้องการsubset(mtcars,cyl == a)จะไม่ทำงานเลย
joran

ไม่มีใครรู้ว่าทำไมเซ็ตย่อย () จะไม่ใช้วิธีที่เร็วกว่าและปลอดภัยกว่า [เบื้องหลัง]?
Bjorks แฟนหมายเลขหนึ่ง

1
@ MikePalmice มันทำ บรรทัดสุดท้ายของการมีsubset.data.frame x[r, vars, drop = drop]ปัญหาคือว่าจะได้รับจาก unquoted subsetและการขัดแย้งกับสิ่งที่คุณอย่างถูกต้องสามารถส่งผ่านไปselect [.data.frame
joran

@ Jonan เข้าใจแล้วขอบคุณ คุณคิดว่าจะใช้ตัวกรองของ dplyr []อย่างไร
Bjorks แฟนหมายเลขหนึ่ง

30

ยัง[เร็วกว่า:

require(microbenchmark)        
microbenchmark(subset(airquality, Month == 8 & Temp > 90),airquality[airquality$Month == 8 & airquality$Temp > 90,])
    Unit: microseconds
                                                           expr     min       lq   median       uq     max neval
                     subset(airquality, Month == 8 & Temp > 90) 301.994 312.1565 317.3600 349.4170 500.903   100
     airquality[airquality$Month == 8 & airquality$Temp > 90, ] 234.807 239.3125 244.2715 271.7885 340.058   100

36
ใช่และไม่. ฉันคิดว่าความแตกต่างของเวลาที่คุณเห็นนั้นเกิดจากสองสิ่ง 1) ขนาดเล็ก (<100 microseconds) ค่าใช้จ่ายและ 2) subsetซึ่งแตกต่างจากเอาแถวที่กรองประเมิน[ NAทำสิ่งนี้และคุณจะเห็นว่าพวกเขาทั้งสองเร็วเมื่อเปรียบเทียบ " x <- do.call(rbind, rep(list(airquality), 100)); microbenchmark(subset(x, Month == 8 & Temp > 90),{ i <- x$Month == 8 & x$Temp > 90; x[!is.na(i) & i ,] })
ธรรมะ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.