[PYTHON] ์˜์‚ฌ๊ฒฐ์ •๋‚˜๋ฌด (Decision Tree)

2023. 2. 7. 15:30ใ†๐Ÿง‘๐Ÿป‍๐Ÿ’ป With Data/๋ฐ์ดํ„ฐ ๋ถ„์„

์˜์‚ฌ๊ฒฐ์ •๋‚˜๋ฌด๋Š” ๋ถ„๋ฅ˜์™€ ํšŒ๊ท€ ๋ฌธ์ œ์— ๋ชจ๋‘ ์ ์šฉ์ด ๊ฐ€๋Šฅํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ,

๊ฒฐ๊ณผ๋„์ถœ๊ณผ์ •๊ณผ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ํ•ด์„ํ•˜๊ธฐ์— ๋งค์šฐ ์œ ๋ฆฌํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.

ํŒŒ์ด์ฌ์˜ ์˜์‚ฌ๊ฒฐ์ •๋‚˜๋ฌด ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์‚ฌ์ดํ‚ท๋Ÿฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•œ๋‹ค.

 

๋ถ„์„์— ์“ฐ์ธ ๋ฐ์ดํ„ฐ๋Š” ์บ๊ธ€์—์„œ ๊ฐ€์ ธ์˜จ ibm hr๋ถ„์„(ํ‡ด์‚ฌ์—ฌ๋ถ€ ๋ถ„๋ฅ˜) ๋ฐ์ดํ„ฐ์ด๋‹ค.

