Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
## 2024-07-08 - R 언어에서 루프 내 인덱스 검색(which) O(N) 병목 최적화
**Learning:** R에서 반복문 내부에서 특정 조건을 만족하는 데이터의 위치를 찾기 위해 `which()`를 여러 번 호출하면 매번 O(N)의 선형 탐색(linear scan)이 발생하여 데이터 크기가 클수록 성능이 크게 저하됩니다. 또한 `paste0()`를 이용한 불필요한 배열 단위 문자열 생성은 반복문 오버헤드를 가중시킵니다.
**Action:** 조건에 맞는 인덱스를 최초 한 번 `split(seq_len(nrow(df)), df$column)`를 통해 리스트 형태로 캐싱(dictionary lookup)하여 루프 외부에서 O(1) 검색 체계로 만들고, 스칼라 값에 대한 불필요한 `paste0()` 함수 호출을 최적화(`paste(..., collapse=' ')`)하여 오버헤드를 줄입니다.
## 2026-07-11 - R 언어에서 루프 내 벡터 동적 확장 및 조건부 탐색 최적화
**Learning:** R에서 for 루프 내에 동적으로 벡터 크기를 늘리면서 (`vector[i] <- value`) 조건을 검사하는 것은 O(N^2)의 복사 오버헤드(copy-on-modify)를 발생시키며 매 반복마다 `match()` 스캔을 수행하면 성능 저하를 초래합니다.
**Action:** 루프 외부에 벡터화된 `match()`를 한 번만 수행하여 유효한 인덱스를 찾고, 벡터 인덱싱(`vector[idx]`)으로 한 번에 데이터를 추출하여 불필요한 루프 오버헤드 및 동적 메모리 재할당을 방지하여 O(1) 수준으로 성능을 개선해야 합니다.
22 changes: 8 additions & 14 deletions R/aFIPC.R
Original file line number Diff line number Diff line change
Expand Up @@ -619,25 +619,19 @@ autoFIPC <-
rep('newForm', nrow(newformXDataK))
))
IPDItemCount <- 0
IPDItemNamesOldForm <- vector()
IPDItemNamesNewForm <- vector()

# IPD target item checking
newFormColNames <- colnames(newformXDataK[colnames(newFormModel@Data$data)])
oldFormColNames <- colnames(oldformYDataK[colnames(oldFormModel@Data$data)])

for (i in 1:length(oldformCommonItemNames)) {
newFormItemName <- newFormColNames[match(newformCommonItemNames[i], newFormColNames)]
oldFormItemName <- oldFormColNames[match(oldformCommonItemNames[i], oldFormColNames)]
if (
!is.na(newFormItemName) &&
!is.na(oldFormItemName)
) {
IPDItemCount <- IPDItemCount + 1
IPDItemNamesOldForm[IPDItemCount] <- oldFormItemName
IPDItemNamesNewForm[IPDItemCount] <- newFormItemName
}
}
# ⚡ Bolt: Vectorized match() to avoid dynamic array growth overhead inside a for loop
idxNew <- match(newformCommonItemNames, newFormColNames)
idxOld <- match(oldformCommonItemNames, oldFormColNames)
valid_idx <- !is.na(idxNew) & !is.na(idxOld)

IPDItemNamesNewForm <- newFormColNames[idxNew[valid_idx]]
IPDItemNamesOldForm <- oldFormColNames[idxOld[valid_idx]]
IPDItemCount <- length(IPDItemNamesNewForm)

# IPD Data generation
IPDItemList <-
Expand Down
Loading