diff --git a/.Rbuildignore b/.Rbuildignore index 44b7552..81e02e1 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -16,3 +16,5 @@ ^task_agent_mapping\.json$ ^\.gitleaks\.toml$ ^\.jules(/.*)?$ +^\.trivyignore\.yaml$ +^trivy\.yaml$ diff --git a/.jules/bolt.md b/.jules/bolt.md index 1abb238..fc04ae0 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-07 - R 언어에서 데이터 프레임의 특정 항목 탐색을 캐싱하여 O(N) 검색 병목 최적화 +**Learning:** R에서 반복문 내부에서 특정 조건을 만족하는 데이터의 위치를 찾기 위해 `which()`를 여러 번 반복 호출하는 것은 O(N) 시간 복잡도를 가져 매번 불필요한 배열 스캔을 유발합니다. 이는 루프의 반복 횟수가 많고, 탐색해야할 데이터가 클 수록 성능 저하의 주 원인이 됩니다. +**Action:** 조건에 맞는 인덱스를 최초 탐색 시 변수에 캐싱(`newIdx`, `oldIdx` 등)하여 저장하고 이후 동일한 데이터 접근 시 캐싱된 인덱스를 사용함으로써 O(1) 수준으로 성능을 향상시킬 수 있습니다. 추가로 스칼라 값에 대한 불필요한 `paste0()` 함수 호출을 제거하여 오버헤드를 줄입니다. diff --git a/R/aFIPC.R b/R/aFIPC.R index 091bf51..25dfcd1 100644 --- a/R/aFIPC.R +++ b/R/aFIPC.R @@ -743,9 +743,13 @@ autoFIPC <- 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)] + for (i in seq_along(oldformCommonItemNames)) { + newFormItemStr <- newformCommonItemNames[i] + oldFormItemStr <- oldformCommonItemNames[i] + + newFormItemName <- newFormColNames[match(newFormItemStr, newFormColNames)] + oldFormItemName <- oldFormColNames[match(oldFormItemStr, oldFormColNames)] + if ( !is.na(newFormItemName) && !is.na(oldFormItemName) && @@ -754,64 +758,49 @@ autoFIPC <- ) { message( 'applying ', - paste0(newformCommonItemNames[i]), + newFormItemStr, ' <<< ', - paste0(oldformCommonItemNames[i]), + oldFormItemStr, ' as common item use' ) + newIdx <- which(NewScaleParms$item == newFormItemStr) + oldIdx <- which(OldScaleParms$item == oldFormItemStr) + message( ' Newform Parms: ', paste0( - NewScaleParms[ - which(NewScaleParms$item == paste0(newformCommonItemNames[i])), - "value" - ], + NewScaleParms[newIdx, "value"], ' ' ) ) message( ' Oldform Parms: ', paste0( - OldScaleParms[ - which(OldScaleParms$item == paste0(oldformCommonItemNames[i])), - "value" - ], + OldScaleParms[oldIdx, "value"], ' ' ) ) - NewScaleParms[ - which(NewScaleParms$item == paste0(newformCommonItemNames[i])), - "value" - ] <- - OldScaleParms[ - which(OldScaleParms$item == paste0(oldformCommonItemNames[i])), - "value" - ] + NewScaleParms[newIdx, "value"] <- + OldScaleParms[oldIdx, "value"] message( ' Linkedform Parms: ', paste0( - NewScaleParms[ - which(NewScaleParms$item == paste0(newformCommonItemNames[i])), - "value" - ], + NewScaleParms[newIdx, "value"], ' ' ), '\n' ) - NewScaleParms[ - which(NewScaleParms$item == paste0(newformCommonItemNames[i])), - "est" - ] <- + NewScaleParms[newIdx, "est"] <- FALSE } else { message( 'skipping ', - paste0(newformCommonItemNames[i]), + newFormItemStr, ' <<< ', - paste0(oldformCommonItemNames[i]), + oldFormItemStr, ' as common item use' ) } @@ -821,9 +810,12 @@ autoFIPC <- length(attr(newFormModel@ParObjects$lrPars, 'parnum')) != 0 && length(attr(oldFormModel@ParObjects$lrPars, 'parnum')) != 0 ) { - NewScaleParms[which(NewScaleParms$item == paste0('BETA')), "value"] <- - OldScaleParms[which(OldScaleParms$item == paste0('BETA')), "value"] - NewScaleParms[which(NewScaleParms$item == paste0('BETA')), "est"] <- + newBetaIdx <- which(NewScaleParms$item == 'BETA') + oldBetaIdx <- which(OldScaleParms$item == 'BETA') + + NewScaleParms[newBetaIdx, "value"] <- + OldScaleParms[oldBetaIdx, "value"] + NewScaleParms[newBetaIdx, "est"] <- FALSE message('applying BETA parameter as linking') @@ -831,7 +823,7 @@ autoFIPC <- message( ' Linkedform Parms: ', paste0( - NewScaleParms[which(NewScaleParms$item == paste0('BETA')), "value"], + NewScaleParms[newBetaIdx, "value"], ' ' ), '\n'