# ๐Ÿ“Š ์žฌ๊ณ  ๋ถ„์„ ํ†ต๊ณ„ ์ตœ์ ํ™” ๋…ธํŠธ > ์žฌ๊ณ ๋Ÿ‰ vs ์‚ฌ์šฉ๋Ÿ‰ ๋น„๊ต ๊ทธ๋ž˜ํ”„์˜ ์ถ”์„ธ ๋ถ„์„ ๋กœ์ง์„ ์ตœ์ ํ™”ํ•˜๋Š” ๊ณผ์ • ๊ธฐ๋ก --- ## ๐Ÿ“Œ ์ปค๋ฐ‹ ํžˆ์Šคํ† ๋ฆฌ (๋กค๋ฐฑ ํฌ์ธํŠธ) | ์ปค๋ฐ‹ | Hash | ์„ค๋ช… | ํŠน์ง• | |------|------|------|------| | ์žฌ๊ณ  ๋ณ€ํ™”๋งŒ | `2ca35cd` | ์žฌ๊ณ  ๋ณ€ํ™” ์ถ”์ด ๊ทธ๋ž˜ํ”„ (๋‹จ์ผ Y์ถ•) | ๋ณด๋ผ์ƒ‰ ๋ผ์ธ๋งŒ, ๊น”๋”ํ•จ | | ์ด์ค‘ Y์ถ• v1 | `0b81999` | ์žฌ๊ณ  + ์‚ฌ์šฉ๋Ÿ‰ ๋น„๊ต (์ „๋ฐ˜๋ถ€/ํ›„๋ฐ˜๋ถ€ ํ•ฉ) | ํ”ผํฌ์— ๋ฏผ๊ฐํ•œ ๋ฌธ์ œ | | ์ด์ค‘ Y์ถ• v2 | *(ํ˜„์žฌ)* | ์žฌ๊ณ  + ์‚ฌ์šฉ๋Ÿ‰ ๋น„๊ต (์ตœ๊ทผ 3๊ฐœ์›” ํ‰๊ท ) | ํ”ผํฌ ์˜ํ–ฅ ์ค„์ž„ | ### ๋กค๋ฐฑ ๋ฐฉ๋ฒ• ```bash # ์žฌ๊ณ  ๋ณ€ํ™”๋งŒ ์žˆ๋˜ ๊น”๋”ํ•œ ๋ฒ„์ „์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ git checkout 2ca35cd -- backend/templates/admin_stock_analytics.html backend/app.py # ์ด์ค‘ Y์ถ• v1์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ git checkout 0b81999 -- backend/templates/admin_stock_analytics.html backend/app.py ``` --- ## ๐Ÿ”„ ์ถ”์„ธ ๋ถ„์„ ๋กœ์ง ๋ณ€์ฒœ์‚ฌ ### v1: ์ „๋ฐ˜๋ถ€ ํ•ฉ vs ํ›„๋ฐ˜๋ถ€ ํ•ฉ (โŒ ํ๊ธฐ) ```javascript // ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜์œผ๋กœ ๋‚˜๋ˆ ์„œ ์ดํ•ฉ ๋น„๊ต const half = Math.floor(items.length / 2); const firstHalfUsage = items.slice(0, half).reduce((sum, i) => sum + i.rx_usage, 0); const secondHalfUsage = items.slice(half).reduce((sum, i) => sum + i.rx_usage, 0); const usageChange = secondHalfUsage - firstHalfUsage; ``` **๋ฌธ์ œ์ :** - 19๊ฐœ์›” ๋ฐ์ดํ„ฐ โ†’ ์•ž 9๊ฐœ์›” vs ๋’ค 10๊ฐœ์›” - ํ›„๋ฐ˜๋ถ€์— ํ”ผํฌ(์˜ˆ: 2025-06)๊ฐ€ ํ•˜๋‚˜๋งŒ ์žˆ์–ด๋„ "์ฆ๊ฐ€ ์ถ”์„ธ"๋กœ ํŒ์ • - ์ตœ๊ทผ 3๊ฐœ์›”์ด ๊ณ„์† ๋–จ์–ด์ ธ๋„ ํ”ผํฌ ํ•˜๋‚˜ ๋•Œ๋ฌธ์— ์ž˜๋ชป๋œ ๊ฒฐ๊ณผ **์‹ค์ œ ์‚ฌ๋ก€ (ํ…Œ๋ผํŽœ์„ธ๋ฏธ์ •):** - ๋ˆˆ์œผ๋กœ ๋ณด๋ฉด: ๋ช…๋ฐฑํ•œ ๊ฐ์†Œ ์ถ”์„ธ (6,500 โ†’ 1,000) - ๋กœ์ง ๊ฒฐ๊ณผ: "+13,457 (+37%)" ์ฆ๊ฐ€ ์ถ”์„ธ โ† ํ‹€๋ฆผ! - ์›์ธ: 2025-06 ํ”ผํฌ(~7,000)๊ฐ€ ํ›„๋ฐ˜๋ถ€ ์ดํ•ฉ์„ ๋ปฅํŠ€๊ธฐ --- ### v2: ์ตœ๊ทผ 3๊ฐœ์›” ํ‰๊ท  vs ์ด์ „ 3๊ฐœ์›” ํ‰๊ท  (ํ˜„์žฌ) ```javascript // ์ตœ๊ทผ 3๊ฐœ ๊ธฐ๊ฐ„ vs ๊ทธ ์ด์ „ 3๊ฐœ ๊ธฐ๊ฐ„์˜ ํ‰๊ท  ๋น„๊ต const recentCount = Math.min(3, Math.floor(items.length / 2)); const recentItems = items.slice(-recentCount); const previousItems = items.slice(-recentCount * 2, -recentCount); const recentAvg = recentItems.reduce((sum, i) => sum + i.rx_usage, 0) / recentItems.length; const previousAvg = previousItems.reduce((sum, i) => sum + i.rx_usage, 0) / previousItems.length; const usageChange = Math.round(recentAvg - previousAvg); const usageChangePercent = previousAvg > 0 ? Math.round((usageChange / previousAvg) * 100) : 0; ``` **์žฅ์ :** - ์ค‘๊ฐ„์˜ ํ”ผํฌ์— ์˜ํ–ฅ ์•ˆ ๋ฐ›์Œ - "์ตœ๊ทผ" ๋ณ€ํ™”๋ฅผ ์ •ํ™•ํžˆ ๊ฐ์ง€ - ์ง๊ด€์ ์ธ ๊ฒฐ๊ณผ **๋‹จ์ :** - ์›”๋ณ„ ๋ถ„์„ ์‹œ 6๊ฐœ์›”๋งŒ ๋ด„ (๋” ๊ธด ์ถ”์„ธ ๋†“์น  ์ˆ˜ ์žˆ์Œ) - ๊ณ„์ ˆ์„ฑ ๋ฐ˜์˜ ์•ˆ ๋จ --- ## ๐ŸŽฏ ๊ณ ๋ ค ์ค‘์ธ ๋Œ€์•ˆ๋“ค ### ์˜ต์…˜ A: ์ „์›” ๋Œ€๋น„ (MoM) ```javascript const lastMonth = items[items.length - 1].rx_usage; const prevMonth = items[items.length - 2].rx_usage; const change = lastMonth - prevMonth; ``` - โœ… ๊ฐ€์žฅ ์ง๊ด€์  ("์ง€๋‚œ๋‹ฌ ๋Œ€๋น„ ์–ผ๋งˆ?") - โœ… ๋น„์ฆˆ๋‹ˆ์Šค์—์„œ ํ‘œ์ค€ - โŒ ๋‹จ๊ธฐ ๋ณ€๋™์— ๋ฏผ๊ฐ ### ์˜ต์…˜ B: ์ด๋™ํ‰๊ท  (Moving Average) ```javascript // 3๊ฐœ์›” ์ด๋™ํ‰๊ท  ๊ณ„์‚ฐ ํ›„ ๊ธฐ์šธ๊ธฐ ๋น„๊ต const ma3 = items.map((item, i, arr) => { if (i < 2) return null; return (arr[i].rx_usage + arr[i-1].rx_usage + arr[i-2].rx_usage) / 3; }).filter(v => v !== null); ``` - โœ… ๋…ธ์ด์ฆˆ ์ œ๊ฑฐ - โœ… ๊ทธ๋ž˜ํ”„์— ์ถ”์„ธ์„ ์œผ๋กœ ํ‘œ์‹œ ๊ฐ€๋Šฅ - โŒ ๊ตฌํ˜„ ๋ณต์žก ### ์˜ต์…˜ C: ์„ ํ˜• ํšŒ๊ท€ ๊ธฐ์šธ๊ธฐ ```javascript // ์ตœ์†Œ์ž์Šน๋ฒ•์œผ๋กœ ๊ธฐ์šธ๊ธฐ ๊ณ„์‚ฐ function linearRegression(data) { const n = data.length; const sumX = data.reduce((s, _, i) => s + i, 0); const sumY = data.reduce((s, v) => s + v, 0); const sumXY = data.reduce((s, v, i) => s + i * v, 0); const sumX2 = data.reduce((s, _, i) => s + i * i, 0); return (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX); } ``` - โœ… ํ†ต๊ณ„์ ์œผ๋กœ ์ •ํ™• - โœ… ์ „์ฒด ๋ฐ์ดํ„ฐ ํ™œ์šฉ - โŒ ํ•™์ˆ ์ , ์ง๊ด€์„ฑ ๋–จ์–ด์ง ### ์˜ต์…˜ D: ๋ณตํ•ฉ (์ถ”์ฒœ ์˜ˆ์ •) - **์ „์›” ๋Œ€๋น„**: ์นด๋“œ์— ์ˆซ์ž๋กœ ํ‘œ์‹œ - **3๊ฐœ์›” ์ด๋™ํ‰๊ท **: ๊ทธ๋ž˜ํ”„์— ์ถ”์„ธ์„ ์œผ๋กœ ํ‘œ์‹œ - **์ถ”์„ธ ํŒ์ •**: ์ด๋™ํ‰๊ท  ๊ธฐ์šธ๊ธฐ๋กœ --- ## ๐Ÿ“ TODO - [ ] ์ „์›” ๋Œ€๋น„ ์ˆ˜์น˜ ์ถ”๊ฐ€ - [ ] ์ด๋™ํ‰๊ท  ์ถ”์„ธ์„  ๊ทธ๋ž˜ํ”„์— ํ‘œ์‹œ - [ ] ๊ณ„์ ˆ์„ฑ ๊ณ ๋ ค (์ „๋…„ ๋™์›” ๋Œ€๋น„) - [ ] ์ผ๋ณ„ ๋ถ„์„ ์‹œ 7์ผ ์ด๋™ํ‰๊ท  ์ ์šฉ - [ ] ์ถ”์„ธ ํŒ์ • ๊ธฐ์ค€๊ฐ’ ํŠœ๋‹ (ํ˜„์žฌ ยฑ10%) --- ## ๐Ÿ“… ๋ณ€๊ฒฝ ์ด๋ ฅ | ๋‚ ์งœ | ๋ณ€๊ฒฝ ๋‚ด์šฉ | |------|-----------| | 2026-03-13 | ์ด์ค‘ Y์ถ• ๊ทธ๋ž˜ํ”„ ์ตœ์ดˆ ๊ตฌํ˜„ (์ „๋ฐ˜๋ถ€/ํ›„๋ฐ˜๋ถ€ ํ•ฉ) | | 2026-03-13 | ์ถ”์„ธ ๋กœ์ง ์ˆ˜์ • (์ตœ๊ทผ 3๊ฐœ์›” ํ‰๊ท ์œผ๋กœ ๋ณ€๊ฒฝ) | | 2026-03-13 | ์ตœ์ ํ™” ๋…ธํŠธ ๋ฌธ์„œ ์ƒ์„ฑ | --- ## ๐Ÿ–ผ๏ธ ์ฐธ๊ณ : ์ด์ „ ๋ฒ„์ „ ๊ทธ๋ž˜ํ”„ ### ์žฌ๊ณ  ๋ณ€ํ™”๋งŒ (๋‹จ์ผ Y์ถ•) - `2ca35cd` - ๋ณด๋ผ์ƒ‰ ๋ผ์ธ ํ•˜๋‚˜๋กœ ์žฌ๊ณ  ์ถ”์ด๋งŒ ํ‘œ์‹œ - ๊น”๋”ํ•˜๊ณ  ์‹ฌํ”Œํ•จ - ์‚ฌ์šฉ๋Ÿ‰ ์ •๋ณด ์—†์Œ ### ์ด์ค‘ Y์ถ• v1 - `0b81999` - ์™ผ์ชฝ Y์ถ•: ์žฌ๊ณ ๋Ÿ‰ (๋ณด๋ผ์ƒ‰ ๋ผ์ธ) - ์˜ค๋ฅธ์ชฝ Y์ถ•: ์ฒ˜๋ฐฉ ์‚ฌ์šฉ๋Ÿ‰ (ํŒŒ๋ž€์ƒ‰ ๋ฐ”) - ์ถ”์„ธ ๋ถ„์„: ์ „๋ฐ˜๋ถ€/ํ›„๋ฐ˜๋ถ€ ํ•ฉ ๋น„๊ต (๋ฌธ์ œ ์žˆ์Œ)