ปัญหาที่ใหญ่ที่สุดและรากของความไม่มีประสิทธิภาพจัดทำดัชนี data.frame temp[,]
ผมหมายถึงทุกบรรทัดนี้ที่คุณใช้
พยายามหลีกเลี่ยงปัญหานี้ให้มากที่สุด ฉันทำหน้าที่ของคุณเปลี่ยนการจัดทำดัชนีและที่นี่version_A
dayloop2_A <- function(temp){
res <- numeric(nrow(temp))
for (i in 1:nrow(temp)){
res[i] <- i
if (i > 1) {
if ((temp[i,6] == temp[i-1,6]) & (temp[i,3] == temp[i-1,3])) {
res[i] <- temp[i,9] + res[i-1]
} else {
res[i] <- temp[i,9]
}
} else {
res[i] <- temp[i,9]
}
}
temp$`Kumm.` <- res
return(temp)
}
อย่างที่คุณเห็นฉันสร้างเวกเตอร์res
ที่รวบรวมผลลัพธ์ ในตอนท้ายฉันเพิ่มลงในdata.frame
และฉันไม่จำเป็นต้องยุ่งกับชื่อ แล้วมันจะดีกว่านี้อย่างไร?
ผมทำงานในแต่ละฟังก์ชั่นdata.frame
ที่มีnrow
จาก 1,000 ถึง 10,000 1,000 และวัดเวลากับsystem.time
X <- as.data.frame(matrix(sample(1:10, n*9, TRUE), n, 9))
system.time(dayloop2(X))
ผลที่ได้คือ
nrow(X)
คุณจะเห็นว่ารุ่นของคุณขึ้นอยู่กับการชี้แจงจาก เวอร์ชันที่แก้ไขมีความสัมพันธ์เชิงเส้นและlm
แบบจำลองอย่างง่ายทำนายว่าสำหรับการคำนวณแถว 850,000 แถวใช้เวลา 6 นาทีและ 10 วินาที
พลังของ vectorization
ในฐานะที่ Shane และ Calimo กล่าวถึงคำตอบของพวกเขา vectorization เป็นกุญแจสำคัญในการทำงานที่ดีขึ้น จากรหัสของคุณคุณสามารถย้ายออกจากวง:
- เครื่อง
- การเริ่มต้นของผลลัพธ์ (ซึ่งคือ
temp[i,9]
)
สิ่งนี้นำไปสู่รหัสนี้
dayloop2_B <- function(temp){
cond <- c(FALSE, (temp[-nrow(temp),6] == temp[-1,6]) & (temp[-nrow(temp),3] == temp[-1,3]))
res <- temp[,9]
for (i in 1:nrow(temp)) {
if (cond[i]) res[i] <- temp[i,9] + res[i-1]
}
temp$`Kumm.` <- res
return(temp)
}
เปรียบเทียบผลสำหรับฟังก์ชั่นนี้คราวนี้nrow
จาก 10,000 ถึง 100,000 โดย 10,000
ปรับจูน
บิดหนึ่งคือการเปลี่ยนแปลงในการจัดทำดัชนีห่วงtemp[i,9]
ไปres[i]
(ซึ่งเป็นที่แน่นอนเดียวกันในปีที่ i ย้ำห่วง) data.frame
มันเป็นอีกความแตกต่างระหว่างการจัดทำดัชนีเวกเตอร์และจัดทำดัชนี
สิ่งที่สอง: เมื่อคุณดูลูปคุณจะเห็นว่าไม่จำเป็นต้องวนซ้ำทั้งหมดi
แต่เฉพาะสำหรับลูปที่เหมาะสม
ดังนั้นที่นี่เราไป
dayloop2_D <- function(temp){
cond <- c(FALSE, (temp[-nrow(temp),6] == temp[-1,6]) & (temp[-nrow(temp),3] == temp[-1,3]))
res <- temp[,9]
for (i in (1:nrow(temp))[cond]) {
res[i] <- res[i] + res[i-1]
}
temp$`Kumm.` <- res
return(temp)
}
ประสิทธิภาพที่คุณได้รับนั้นขึ้นอยู่กับโครงสร้างข้อมูล แม่นยำ - ตามเปอร์เซ็นต์ของTRUE
ค่าในเงื่อนไข สำหรับข้อมูลจำลองของฉันมันใช้เวลาในการคำนวณสำหรับ 850,000 แถวด้านล่างหนึ่งวินาที
ฉันต้องการให้คุณไปไกลกว่านี้ฉันเห็นอย่างน้อยสองสิ่งที่สามารถทำได้:
- เขียน
C
รหัสเพื่อทำ cumsum ตามเงื่อนไข
หากคุณรู้ว่าในลำดับข้อมูลสูงสุดของคุณไม่ใหญ่คุณสามารถเปลี่ยนวนเป็น vectorized ได้ในขณะนั้น
while (any(cond)) {
indx <- c(FALSE, cond[-1] & !cond[-n])
res[indx] <- res[indx] + res[which(indx)-1]
cond[indx] <- FALSE
}
รหัสที่ใช้สำหรับการจำลองและตัวเลขเป็นที่มีอยู่บน GitHub