diff --git a/.jules/bolt.md b/.jules/bolt.md index 1abb238..5af3dd7 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -1,3 +1,6 @@ ## 2024-07-04 - R 언어에서 루프 내 데이터 프레임 탐색 병목 최적화 **Learning:** R에서 루프를 돌면서 매번 데이터 프레임을 서브셋팅(subsetting)하는 작업은 복사 오버헤드로 인해 매우 느려질 수 있습니다. 특히 공통 문항 수가 많아질 경우 O(N^2)의 비효율을 초래합니다. **Action:** 루프 내에서 수행하던 데이터 프레임 조회를 루프 외부에서 한 번에 `as.character(unlist(...))`로 처리하는 벡터 연산으로 변경하여 타입 변환 없이 O(1) 수준으로 성능을 크게 향상시킬 수 있습니다. +## 2024-07-26 - R 언어에서 루프 내 불필요한 배열 스캔 및 문자열 조작 병목 +**Learning:** R에서 `for` 루프 내부에서 데이터프레임의 특정 열을 조건으로 조회할 때(`which()`), 이를 루프 안에서 매번 호출하면 매번 O(N)의 스캔이 발생하여 반복 횟수에 비례해 급격한 성능 저하를 초래합니다. 또한 R 4.0 이상부터는 단일 문자열 변수를 출력할 때 `paste0()`로 감싸는 것이 불필요한 함수 호출을 유발합니다. +**Action:** 동일한 `which()` 결과를 루프 내에서 여러 번 참조해야 하는 경우 루프 내부의 변수에 캐싱(caching)하여 O(N) 연산을 1회로 줄이고, 루프 내 단일 문자열 변수의 경우 `paste0()` 래핑을 제거해 성능을 개선할 수 있습니다. diff --git a/R/aFIPC.R b/R/aFIPC.R index 2e5ac4a..a61c40e 100644 --- a/R/aFIPC.R +++ b/R/aFIPC.R @@ -725,17 +725,21 @@ autoFIPC <- ) { message( 'applying ', - paste0(newformCommonItemNames[i]), + newformCommonItemNames[i], ' <<< ', - paste0(oldformCommonItemNames[i]), + oldformCommonItemNames[i], ' as common item use' ) + # ⚡ Bolt: Cache index lookups to avoid repeated O(N) scans + new_idx <- which(NewScaleParms$item == newformCommonItemNames[i]) + old_idx <- which(OldScaleParms$item == oldformCommonItemNames[i]) + message( ' Newform Parms: ', paste0( NewScaleParms[ - which(NewScaleParms$item == paste0(newformCommonItemNames[i])), + new_idx, "value" ], ' ' @@ -745,7 +749,7 @@ autoFIPC <- ' Oldform Parms: ', paste0( OldScaleParms[ - which(OldScaleParms$item == paste0(oldformCommonItemNames[i])), + old_idx, "value" ], ' ' @@ -753,18 +757,18 @@ autoFIPC <- ) NewScaleParms[ - which(NewScaleParms$item == paste0(newformCommonItemNames[i])), + new_idx, "value" ] <- OldScaleParms[ - which(OldScaleParms$item == paste0(oldformCommonItemNames[i])), + old_idx, "value" ] message( ' Linkedform Parms: ', paste0( NewScaleParms[ - which(NewScaleParms$item == paste0(newformCommonItemNames[i])), + new_idx, "value" ], ' ' @@ -773,16 +777,16 @@ autoFIPC <- ) NewScaleParms[ - which(NewScaleParms$item == paste0(newformCommonItemNames[i])), + new_idx, "est" ] <- FALSE } else { message( 'skipping ', - paste0(newformCommonItemNames[i]), + newformCommonItemNames[i], ' <<< ', - paste0(oldformCommonItemNames[i]), + oldformCommonItemNames[i], ' as common item use' ) }