From 3744c09593f8e922c9c21f8782feed4bb8f748b3 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 12 Jul 2026 19:19:26 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20=EC=B5=9C=EC=A0=81=ED=99=94?= =?UTF-8?q?=20-=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20which()=20?= =?UTF-8?q?=EB=B0=8F=20=EB=B0=98=EB=B3=B5=20=ED=8F=89=EA=B0=80=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=EB=A1=9C=20=EC=84=9C=EB=B8=8C=EC=85=8B=ED=8C=85=20?= =?UTF-8?q?=EA=B0=80=EC=86=8D=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/bolt.md | 3 +++ R/aFIPC.R | 50 ++++++++++++++++++++++---------------------------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 2e7794b..eaa6977 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -10,3 +10,6 @@ ## 2026-07-11 - R 언어에서 루프 내 벡터 동적 확장 및 조건부 탐색 최적화 **Learning:** R에서 for 루프 내에 동적으로 벡터 크기를 늘리면서 (`vector[i] <- value`) 조건을 검사하는 것은 O(N^2)의 복사 오버헤드(copy-on-modify)를 발생시키며 매 반복마다 `match()` 스캔을 수행하면 성능 저하를 초래합니다. **Action:** 루프 외부에 벡터화된 `match()`를 한 번만 수행하여 유효한 인덱스를 찾고, 벡터 인덱싱(`vector[idx]`)으로 한 번에 데이터를 추출하여 불필요한 루프 오버헤드 및 동적 메모리 재할당을 방지하여 O(1) 수준으로 성능을 개선해야 합니다. +## 2024-07-12 - R 언어에서 데이터프레임 서브셋팅 시 불필요한 which() 및 반복 평가 제거 +**Learning:** 데이터 프레임의 특정 로우(row)를 변경할 때 `df[which(df$col == "val"), ]`와 같이 `which()`를 사용하면 내부적으로 추가 함수 호출 및 논리 벡터 평가 오버헤드가 발생합니다. 또한, 여러 값을 업데이트하기 위해 동일한 조건식을 연속으로 사용하면 매번 동일한 O(N) 논리 벡터 평가가 중복해서 일어납니다. 불필요한 `paste0("GROUP")` 호출도 오버헤드를 더합니다. +**Action:** `which()`를 생략하고 직접 논리 인덱싱(`df$col == "val"`)을 사용하며, 동일한 조건식을 두 번 이상 연속으로 사용할 경우 해당 논리 벡터를 변수에 캐싱(`idx <- df$col == "val"`)하여 여러 번 재사용함으로써 중복된 O(N) 선형 스캔을 피하고 성능을 최적화해야 합니다. 또한 불필요한 문자열 연산을 제거합니다. diff --git a/R/aFIPC.R b/R/aFIPC.R index 1c0fb73..9823989 100644 --- a/R/aFIPC.R +++ b/R/aFIPC.R @@ -595,19 +595,15 @@ autoFIPC <- # Preserve mirt's structural estimability flags. Forcing every row TRUE # frees boundary parameters such as 2PL g/u and makes the Hessian unstable. - NewScaleParms[which(NewScaleParms$item == paste0('GROUP')), "est"] <- - FALSE - OldScaleParms[which(OldScaleParms$item == paste0('GROUP')), "est"] <- - FALSE + NewScaleParms[NewScaleParms$item == 'GROUP', "est"] <- FALSE + OldScaleParms[OldScaleParms$item == 'GROUP', "est"] <- FALSE - NewScaleParms[which(NewScaleParms$name == "COV_11"), "est"] <- - TRUE - OldScaleParms[which(OldScaleParms$name == "COV_11"), "est"] <- - TRUE + NewScaleParms[NewScaleParms$name == "COV_11", "est"] <- TRUE + OldScaleParms[OldScaleParms$name == "COV_11", "est"] <- TRUE if (itemtype == 'Rasch') { - NewScaleParms[which(NewScaleParms$name == "a1"), "est"] <- FALSE - OldScaleParms[which(OldScaleParms$name == "a1"), "est"] <- FALSE + NewScaleParms[NewScaleParms$name == "a1", "est"] <- FALSE + OldScaleParms[OldScaleParms$name == "a1", "est"] <- FALSE } #IPD @@ -811,8 +807,8 @@ autoFIPC <- length(attr(newFormModel@ParObjects$lrPars, 'parnum')) != 0 && length(attr(oldFormModel@ParObjects$lrPars, 'parnum')) != 0 ) { - newBetaIdx <- which(NewScaleParms$item == 'BETA') - oldBetaIdx <- which(OldScaleParms$item == 'BETA') + newBetaIdx <- NewScaleParms$item == 'BETA' + oldBetaIdx <- OldScaleParms$item == 'BETA' NewScaleParms[newBetaIdx, "value"] <- OldScaleParms[oldBetaIdx, "value"] @@ -850,18 +846,18 @@ autoFIPC <- if (forceNormalZeroOne) { freeMEAN <- F - NewScaleParms[which(NewScaleParms$name == "COV_11"), "est"] <- - FALSE - OldScaleParms[which(OldScaleParms$name == "COV_11"), "est"] <- - FALSE - NewScaleParms[which(NewScaleParms$name == "MEAN_11"), "est"] <- - FALSE - OldScaleParms[which(OldScaleParms$name == "MEAN_11"), "est"] <- - FALSE - NewScaleParms[which(NewScaleParms$name == "COV_11"), "value"] <- - 1 - OldScaleParms[which(OldScaleParms$name == "MEAN_11"), "value"] <- - 0 + new_cov11_idx <- NewScaleParms$name == "COV_11" + old_cov11_idx <- OldScaleParms$name == "COV_11" + new_mean11_idx <- NewScaleParms$name == "MEAN_11" + old_mean11_idx <- OldScaleParms$name == "MEAN_11" + + NewScaleParms[new_cov11_idx, "est"] <- FALSE + OldScaleParms[old_cov11_idx, "est"] <- FALSE + NewScaleParms[new_mean11_idx, "est"] <- FALSE + OldScaleParms[old_mean11_idx, "est"] <- FALSE + + NewScaleParms[new_cov11_idx, "value"] <- 1 + OldScaleParms[old_mean11_idx, "value"] <- 0 } if (freeMEAN == T) { LinkedModelSyntax <- @@ -872,10 +868,8 @@ autoFIPC <- 'MEAN = F1' )) - NewScaleParms[which(NewScaleParms$name == "MEAN_1"), "est"] <- - TRUE - OldScaleParms[which(OldScaleParms$name == "MEAN_1"), "est"] <- - TRUE + NewScaleParms[NewScaleParms$name == "MEAN_1", "est"] <- TRUE + OldScaleParms[OldScaleParms$name == "MEAN_1", "est"] <- TRUE } else { LinkedModelSyntax <- mirt::mirt.model(paste0(