Skip to content
Open
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 @@ -16,3 +16,6 @@
## 2025-02-12 - R 언어에서 반복적인 mirt 모델 생성 시 불필요한 데이터프레임 부분집합 추출 최적화
**Learning:** R에서 데이터프레임의 특정 열을 추출하는 작업(`df[cols]`)은 O(N)의 메모리 복사를 수반합니다. `autoFIPC`에서 `mirt` 모델의 파라미터를 설정하거나 호출하는 과정 중에 `newformXDataK[colnames(newFormModel@Data$data)]` 코드가 반복해서 사용되었고, 심지어 `ncol()`을 위해 단순히 개수를 구할 때도 사용되어 불필요한 메모리 할당과 오버헤드를 초래했습니다.
**Action:** 조건문이나 반복문 내부에서 불필요하게 데이터프레임 부분집합 연산이 반복되지 않도록 외부에서 한 번만 `linkedFormData <- newformXDataK[colnames(newFormModel@Data$data)]`로 캐싱(caching)한 뒤, `ncol(linkedFormData)`와 `data = linkedFormData` 형태로 재사용하여 메모리 복사와 O(N) 오버헤드를 방지해야 합니다.
## 2025-02-13 - R 언어에서 불필요한 데이터 프레임 서브셋팅을 제거하여 열 이름 추출 성능 향상
**Learning:** `colnames(df[cols])` 형태의 코드는 단순히 데이터 프레임의 특정 열의 이름(colnames)을 확인하기 위함일지라도 `df[cols]`라는 과정에서 O(N)의 무거운 데이터 복사(subsetting)가 발생하여 불필요한 메모리를 할당하고 성능을 크게 저하시킬 수 있습니다.
**Action:** 단순히 어떤 열 이름이 데이터 프레임에 존재하는지 확인하거나 일치하는 열 이름을 순서대로 가져와야 할 때, 부분집합 추출(`df[cols]`) 대신 `intersect(cols, colnames(df))`를 사용하여 복사 없이 O(1) 수준의 벡터 집합 연산으로 최적화합니다.
10 changes: 6 additions & 4 deletions R/aFIPC.R
Original file line number Diff line number Diff line change
Expand Up @@ -620,8 +620,9 @@ autoFIPC <-
IPDItemCount <- 0

# IPD target item checking
newFormColNames <- colnames(newformXDataK[colnames(newFormModel@Data$data)])
oldFormColNames <- colnames(oldformYDataK[colnames(oldFormModel@Data$data)])
# ⚡ Bolt: Replace O(N) data frame copying with O(1) string intersection
newFormColNames <- intersect(colnames(newFormModel@Data$data), colnames(newformXDataK))
oldFormColNames <- intersect(colnames(oldFormModel@Data$data), colnames(oldformYDataK))
Comment on lines +623 to +625

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== files ==\n'
git ls-files R/aFIPC.R .jules/bolt.md

printf '\n== aFIPC outline ==\n'
ast-grep outline R/aFIPC.R --view expanded || true

printf '\n== aFIPC relevant lines ==\n'
sed -n '600,780p' R/aFIPC.R | cat -n

printf '\n== bolt doc relevant lines ==\n'
if [ -f .jules/bolt.md ]; then
  sed -n '1,80p' .jules/bolt.md | cat -n
fi

Repository: ContextualWisdomLab/aFIPC

Length of output: 11421


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== locate aFIPC helpers and validations ==\n'
rg -n "setdiff\\(|intersect\\(|missing.*column|missing.*열|stop\\(|abort\\(" R/aFIPC.R

printf '\n== surrounding function definitions ==\n'
ast-grep outline R/aFIPC.R --view expanded || true

Repository: ContextualWisdomLab/aFIPC

Length of output: 4662


누락 열을 조용히 제거하지 말고 명시적으로 중단하세요.

  • R/aFIPC.R#L624-L625R/aFIPC.R#L754-L755intersect()는 모델/입력 열 불일치를 숨겨서, 없는 열에서 나던 오류 대신 일부 문항을 조용히 제외합니다. setdiff()로 누락 열을 먼저 검사하고 두 경로 모두에서 중단하세요.
  • .jules/bolt.md#L19-L21intersect()를 O(1)로 설명한 문구는 부정확하니 수정하세요.
📍 Affects 1 file
  • R/aFIPC.R#L623-L625 (this comment)
  • R/aFIPC.R#L753-L755
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@R/aFIPC.R` around lines 623 - 625, R/aFIPC.R lines 623-625와 753-755의 각
intersect() 경로에서 setdiff()로 모델과 입력 데이터의 누락 열을 먼저 검증하고, 누락 열이 있으면 명시적으로 중단하도록
수정하세요. 열이 모두 존재할 때만 기존 열 교집합 처리를 계속 유지하세요. .jules/bolt.md lines 19-21의
intersect() 성능 설명도 실제 동작에 맞게 O(1)이라는 표현을 제거하거나 정확한 설명으로 변경하세요.


# ⚡ Bolt: Vectorized match() to avoid dynamic array growth overhead inside a for loop
idxNew <- match(newformCommonItemNames, newFormColNames)
Expand Down Expand Up @@ -749,8 +750,9 @@ autoFIPC <-
}
}

newFormColNames <- colnames(newformXDataK[colnames(newFormModel@Data$data)])
oldFormColNames <- colnames(oldformYDataK[colnames(oldFormModel@Data$data)])
# ⚡ Bolt: Replace O(N) data frame copying with O(1) string intersection
newFormColNames <- intersect(colnames(newFormModel@Data$data), colnames(newformXDataK))
oldFormColNames <- intersect(colnames(oldFormModel@Data$data), colnames(oldformYDataK))

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