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 @@ -4,3 +4,6 @@
## 2024-07-07 - R 언어에서 데이터 프레임의 특정 항목 탐색을 캐싱하여 O(N) 검색 병목 최적화
**Learning:** R에서 반복문 내부에서 특정 조건을 만족하는 데이터의 위치를 찾기 위해 `which()`를 여러 번 반복 호출하는 것은 O(N) 시간 복잡도를 가져 매번 불필요한 배열 스캔을 유발합니다. 이는 루프의 반복 횟수가 많고, 탐색해야할 데이터가 클 수록 성능 저하의 주 원인이 됩니다.
**Action:** 조건에 맞는 인덱스를 최초 탐색 시 변수에 캐싱(`newIdx`, `oldIdx` 등)하여 저장하고 이후 동일한 데이터 접근 시 캐싱된 인덱스를 사용함으로써 O(1) 수준으로 성능을 향상시킬 수 있습니다. 추가로 스칼라 값에 대한 불필요한 `paste0()` 함수 호출을 제거하여 오버헤드를 줄입니다.
## 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=' ')`)하여 오버헤드를 줄입니다.
35 changes: 11 additions & 24 deletions R/aFIPC.R
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,10 @@ autoFIPC <-
newFormColNames <- colnames(newformXDataK[colnames(newFormModel@Data$data)])
oldFormColNames <- colnames(oldformYDataK[colnames(oldFormModel@Data$data)])

# ⚡ Bolt: Cache parameter indices to avoid O(N) linear search inside loop
newScaleParmsItemIdxCache <- split(seq_len(nrow(NewScaleParms)), NewScaleParms$item)
oldScaleParmsItemIdxCache <- split(seq_len(nrow(OldScaleParms)), OldScaleParms$item)

for (i in seq_along(oldformCommonItemNames)) {
newFormItemStr <- newformCommonItemNames[i]
oldFormItemStr <- oldformCommonItemNames[i]
Expand All @@ -780,34 +784,17 @@ autoFIPC <-
' as common item use'
)

newIdx <- which(NewScaleParms$item == newFormItemStr)
oldIdx <- which(OldScaleParms$item == oldFormItemStr)
# ⚡ Bolt: Use cached O(1) dictionary lookups instead of O(N) which() scans
newIdx <- newScaleParmsItemIdxCache[[newFormItemStr]]
oldIdx <- oldScaleParmsItemIdxCache[[oldFormItemStr]]

message(
' Newform Parms: ',
paste0(
NewScaleParms[newIdx, "value"],
' '
)
)
message(
' Oldform Parms: ',
paste0(
OldScaleParms[oldIdx, "value"],
' '
)
)
# ⚡ Bolt: Remove unnecessary paste0() array string generation overhead
message(' Newform Parms: ', paste(NewScaleParms[newIdx, "value"], collapse = ' '))
message(' Oldform Parms: ', paste(OldScaleParms[oldIdx, "value"], collapse = ' '))

NewScaleParms[newIdx, "value"] <-
OldScaleParms[oldIdx, "value"]
message(
' Linkedform Parms: ',
paste0(
NewScaleParms[newIdx, "value"],
' '
),
'\n'
)
message(' Linkedform Parms: ', paste(NewScaleParms[newIdx, "value"], collapse = ' '), '\n')

NewScaleParms[newIdx, "est"] <-
FALSE
Expand Down
Loading