(https://www.kaggle.com/datasets/pavansubhasht/ibm-hr-analytics-attrition-dataset?datasetId=1067&searchQuery=deci)

 

์ „์ฒ˜๋ฆฌ ๊ณผ์ •์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฒƒ์€ ์ž๋ฃŒํ˜• ํ™•์ธ, ๊ฒฐ์ธก์น˜ ํ™•์ธ, ๋ฐ์ดํ„ฐ ๋ถ„ํฌ ํ™•์ธ ๋“ฑ์ด ์žˆ๋‹ค.

์œ„ ๋ฐ์ดํ„ฐ๋Š” ํŠนํžˆ ์ž๋ฃŒํ˜•์— ์œ ์˜ํ•ด์•ผ ํ•œ๋‹ค.

๋ฐ์ดํ„ฐ ์„ค๋ช…์„ ์ฐธ์กฐํ•˜๋ฉด ์–ผํ• ์ˆ˜์น˜ํ˜•์œผ๋กœ ๋ณด์ด๋Š” ๋ณ€์ˆ˜๋“ค์ด ์‚ฌ์‹ค์€ ๋ช…๋ชฉํ˜• ๋ณ€์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๊ณ  ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

 

์ด์–ด์ง€๋Š” ์ฝ”๋“œ๋“ค์€ ์„ค๋ช…์„ ์œ„ํ•œ ๊ฒƒ์œผ๋กœ, ๋“ค์—ฌ์“ฐ๊ธฐ ๋“ฑ ๊ทธ๋Œ€๋กœ ๋ณต๋ถ™ ์‹œ์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์—ฌ์ง€๊ฐ€ ์žˆ๋‹ค.

์ด์— ์ง์ ‘ ๊ตฌํ˜„์„ ์œ„ํ•œ๋‹ค๋ฉด ๊นƒํ—ˆ๋ธŒ ๋งํฌ ์†์˜ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜๋Š” ํŽธ์ด ๋‚ซ๋‹ค.

 

์ด์— ์„ค๋ช…์„ ์ฐธ์กฐํ•˜๋ฉฐ ๋ช…๋ชฉํ˜•์œผ๋กœ ๋ณด๋Š” ๊ฒƒ์ด ์ ์ ˆํ•œ ๋ณ€์ˆ˜๋“ค์„ ์นดํ…Œ๊ณ ๋ฆฌ ํ˜•์œผ๋กœ ๋ณ€ํ™˜ํ•ด์ค€๋‹ค.

#์นดํ…Œ๊ณ ๋ฆฌํ˜•์œผ๋กœ ๋ณ€ํ™˜ # .astype
hr = hr.astype({'JobLevel': 'category', 'StockOptionLevel': 'category', 'Education':'category', 'MaritalStatus':'category','Attrition':'category', 'OverTime':'category', 'Gender':'category', 'BusinessTravel':'category', 'Department':'category','EducationField':'category','JobRole':'category' })
#๊ฐ™์€ ๊ฐ’์„ ๊ฐ€์ง€๋Š” ๋ณ€์ˆ˜ ์ œ๊ฑฐ #drop
hr.drop(['EmployeeCount','StandardHours','Over18','EmployeeNumber'],axis=1,inplace=True)

 

์˜์‚ฌ๊ฒฐ์ •๋‚˜๋ฌด ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋ช…๋ชฉํ˜• ๋ณ€์ˆ˜๋“ค์˜ ๋”๋ฏธํ™”(์ˆ˜์น˜ํ™”)๊ฐ€ ํ•„์š”ํ•˜์ง€๋งŒ,

๋‹จ์œ„๋ฅผ ๋งž์ถฐ์ฃผ๋Š” ํ‘œ์ค€ํ™” ์ž‘์—…์€ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค.

 

๋”๋ฏธํ™”๋Š” ์‚ฌ์ดํ‚ท๋Ÿฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜  OneHotEncoder๋‚˜ ํŒ๋‹ค์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ get_dummies๋ฅผ ์ด์šฉํ•œ๋‹ค.

 

#์ˆ˜์น˜/๋ช…๋ชฉํ˜• ๋ณ€์ˆ˜๋“ค ๋ถ„๋ฆฌ
num_fea = [column for column in hr_copy.columns if hr_copy[column].dtype != "category"]
cat_fea = [column for column  in hr_copy.columns if hr_copy[column].dtype ==  "category"]
#์›ํ•ซ์ธ์ฝ”๋”
#๋”๋ฏธํ™”

from sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder()
dummies = ohe.fit_transform(hr[cat_fea]).toarray()
df_dummies = pd.DataFrame(dummies, columns = ohe.get_feature_names(hr[cat_fea].columns)) hr_dum=pd.concat([hr_copy[num_fea].reset_index(), df_dummies], axis=1) hr_dum.drop('index',inplace=True,axis=1) hr_dum.columns

* ์ฐธ๊ณ ๋กœ ํŒ๋‹ค์Šค์˜ get_dummies ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜๋ฉด ์œ„๋ณด๋‹ค ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ๋”๋ฏธํ™”๋ฅผ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

#๋ ˆ์ด๋ธ” ๋ถ„ํฌ ํ™•์ธ
x = hr_dum y = hr.Attrition
y.value_counts()

์œ„ ์ฝ”๋“œ ๊ฒฐ๊ณผ, y, ์ฆ‰, ๋ ˆ์ด๋ธ”์˜ ํด๋ž˜์ˆ˜ ์ˆ˜๊ฐ€ 1233(ํ‡ด์‚ฌx) : 237(ํ‡ด์‚ฌo)๋กœ ๋ถˆ๊ท ํ˜•ํ•œ ์ƒํƒœ์ธ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด์—, ์ ์€ ํด๋ž˜์ˆ˜๋ฅผ ๋†’์—ฌ์ฃผ๋Š” ์˜ค๋ฒ„์ƒ˜ํ”Œ๋ง์ด๋‚˜ ๋งŽ์€ ํด๋ž˜์ˆ˜๋ฅผ ๋‚ฎ์ถฐ์ฃผ๋Š” ์–ธ๋”์ƒ˜ํ”Œ๋ง์„ ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

 

๊ทธ๋Ÿฐ๋ฐ, ์˜ค๋ฒ„์ƒ˜ํ”Œ๋ง์€ ์›๋ž˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋˜ ๊ณ ์œ ์˜ ํŠน์„ฑ ๋‚ด์ง€๋Š” ๋ถ„ํฌ๋ฅผ ๋”์šฑ ํฌ๊ฒŒ ์™œ๊ณก์‹œํ‚จ๋‹ค.

์ด์— ์ƒ๋Œ€์ ์œผ๋กœ ๊ทธ ์™œ๊ณก์ด ์ ์€ ์–ธ๋”์ƒ˜ํ”Œ๋ง์„ ์ง€ํ–ฅํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค. (๋‹จ, ๋ฐ์ดํ„ฐ ์ˆ˜๊ฐ€ ์ถฉ๋ถ„ํžˆ ํฌ๋‹ค๋ฉด)

 

#oss ์–ธ๋” ์ƒ˜ํ”Œ๋ง
from imblearn.under_sampling import *
X_samp, y_samp = OneSidedSelection().fit_resample(x,y)

์—ฌ๊ธฐ์„œ๋Š” ์—ฌ๋Ÿฌ ์–ธ๋”์ƒ˜ํ”Œ๋ง ๋ฐฉ๋ฒ• ์ค‘ oss๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋Š”๋ฐ,

์ด๋Š” ์ž‘์€ ํด๋ž˜์Šค์˜ ๋ฐ์ดํ„ฐ์—์„œ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ํฐ ํด๋ž˜์Šค์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฐพ์•„์„œ ์ง€์šฐ๋Š” "ํ† ๋งฅ๋žญํฌ"์™€

ํฐ ํด๋ž˜์Šค์—์„œ ์ž‘์€ ํด๋ž˜์™€ ์ง€๋‚˜์น˜๊ฒŒ ๊ฑฐ๋ฆฌ๊ฐ€ ๋จผ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ฑฐํ•˜๋Š” "cnn"๊ธฐ๋ฒ•์„ ํ•ฉ์นœ ๊ธฐ๋ฒ•์ด๋‹ค.

์ฆ‰, oss๋Š” ๋‘˜์˜ ์žฅ์ ์„ ์„ž์€ ๊ธฐ๋ฒ•์œผ๋กœ, ๋ฐ์ดํ„ฐ์˜ ์ค‘์‹ฌ๋ถ„ํฌ๋Š” ์œ ์ง€ํ•˜๋ฉด์„œ ๋ถ„๋ฅ˜์ง€์ ์— ๊ฐ€๊นŒ์šด ๊ฐ’๋“ค๊ณผ ์ง€๋‚˜์น˜๊ฒŒ ๋ฉ€๋ฆฌ ์žˆ๋Š” ์ด์ƒ์น˜๋“ค์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

 

# ๋ฐ์ดํ„ฐ ๋ถ„ํ• 
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(X_samp, y_samp, test_size=.2, shuffle = True, stratify = y_samp,random_state = 2)

ํ•™์Šต ๋ฐ์ดํ„ฐ์™€ ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ 8:2๋กœ ๋ถ„ํ• ํ•œ๋‹ค.

 

#๋ชจ๋ธ ๋งŒ๋“ค๊ธฐ, ํ•™์Šต
from sklearn.tree import DecisionTreeClassifier #์˜์‚ฌ๊ฒฐ์ •๋‚˜๋ฌด ์ฝ”๋“œ import 

max_depth = [5,6,7,8,9,10]

for i in max_depth:
dt_md = DecisionTreeClassifier(min_samples_leaf = 
20 , criterion = "entropy",max_depth = i,  class_weight= 'balanced',random_state = 2) # ์ตœ๋Œ€์„ฑ์žฅ๊นŠ์ด๋ฅผ ๋ฐ”๊ฟ”๊ฐ€๋ฉฐ ๋ชจ๋ธ๋ง

dt_md.fit(x_train,y_train) #ํ•™์Šต

print("max_depth:",i)

print('์ •ํ™•๋„:',dt_md.score(x_test,y_test))

์œ„ ์ฝ”๋“œ๋Š” ์˜์‚ฌ๊ฒฐ์ •๋‚˜๋ฌด ๋ชจ๋ธ์„ ๋งŒ๋“ค์–ด ํ•™์Šต์‹œํ‚ค๋Š” ์ฝ”๋“œ์ด๋‹ค.

DecisionTreeClassifier()๋กœ ๋ชจ๋ธ์„ ๋งŒ๋“ค๊ณ  .fit()์„ ํ†ตํ•ด ๋ชจ๋ธ์— ํ•™์Šต ๋ฐ์ดํ„ฐ๋ฅผ ์ ํ•ฉ์‹œํ‚จ๋‹ค.

์œ„์—์„œ ์ฃผ๋ชฉํ•ด์•ผํ•  ๊ฒƒ์€ DecisionTreeClassifier(min_samples_leaf = 20 , criterion = "entropy",max_depth = i, class_weight= 'balanced',random_state = 2) ์ธ๋ฐ,

 

min_samples_leaf =20 # ์žŽ ๋…ธ๋“œ ์ตœ์†Œ ๋ฐ์ดํ„ฐ ์ˆ˜ 20

criterion = "entropy" # ์—”ํŠธ๋กœํ”ผ๋กœ ๋ถ„๊ธฐ

max_depth = #์ตœ๋Œ€ ์„ฑ์žฅ์น˜

class_weight = 'balanced' # class ๊ฐ€์ค‘์น˜ ๋ถ€์—ฌ

random_state = 2 # ๋ชจ๋ธ ๊ณ ์ •

 

์ด์™€ ๊ฐ™์€ "ํ•˜์ดํผ ํŒŒ๋ผ๋ฏธํ„ฐ"๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋Š” ๊ณผ์ ํ•ฉ, ๊ณผ์†Œ์ ํ•ฉ ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š” ๊ฒƒ๊ณผ ๋”๋ถˆ์–ด ๋ชจ๋ธ์˜ ์„ฑ๋Šฅ์—๋„ ํฐ ์˜ํ–ฅ์„ ์ฃผ๋Š” ๊ฒƒ๋“ค์ด๋‹ค.

์œ„ ์ฝ”๋“œ์—์„œ๋Š” ๊ณผ์ ํ•ฉ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ์ตœ๋Œ€ ์„ฑ์žฅ์น˜๋ณ„ ๋ชจ๋ธ์˜ ์ •ํ™•๋„๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•˜์˜€๋‹ค.

 

์œ„ ๊ฒฐ๊ณผ๋Š” ๋‚˜๋ฌด๊ฐ€ ๊นŠ๊ฒŒ ์„ฑ์žฅํ•œ๋‹ค๊ณ  ํ•ด์„œ ์ •ํ™•๋„๊ฐ€ ํ–ฅ์ƒ๋˜์ง€ ์•Š๊ณ  ์˜คํžˆ๋ ค ๋–จ์–ด์ง€๊ณ  ์žˆ์Œ์„ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ๋‹ค.

์ด๋Š” ๊ณผ์ ํ•ฉ ๋ฌธ์ œ๋กœ, ํ•™์Šต ๋ฐ์ดํ„ฐ์— ์ง€๋‚˜์น˜๊ฒŒ ์ ํ•ฉ๋œ ๋ชจ๋ธ์ด๋ผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

๋ฐ˜๋Œ€๋กœ ๋‚˜๋ฌด๊ฐ€ ์–•๊ฒŒ ์„ฑ์žฅํ•œ๋‹ค๋ฉด ๊ทธ ๋ชจ๋ธ์˜ ์„ค๋ช…๋ ฅ์ด ๋–จ์–ด์ง€๋Š” ๋ฌธ์ œ์ ์ด ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ ์œ„์™€ ๊ฐ™์ด ์ •ํ™•๋„๋ฅผ ํ™•์ธํ•ด๊ฐ€๋ฉฐ max_depth์„ ํฌํ•จํ•œ ์—ฌ๋Ÿฌ ํ•˜์ดํผ ํŒŒ๋ผ๋ฏธํ„ฐ๋“ค์„ ์ ์ ˆํ•˜๊ฒŒ ๊ฒฐ์ •ํ•ด์•ผ ํ•œ๋‹ค.

 

#์‹œ๊ฐํ™”
from sklearn import tree
import graphviz
dot_data = tree.export_graphviz(dt_5,
# ์˜์‚ฌ๊ฒฐ์ •๋‚˜๋ฌด ๋ชจํ˜• ๋Œ€์ž… out_file = None, # file๋กœ ๋ณ€ํ™˜ํ•  ๊ฒƒ์ธ๊ฐ€ feature_names = x_test.columns, # feature ์ด๋ฆ„ class_names = ['NO','YES'], # target ์ด๋ฆ„ filled = True, # ๊ทธ๋ฆผ์— ์ƒ‰์ƒ์„ ๋„ฃ์„๊ฒƒ์ธ๊ฐ€ rounded = True, # ๋ฐ˜์˜ฌ๋ฆผ์„ ์ง„ํ–‰ํ•  ๊ฒƒ์ธ๊ฐ€ special_characters = True) # ํŠน์ˆ˜๋ฌธ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋‚˜
graph = graphviz.Source(dot_data)
graph

์œ„์™€ ๊ฐ™์ด graphviz๋ฅผ ํ†ตํ•ด ์˜์‚ฌ๊ฒฐ์ •๋‚˜๋ฌด๋ฅผ ์‹œ๊ฐํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.

์‹œ๊ฐํ™”๋Š” ๋ชจ๋ธ์˜ ์ดํ•ด์™€ ํ•ด์„์„ ๋•๋Š” ๋งค์šฐ ํšจ๊ณผ์ ์ธ ๋„๊ตฌ์ด๋‹ค.

์˜์‚ฌ๊ฒฐ์ •๋‚˜๋ฌด ์‹œ๊ฐํ™”

 

๋ชจ๋ธ์„ ๋งŒ๋“ค๊ณ  ํ•™์Šต์‹œํ‚จ ํ›„, ํ•ด๋‹น ๋ชจ๋ธ์— ๋Œ€ํ•œ ์„ฑ๋Šฅ์„ ํ‰๊ฐ€ํ•˜๋Š” ๊ฒƒ ๋˜ํ•œ ์ค‘์š”ํ•˜๋‹ค.

 

#๋ถ„๋ฅ˜_๋ ˆํฌํŠธ ์ถœ๋ ฅ
from sklearn.metrics import classification_report
print(classification_report(y_test, y_predict, target_names = ["F", "T"])) #(์‹ค์ œ ๊ฐ’, ์˜ˆ์ธก ๊ฐ’)์ˆœ์„œ

 

 

์œ„ ๊ฐ’๋“ค์€ ๋ถ„๋ฅ˜์„ฑ๋Šฅ์„ ํ‰๊ฐ€ํ•˜๋Š” ์ง€ํ‘œ๋“ค์ด๋‹ค. (F: ํ‡ด์‚ฌ x, T: ํ‡ด์‚ฌ o)

 

accuracy(์ •ํ™•๋„): ์ „์ฒด ๊ฐ’๋“ค ์ค‘ ์˜ˆ์ธก๊ฐ’์ด ๋งž์€ ๊ฒƒ์˜ ๋น„์œจ

precision(์ •๋ฐ€๋„): ์˜ˆ์ธก ๊ฐ’๋“ค ์ค‘์—์„œ ์‹ค์ œ ๊ฐ’๊ณผ ๋งž๋Š” ๊ฒƒ๋“ค์˜ ๋น„์œจ

recall(์žฌํ˜„์œจ): ์‹ค์ œ ๊ฐ’๋“ค ์ค‘์—์„œ ์˜ˆ์ธก ๊ฐ’์ด ๋งž๋Š” ๊ฒƒ๋“ค์˜ ๋น„์œจ

f1-score: Precision๊ณผ Recall์˜ ์กฐํ™”ํ‰๊ท  (2*(Recall * Precision) / (Recall + Precision)

 

* f1-score๋Š” ํด๋ž˜์Šค ๋ถˆ๊ท ํ˜•์ด ์‹ฌํ•  ๋•Œ ์ •๋ฐ€๋„์™€ ์žฌํ˜„์œจ์„ ๋ณด์ •ํ•œ ์„ฑ๋Šฅ์œผ๋กœ ์ด์šฉํ•œ๋‹ค.

- ์œ„ ์ผ€์ด์Šค๋Š” ์‹ค์ œ T(ํ‡ด์‚ฌ o)๊ฐ€ F(ํ‡ด์‚ฌ x)๋ณด๋‹ค ์ ๊ธฐ ๋•Œ๋ฌธ์— precison์ด ๋‚ฎ๊ฒŒ ๋‚˜์˜ฌ ์ˆ˜ ๋ฐ–์— ์—†๋‹ค.

   ๋•Œ๋ฌธ์— ์žฌํ˜„์œจ๊ณผ ์กฐํ™”ํ‰๊ท ์„ ๊ตฌํ•ด ์„ฑ๋Šฅ์„ ํ‰๊ฐ€ํ•œ๋‹ค.

 

support: ๊ฐ ๋ ˆ์ด๋ธ”(F: ํ‡ด์‚ฌ x, T: ํ‡ด์‚ฌ o)์˜ ์ƒ˜ํ”Œ ์ˆ˜

marco avg: ๋‹จ์ˆœ ํ‰๊ท 

weighted avg: ํด๋ž˜์Šค์˜ ๋ถˆ๊ท ํ˜•์„ ๊ฐ€์ค‘์น˜๋กœ ๋ฐ˜์˜ํ•˜์—ฌ ์‚ฐ์ถœํ•œ ํ‰๊ท 

 

 

*์ •ํ™•ํ•œ ์ฝ”๋“œ ์ฐธ์กฐ

https://github.com/Reign2121/Mining-project

 

GitHub - Reign2121/Mining-project: Data Mining and codes

Data Mining and codes. Contribute to Reign2121/Mining-project development by creating an account on GitHub.

github.com

https://seollane22.tistory.com/15

 

์˜์‚ฌ๊ฒฐ์ •๋‚˜๋ฌด(Decision Tree) [Supervised Learning]

AI, ๋ฐ์ดํ„ฐ ๋ถ„์„์˜ ๋ฐ‘๋ฐ”ํƒ•์ธ ๋จธ์‹ ๋Ÿฌ๋‹(๊ธฐ๊ณ„ํ•™์Šต)์—๋Š” ํฌ๊ฒŒ ์„ธ ๊ฐ€์ง€ ๊ฐˆ๋ž˜๊ฐ€ ์žˆ๋‹ค. - ์ง€๋„ํ•™์Šต (ํƒ€๊ฒŸ, ์ •๋‹ต์„ ํ•จ๊ป˜ ํ•™์Šต์‹œ์ผœ ํƒ€๊ฒŸ์„ ์˜ˆ์ธกํ•œ๋‹ค.) - ๋น„์ง€๋„ํ•™์Šต (ํƒ€๊ฒŸ, ์ •๋‹ต์—†์ด ํ•™์Šต์‹œ์ผœ ๋ฐ์ดํ„ฐ์˜ ํŠน

seollane22.tistory.com