#4 - ABC Analysis
ABC ๋ถ์์ ์ฌ๊ณ ๊ด๋ฆฌ์ ์ฌ์ฉ๋๋ ์ฌ๊ณ ๋ถ๋ฅ ๊ธฐ๋ฒ์ ํ๋์ด๋ค.[1][2]
์ ํ์ ์ค์๋์ ๋ฐ๋ผ ๋ฑ๊ธ์ ๋งค๊ธฐ๊ณ ๊ทธ์ ๋ฐ๋ฅธ ํ๋งค ์ ๋ต์ ์ธ์ธ ๋ ํ์ฉ๋๋ค. ์ค์๋๋ ๋งค์ถ์ ๋ฐ๋ผ ๊ตฌ๋ถ๋๋ฉฐ 20%์ ์ ํ์ด 80%์ ๋งค์ถ์ ์ฐจ์งํ๋ค๊ณ ์๋ ค์ง ํ๋ ํ ๋ฒ์น๋ ABC ๋ถ์์ ๊ทผ๊ฑฐํ๊ณ ์๋ค.
ex. ๋์ ๋งค์ถ ๋น์ค 70% - A ๊ทธ๋ฃน, 70
90% B ๊ทธ๋ฃน, 90100% C ๊ทธ๋ฃน
ABC ๋ถ์ (Pareto Chart)
์ ํ๋ณ ๋งค์ถ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ABC ๋ถ์์ ์งํํด ๋ณด์.
๋ค์์ ํ๋งค ์ ํ์ ์นดํ ๊ณ ๋ฆฌ๊น์ง ํฌํจ๋ ๋งค์ถ ์์ธ ์ด๋ ฅ์ด๋ค.
๋งค์ถ ๋ฐ์ดํฐ ์์ฑ - ๊ตฌ๋งค ์์ธ ์ด๋ ฅ
DECLARE purchase_detail_log_raw ARRAY<STRUCT<
dt STRING,
order_id INT64,
user_id STRING,
item_id STRING,
price INT64,
category STRING,
sub_category STRING
>>
DEFAULT [
('2017-01-18', 48291, 'usr33395', 'lad533', 37300, 'ladys_fashion', 'bag'),
('2017-01-18', 48291, 'usr33395', 'lad329', 97300, 'ladys_fashion', 'jacket'),
('2017-01-18', 48291, 'usr33395', 'lad102', 114600, 'ladys_fashion', 'jacket'),
('2017-01-18', 48291, 'usr33395', 'lad886', 33300, 'ladys_fashion', 'bag'),
('2017-01-18', 48292, 'usr52832', 'dvd871', 32800, 'dvd' , 'documentary'),
('2017-01-18', 48292, 'usr52832', 'gam167', 26000, 'game' , 'accessories'),
('2017-01-18', 48292, 'usr52832', 'lad289', 57300, 'ladys_fashion', 'bag'),
('2017-01-18', 48293, 'usr28891', 'out977', 28600, 'outdoor' , 'camp'),
('2017-01-18', 48293, 'usr28891', 'boo256', 22500, 'book' , 'business'),
('2017-01-18', 48293, 'usr28891', 'lad125', 61500, 'ladys_fashion', 'jacket'),
('2017-01-18', 48294, 'usr33604', 'mem233', 116300, 'mens_fashion' , 'jacket'),
('2017-01-18', 48294, 'usr33604', 'cd477' , 25800, 'cd' , 'classic'),
('2017-01-18', 48294, 'usr33604', 'boo468', 31000, 'book' , 'business'),
('2017-01-18', 48294, 'usr33604', 'foo402', 48700, 'food' , 'meats'),
('2017-01-18', 48295, 'usr38013', 'foo134', 32000, 'food' , 'fish'),
('2017-01-18', 48295, 'usr38013', 'lad147', 96100, 'ladys_fashion', 'jacket')
];
CREATE OR REPLACE TABLE learning_club.purchase_detail_log AS
SELECT l.* FROM UNNEST(purchase_detail_log_raw) l;
ABC ๋ถ์ ๋งํธ
ABC ๋ถ์์ ํ์ํ ์งํ๋ค๋ก ๋งํธ๋ฅผ ๊ตฌ์ฑํ ์๋ ๋ค์๊ณผ ๊ฐ๋ค. ๋ง์ง๋ง ๋ฑ๊ธ ์ปฌ๋ผ์ ํธ์์ ์ถ๊ฐํ์๋ค.
โ ๋ฐ์ดํฐ ๋งํธ ํ์
1
ladys_fashion
497400
57.76
57.76
A
2
mens_fashion
116300
13.51
71.27
B
3
food
80700
9.37
80.64
B
4
book
53500
6.21
86.85
B
5
dvd
32800
3.81
90.66
C
6
outdoor
28600
3.32
93.98
C
7
game
26000
3.02
97.0
C
8
cd
25800
3.0
100.0
C
๊ฐ ์ปฌ๋ผ์ ์๋ฏธ์ ์ฐ์ถ ๋ฐฉ๋ฒ์ ๊ฐ๋ตํ ์ดํด๋ณด์.
category
- ๋ถ์์ ๊ธฐ์ค๋งค์ถ
-purchase_detail_log
์์ ์ ํ category๋ณ ์ง๊ณ ํจ์ ์ ์ฉ๊ตฌ์ฑ๋น
-๋งค์ถ
/์ด๋งค์ถ
* 100 (%)๋ถ์(์๋์ฐ) ํจ์๋ก
์ด๋งค์ถ
๊ณ์ฐ -SUM(..) OVER ()
์ค์นผ๋ผ ์๋ธ์ฟผ๋ฆฌ๋ฅผ ํตํด์
์ด๋งค์ถ
๊ณ์ฐ -(SELECT SUM(...) FROM ...)
๊ตฌ์ฑ๋น๋๊ณ
- cumulative sum ๋ถ์ํจ์ ์ ์ฉPARTITION BY
?ORDER BY
?Window Frame ?
โ category๋ณ ๋งค์ถ
์ด๋ ต์ง ์๊ฒ ๊ณ์ฐํ ์ ์๋ค. ์ฌ๊ธฐ์๋ ํ๋ฌ ๋งค์ถ์ ๊ธฐ์ค์ผ๋ก ์ ํ ์นดํ ๊ณ ๋ฆฌ๋ณ ๋งค์ถ์ก์ด ์ฐ์ถ๋๋ค.
SELECT category,
SUM(price),
-- ...
FROM learning_club.purchase_detail_log
WHERE dt BETWEEN '2017-01-01' AND '2017-01-31'
GROUP BY 1
;
โ category๋ณ ๊ตฌ์ฑ๋น
CREATE OR REPLACE TABLE learning_club.abc_mart AS
SELECT category,
SUM(price) AS amount,
ROUND(SUM(price) / (SUM(SUM(price)) OVER ()) * 100, 2) AS amount_rate,
ROUND(SUM(SUM(price)) OVER (ORDER BY SUM(price) DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) /
SUM(SUM(price)) OVER () * 100, 2) AS cumulative_rate
FROM learning_club.purchase_detail_log
WHERE dt BETWEEN '2017-01-01' AND '2017-01-31'
GROUP BY 1
ORDER BY 2 DESC;
๊ตฌ์ฑ๋น๋ฅผ ๊ตฌํ๊ธฐ ์ํด์๋ ์ฐ์ ์ ์ฒด ๋งค์ถ์ก์ด ํ์ํ๋ค. ์ ์ฒด ๋งค์ถ์ก์ ๋ถ์ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์๊ณผ ๊ฐ์ด ๊ณ์ฐํ๋ค.
SUM(SUM(price)) OVER ()
OVER
๊ตฌ๋ฌธ ์์ ํํฐ์
์ด๋ ์๋์ฐํ๋ ์์ ์ง์ ํ์ง ์์๋ค. ์ด๋ ์ ์ฒด ํ
์ด๋ธ์ ํ๋์ ํํฐ์
์ผ๋ก ๋ณด๊ฒ ๋ค๋ ์๊ธฐ์ด๋ฉฐ ์๋์ฐํ๋ ์๋ ํํฐ์
์ ์ฒ์๋ถํฐ ๋๊น์ง๋ฅผ ํ๋๋ก ๊ฐ์ฃผํ๊ฒ ๋ค๋ ์๋ฏธ์ด๋ค. ์ด๋ ๊ฒ ๋ง๋ค์ด์ง ์๋์ฐํ๋ ์์ SUM(SUM())
ํ๋ฉด ์ ์ฒด ๋งค์ถ์ก์ด ๊ตฌํด์ง๋ค.
์์ชฝ์ SUM()
์ GROUP BY
์ ์ํด์ ์ํ๋๋ ์ง๊ณํจ์๋ก ์ง์ ์ category๋ณ ๋งค์ถ
์์์ SUM(price)
์ ๋์ผํ๋ค. ๋ฐ๋ฉด, ๋ฐ๊นฅ์ชฝ์ SUM()
์ ์ง๊ณํจ์๊ฐ ์๋ ๋ถ์ํจ์๋ก์ ์นดํ
๊ณ ๋ฆฌ๋ณ ๋งค์ถ์ ๋ชจ๋ ํฉ์ฐํ๊ฒ ๋๋ค.
cumulative_rate
๋ ์กฐ๊ธ ๋ณต์กํ๋ค. ๋ถํดํด์ ์ดํด๋ณด์.
ROUND(..., 2)
๋ ์ค์๊ฐ์ ์์์ 2์๋ฆฌ๊น์ง๋ง ๋ณด์ฌ์ง๋๋ก ์ง์ ํ๋ค. ์๋ตํ๋ฉด ๋ค์์ด ๋จ๋๋ค.SUM(SUM(price)) OVER (ORDER BY SUM(price) DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) / SUM(SUM(price)) OVER () * 100
์ฌ๊ธฐ์ ๋ถ๋ชจ๋ ์ ์ฒด ๋งค์ถ์ก์ ๊ณ์ฐํ๊ณ ์๋ค.
SUM(SUM(price)) OVER ()
๋ถ์์ ์์นํ๊ณ ์๋ ๋ถ์ํจ์ ๊ตฌ๋ฌธ์์๋ ๋ ๊ฐ์ง๋ฅผ ์ดํด์ผ ํ๋ค.
์นดํ ๊ณ ๋ฆฌ๋ณ ๋งค์ถ์ ํด๋นํ๋
SUM(price)
์ ๋ด๋ฆผ์ฐจ์์ผ๋ก ํํฐ์ ์ ์ ๋ ฌ(ORDER BY
)์ํค๊ณ ์๋ค.ORDER BY SUM(price) DESC
์๋์ฐํ๋ ์์ ์์์ ๊ฐ์ฅ ๋งค์ถ์ด ๋์ ์ฒซ๋ฒ์งธ ํ์์๋ถํฐ ํ์ฌ ํ๊น์ง๋ก ์ค์ ํ๊ณ ์๋ค. ๊ฒฐ๊ตญ ๊ฐ์ฅ ๋์ ๋งค์ถ๋ถํฐ ํ์ฌ๊น์ง์ ๋งค์ถ์ ๋์ ํฉ์ฐํ๋ค.
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
์์ฝํ๋ฉด ๋งค์ถ์ก์ ๊ธฐ์ค์ผ๋ก ๋ด๋ฆผ์ฐจ์์ผ๋ก ์นดํ ๊ณ ๋ฆฌ๋ฅผ ์ ๋ ฌ์ํจ ํ์ ํด๋น ์นดํ ๊ณ ๋ฆฌ๊น์ง์ ๋์ ๋งค์ถ์ ์ ์ฒด๋งค์ถ๋ก ๋๋์ผ๋ก์จ ๊ตฌ์ฑ๋น๋ฅผ ๊ตฌํ ์ ์๊ฒ ๋๋ค.
์์ ์ฟผ๋ฆฌ๋ฅผ ์ํ์์ผ ๋งํธ๋ฅผ ๋ง๋ ํ์ Data Stuio๋ก ์๊ฐํ๋ฅผ ํ๊ฒ ๋๋ฉด ์๋์ ๊ฐ์ ๋ ํฌํธ๋ฅผ ๋ง๋ค ์ ์๋ค.

์ฐธ๊ณ ์๋ฃ
[์ฐธ๊ณ ] ๋ค์ฐจ์๋ถ์์ ์ํ ๋งํธ - Cube
SELECT category, sub_category, SUM(price) AS amount,
FROM learning_club.purchase_detail_log
GROUP BY ROLLUP (1, 2)
ORDER BY 1, 2 NULLS LAST;
Last updated