728x90
반응형
성적 예상 등수 계산기
- 시험을 보고 나서 평균, 표준편차, 총원, 내 점수를 입력하면 정규분포 식을 이용해 해당 점수가 몇등일지 예상 등수, 예상 학점을 알려 주는 프로그램
- 프로그램 데모 사진, 이런 식으로 표시된다.
- 링크 : https://gpa-calc.daybreaker42.com/
배운 점
- 확률과 통계 수업에서 pdf, cdf에 대해 배웠는데, 해당 프로젝트에서 정규분포를 사용할 때 이 식이 사용될 줄은 몰랐다.
- normalPDF, normalCDF, erf, normalInverseCDF 이렇게 4개의 함수가 대표적으로 사용되었으며, 해당 함수 각각의 기능은 다음과 같다.
- normalPDF : x, mean(평균), stddev(표준분포)를 이용해 현재 점수가 전체 구간 중 얼마정도를 차지하는지 알려준다.
- 확률적으론 pdf에서 x가 나올 확률이 얼마인지를 나타낸다.
- 해당 프로젝트에선 성적 정규분포에서 구간당 사람이 얼마나 있는지를 나타낼 때, 해당 구간의 밀도를 표현할 때 사용한다.
function normalPDF(x, mean, stddev) {
const exponent = -0.5 * Math.pow((x - mean) / stddev, 2);
return (1 / (stddev * Math.sqrt(2 * Math.PI))) * Math.exp(exponent);
}
- normalCDF : x, meal(평균), stddev(표준분포)를 이용해 특정 점수 이하의 비율을 계산한다.
- 확률적으론 특정 값(x) 이하가 나올 확률을 계산할 때 사용된다.
- 해당 프로젝트에선 해당 점수가 가지는 백분율 구간을 구할 때 사용되었다.
- ((1 - normalCDF()) * 100 = 상위 n%)
- 뒤에서 설명할 erf()를 이용해 이를 구할 수 있다.
function normalCDF(x, mean, stddev) { return 0.5 * (1 + erf((x - mean) / (stddev * Math.sqrt(2)))); }
- erf : 오류 함수, 정규분포의 누적 면적과 비슷한 역할 수행
- 해당 프로젝트에선 normalCDF를 구할 때 사용되었다.
function erf(x) {
const sign = x < 0 ? -1 : 1;
x = Math.abs(x);
const a1 = 0.254829592, a2 = -0.284496736, a3 = 1.421413741;
const a4 = -1.453152027, a5 = 1.061405429, p = 0.3275911;
const t = 1 / (1 + p * x);
const y = 1 - (((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t) * Math.exp(-x * x);
return sign * y;
}
- normalInverseCDF : 역정규분포 함수, 누적 확률값이 주어졌을 때 해당하는 x값을 알려준다.
해당 프로젝트에선 상위 n% 백분율이 주어졌을 때, 해당하는 점수값을 역산할 때 사용됐다.
function normalInverseCDF(p, mean = 0, stddev = 1) { if (p <= 0 || p >= 1) { console.error(`parameter out of bounds: ${p}`); // 오류 로깅 throw new Error("p must be between 0 and 1 (exclusive)"); } // Constants for approximation const a1 = -39.69683028665376, a2 = 220.9460984245205; const a3 = -275.9285104469687, a4 = 138.3577518672690; const a5 = -30.66479806614716, a6 = 2.506628277459239; const b1 = -54.47609879822406, b2 = 161.5858368580409; const b3 = -155.6989798598866, b4 = 66.80131188771972; const b5 = -13.28068155288572; const c1 = -0.007784894002430293, c2 = -0.3223964580411365; const c3 = -2.400758277161838, c4 = -2.549732539343734; const c5 = 4.374664141464968, c6 = 2.938163982698783; const d1 = 0.007784695709041462, d2 = 0.3224671290700398; const d3 = 2.445134137142996, d4 = 3.754408661907416; // Define break-points. const plow = 0.02425; const phigh = 1 - plow; let q, r; let result; if (p < plow) { q = Math.sqrt(-2 * Math.log(p)); result = (((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) / ((((d1 * q + d2) * q + d3) * q + d4) * q + 1); } else if (p <= phigh) { q = p - 0.5; r = q * q; result = (((((a1 * r + a2) * r + a3) * r + a4) * r + a5) * r + a6) * q / (((((b1 * r + b2) * r + b3) * r + b4) * r + b5) * r + 1); } else { q = Math.sqrt(-2 * Math.log(1 - p)); result = -(((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) / ((((d1 * q + d2) * q + d3) * q + d4) * q + 1); } return mean + stddev * result; }
- 그 외에도 step을 정해서 몇 개의 막대가 구간에서 표시되게 정하는 부분이나, chart.js를 이용해 그래프를 그리는 법 등을 배웠다.
아쉬웠던 점
- 정규 분포 함수로는 실제 시험 등수를 구할 수 없다. 다만 평균과 표준 편차를 이용해 실제 데이터가 통계적으로 정규분포 식에 가깝다는 점을 이용해 예상 등수를 구한다. 실제 등수와는 다를 수 있다는 한계가 있다.
- 정규 분포에선 실제 시험 점수의 상한선과 하한선을 넘어갈 수 있다는 문제가 있다. 정규분포이기 때문에 말 그대로 평균 점수에서 표준분포를 이용해 주변 점수의 범위와 그 확률을 구한다. 예를 들어 실제 시험 점수의 상한이 100점이지만, 평균 80에 표준분포 10으로 계산하면 일부 구간에서 100점을 넘어가버리는 문제가 있다.
추가 개발 계획
- 실제 시험 점수의 상한과 하한을 입력하면 해당 구간 내에서만 정규분포식을 적용하고 (넘어가는 부분 절삭), 그 안에서 예상 등수와 상위 n%인지를 다시 구하는 로직을 추가하고 싶다.
728x90
반응형
LIST
'개인 프로젝트' 카테고리의 다른 글
[WEB] 스도쿠 풀이 프로그램 #4 (2) | 2023.12.07 |
---|---|
[개인 프로젝트] Python으로 2048 게임 만들기 #2 (0) | 2022.02.28 |
[Python] 스도쿠 풀이 프로그램 #3 (0) | 2022.02.20 |
[Python] 스도쿠 풀이 프로그램 #2 (0) | 2022.01.13 |
[개인 프로젝트] Python으로 2048게임 만들기 # 1 (0) | 2021.12.15 |