diff --git a/README.md b/README.md new file mode 100644 index 0000000..d7aba6d --- /dev/null +++ b/README.md @@ -0,0 +1,98 @@ +## AHP decision analysis survey + +> [https://ahp.seung6lee.com/](https://ahp.seung6lee.com/) + +스타트업 지원 심사 상황에서 응답자의 직관적 판단과 AHP 가중치 모델의 판단을 비교하는 연구(2026년도 대구국제고 3학년 사회과제연구 논문 작성 활동)를 위해 제작한 웹 설문이다. +응답자는 15개 가상 팀을 직관으로 평가한 뒤 5개 평가 기준에 대한 쌍대비교를 수행하고, 두 결과의 불일치를 확인한다. + +### 구조 + +- 서버: Express 기반 단일 파일 [server.js](server.js) +- 클라이언트: Vanilla JS (Loaded by [index.html](public/index.html)) + - [cases.js](public/js/cases.js): 사례 데이터, 변인 정의, 셔플 + - [ahp.js](public/js/ahp.js): AHP 행렬 구성, 고유벡터 계산, 일관성 지표 + - [app.js](public/js/app.js): 상태 관리, 단계별 렌더링, 제출 +- 스타일: [src/styles/main.scss](src/styles/main.scss) -> [public/css/main.css](public/css/main.css) (`npm run build:css`) + +### 데이터 + +15개 사례는 [cases.js](public/js/cases.js)에 하드코딩되어 있으며 각각 5개 변인(안정성, 수익 가능성, 자금 효율성, 사업 계획 완성도, 사회적 가치)을 0-100 점수로 가진다. 사례는 세 유형으로 나뉜다. + +| type | 개수 | 설계 의도 | +| --- | --- | --- | +| baseline | 4 | 명확 선발, 명확 탈락, 중상, 중하 | +| spike | 5 | 한 변인만 극단값(4-6 또는 96-97), 나머지는 65-72 | +| conflict | 6 | 변인 간 방향이 충돌하거나 전 변인이 50점 경계 | + +### 단계별 동작 + +#### 1. 인트로 페이지 + +![](./screenshots/01.png) + +- 학년 선택 +- 시작 시간 기록 +- 사례 랜덤 섞기 + +#### 2. 상황별 판단 페이지 + +![](./screenshots/02.png) + +- 한번에 하나의 사례씩 제시 +- 5개 변인을 각각 막대로 표시 + - 35 미만: low + - 35 이상, 65 미만: mid + - 65 이상: high +- 응답자는 5점 척도(무조건 탈락 ~ 무조건 선발)중 선택 +- 15개 모두 마치면 3단계로 넘어감 + +#### 3. AHP 쌍대비교 페이지 + +![](./screenshots/03.png) + +- $_5C_2$개의 조합 한번에 하나씩 제시 +- 응답자는 9단계 척도(-4 ~ 4)로 중요도 선택 +- 모든 조합 끝나면 `runAHP()` 실행 + 1. `buildMatrix()`가 $5\times5$ 쌍대비교 행렬 $A$를 만듦. + 각 쌍의 저장값을 $v$라 하면 + + $$a_{ii}=1,\qquad a_{ij}=\begin{cases}v & (v>0)\\[2pt] \dfrac{1}{|v|} & (v<0)\end{cases},\qquad a_{ji}=\dfrac{1}{a_{ij}}$$ + + 2. `powerMethod()`가 거듭제곱법으로 주고유벡터 $w$를 구함. 초기값은 균등 분포이고, 매 반복마다 $Av$를 합으로 정규화함. + + $$v^{(0)}=\tfrac{1}{n}\mathbf{1},\qquad v^{(k+1)}=\frac{Av^{(k)}}{\sum_{i} (Av^{(k)})_i}$$ + + 종료 조건은 $\max_i \lvert v_i^{(k+1)}-v_i^{(k)}\rvert < 10^{-6}$ 이며, 최대 1000회 반복함. + + 3. `calcConsistency()`가 일관성 지표를 계산함. $n=5$, $RI=1.12$임. + + $$\lambda_{max}=\frac{1}{n}\sum_{i=1}^{n}\frac{(Aw)_i}{w_i},\qquad CI=\frac{\lambda_{max}-n}{n-1},\qquad CR=\frac{CI}{RI}$$ + +- `finalizeAHP()`로 사례별 비교표를 만듦 + - 모델 점수: `calcModelScore()`가 5개 변인 점수 $x_i$와 가중치 $w_i$의 가중합을 구함. $\sum w_i = 1$ 이므로 점수는 0-100 범위임. + + $$S=\sum_{i=1}^{5} w_i x_i$$ + + - 모델 판단: 50점 이상이면 선발, 미만이면 탈락 + - 직관 판단: `likertToJudgment()`가 4-5를 선발, 1-2를 탈락, 3을 중립으로 분류함. + - 일치 여부: 중립은 `null`로 두어 판정에서 제외하고, 나머지는 두 판단이 같으면 true, 다르면 false + +#### 4. 결과 페이지 + +![](./screenshots/04.png) + +- AHP 가중치를 백분율 막대로 보여줌. + - 전체 불일치가 7건을 넘거나 CR이 0.1을 넘으면 해당 통계 박스에 경고 스타일이 붙음. + +#### 5. 사후 설문 페이지 + +![](./screenshots/05.png) + +- 5점 리커트 4문항 + 주관식 1문항 제시함. + +#### 6. 감사합니다 페이지 + +![](./screenshots/06.png) + +- 제출 완료 페이지 +- 서버로 응답 데이터 전송함. diff --git a/screenshots/01.png b/screenshots/01.png new file mode 100644 index 0000000..ee89ee4 Binary files /dev/null and b/screenshots/01.png differ diff --git a/screenshots/02.png b/screenshots/02.png new file mode 100644 index 0000000..2f0a126 Binary files /dev/null and b/screenshots/02.png differ diff --git a/screenshots/03.png b/screenshots/03.png new file mode 100644 index 0000000..0731125 Binary files /dev/null and b/screenshots/03.png differ diff --git a/screenshots/04.png b/screenshots/04.png new file mode 100644 index 0000000..cf79a4e Binary files /dev/null and b/screenshots/04.png differ diff --git a/screenshots/05.png b/screenshots/05.png new file mode 100644 index 0000000..977f123 Binary files /dev/null and b/screenshots/05.png differ diff --git a/screenshots/06.png b/screenshots/06.png new file mode 100644 index 0000000..76fabbb Binary files /dev/null and b/screenshots/06.png differ