데이터: 당뇨병 유무와 신체검사 데이터
<머신러닝>
1. 데이터 탐색
(1) 시각화 포함 탐색적 자료분석을 시행하시오(EDA)
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
df = pd.read_csv('data/diabetes_for_test.csv')
print(df)
diabetes = df.groupby('Outcome').mean()
print(diabetes)
fig, axes = plt.subplots(2, 4, figsize=(20, 14))
for i in range(4):
sns.barplot(x=diabetes.index, y=diabetes.iloc[:, i], ax=axes[0][i])
axes[0][i].set_title(diabetes.columns[i])
for i in range(4):
sns.barplot(x=diabetes.index, y=diabetes.iloc[:, i+4], ax=axes[1][i])
axes[1][i].set_title(diabetes.columns[i+4])
plt.suptitle('EDA')
plt.show()

→ 당뇨병이 있는 사람은 없는 사람보다 Pregnancies, Glucose, Insulin, BMI의 평균 수치가 높다
*변수들의 상관관계를 시각화 해보자

→ Outcome을 제외한 변수들 간의 상관성을 보았을 때, 0.9 이상의 상관관계를 가지는 변수는 없음
→ 따라서 모든 변수를 사용해서 모델링해도 될 것으로 판단
(2) 이상치를 식별하고 처리하시오.
print(df.describe())
X = df.drop(columns=['Outcome'])
df_v1 = pd.melt(X, var_name='col', value_name='value') # boxplot을 한 번에 그려주기 위해 데이터 재구조화
print(df_v1)
plt.figure(figsize=(15, 7))
sns.boxplot(x='col', y='value', data=df_v1)
plt.ylim([-50, 1100])
plt.xticks(range(8), X.columns)
plt.show()


*Age 중앙값 및 boxplot 확인
print('Age의 중앙값: ', df.Age.median())
outlier_index = df[df['Age'] > 400].index
df.loc[outlier_index, 'Age'] = df.Age.median()
sns.boxplot(df['Age'])
plt.show()

추가적으로 데이터를 살펴봤을 때, Glucose와 BloodPressure 컬럼에는 0이 존재하지 않아야 함 – 이상치로 판단
*이상치를 제외한 중앙값으로 이상치를 대체
outlier_index = df[df['Glucose'] == 0].index
df.loc[outlier_index, 'Glucose'] = df.Glucose.median()
outlier_index = df[df['BloodPressure'] == 0].index
df.loc[outlier_index, 'BloodPressure'] = df.BloodPressure.median()
print(df.describe())

(3) 앞선 두 단계에서 발견한 향후 분석 시에 고려해야 할 사항을 작성하시오.
min과 max 차이가 많이 나는 컬럼이 존재하므로, 선형 모델 사용 시 scale을 적용할 필요가 있어 보임
2. 클래스 불균형 처리
(1) 업 샘플링 과정을 설명하고 결과를 작성하시오.
- Random: 데이터를 단순 복사하는 방식이므로, 기존 데이터와 동일한 복제 데이터를 생성
→ 사용방법이 간단하지만, 소수 클래스에 과적합이 발생할 가능성이 있다는 단점이 있음 - SMOTE: 적은 데이터세트에 있는 개별 데이터들의 k-최근접 이웃을 찾아, 해당 데이터와 k개 이웃들의 차이를 일정한 값으로 만들어 기존 데이터와 약간의 차이를 지닌 새로운 데이터를 생성
→ 처리 속도가 느리지만, 과적합 문제를 예방할 수 있다는 장점이 있음
from imblearn.over_sampling import RandomOverSampler
print(df['Outcome'].value_counts())
X = df.drop(['Outcome'], axis=1)
y = df[['Outcome']]
ros = RandomOverSampler()
X_upsampling, y_upsampling = ros.fit_resample(X, y)
print('기존 타깃 분포')
print(df['Outcome'].value_counts()/len(df))
print('-'*10)
print('upsampling의 타깃 분포')
print(y_upsampling['Outcome'].value_counts()/len(y_upsampling))

(2) 언더 샘플링 과정을 설명하고 결과를 작성하시오.
- RandomUnderSampler: 랜덤하게 다수 클래스의 데이터를 선택하여 삭제
- Tomek link: 서로 다른 클래스에 가장 가까운 데이터들이 토맥 링크로 묶여서 토맥 링크 중 다수 클래스의 데이터를 제거하는 방식
from imblearn.under_sampling import RandomUnderSampler #TomekLinks
rus = RandomUnderSampler()
X_undersampling, y_undersampling = rus.fit_resample(X, y)
print('기존 타깃 분포')
print(df['Outcome'].value_counts()/len(df))
print('-'*10)
print('undersampling의 타깃 분포')
print(y_undersampling['Outcome'].value_counts()/len(y_undersampling))

(3) 둘 중 하나를 선택하고 선택한 이유를 서술하시오.
→ 데이터가 총 768개로 당뇨병 환자를 대표하기에는 너무 적은 데이터이기 때문에 Oversampling이 적합함
3. 모델링
(1) 최소 3개 이상의 알고리즘을 제시하고 정확도 측면의 모델 1개와 속도 측면의 모델 1개를 선정하시오.
→ 속도 측면에서 Logistic Regression, 정확도 측면에서 SVM, 기타로 XGBoost를 제시
(2) 모델을 비교하고 결과를 설명하시오.
from sklearn.linear_model import LogisticRegression
from xgboost import XGBClassifier
import sklearn.svm as svm
import time
from sklearn.model_selection import KFold
from sklearn.metrics import accuracy_score
from imblearn.over_sampling import SMOTE
smote = SMOTE(random_state=0)
log = LogisticRegression()
xgb = XGBClassifier(random_state=0)
svm_clf = svm.SVC(kernel='linear')
kfold = KFold()
def model_result(model):
pred_li = []
for train_index, test_index in kfold.split(X):
X_train, X_test = X.iloc[train_index, :], X.iloc[test_index, :]
y_train, y_test = y.iloc[train_index, :], y.iloc[test_index, :]
X_train_resample, y_train_resample = smote.fit_resample(X_train, y_train)
start = time.time()
model.fit(X_train_resample, y_train_resample)
end = time.time()
pred = model.predict(X_test)
pred_li.append(accuracy_score(pred, y_test['Outcome']))
## 마지막 데이터 학습 속도
print(f'{end - start:.5f} sec')
print(np.mean(pred_li))
model_result(log)
model_result(xgb)
model_result(svm_clf)

(3) 속도 개선을 위한 차원축소 방법을 설명하고 수행하시오. 그리고 예측 성능과 속도를 비교하고 결과를 작성하시오.
→ PCA 차원축소 수행
→ 데이터 스케일에 따라 각 주성분이 설명 가능한 분산량이 달라질 수 있기 때문에 데이터 스케일링을 꼭 수행
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split
smote = SMOTE(random_state=0)
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, test_size=0.3, random_state=2022)
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
pca = PCA(n_components=8)
X_train_pca = pca.fit(X_train_s)
print(pca.explained_variance_ratio_)
print(pca.explained_variance_ratio_[:5].sum())

→ 8개 독립변수 대신, 주성분 5개를 사용하면 전체 데이터에 81%를 설명할 수 있음
def model_result(model):
pred_li = []
for train_index, test_index in kfold.split(X):
X_train, X_test = X.iloc[train_index, :], X.iloc[test_index, :]
y_train, y_test = y.iloc[train_index, :], y.iloc[test_index, :]
X_train_resample, y_train_resample = smote.fit_resample(X_train, y_train)
scaler = StandardScaler()
X_train_res_s = scaler.fit_transform(X_train_resample)
X_test_s = scaler.transform(X_test)
pca = PCA(n_components=5)
X_train_pca = pca.fit_transform(X_train_res_s) # transform을 왜하지?
X_test_pca = pca.transform(X_test_s)
start = time.time()
model.fit(X_train_pca, y_train_resample)
end = time.time()
pred = model.predict(X_test_pca)
pred_li.append(accuracy_score(pred, y_test['Outcome']))
## 마지막 데이터 학습 속도
print(f'{end - start:.5f} sec')
print(np.mean(pred_li))
model_result(log)
model_result(xgb)
model_result(svm_clf)

→ 예측 성능은 다소 떨어졌지만, 속도는 엄청 빨라짐
<통계분석>
1. 회사 제품의 금속 재질 함유량의 분산이 1.3을 넘으면 불량이라고 판단한다. 회사에서는 품질경영팀으로부터 제조사별로 금속 함유량이 차이가 난다고 제보를 받았다. 해당 금속 함유량 데이터에 대한 검정을 수행하시오(유의확률: 0.05)
(1) 귀무가설과 대립가설을 작성하시오.
- 귀무가설(H0): 제품들의 금속 재질 함유량 분산은 1.3이다
- 대립가설(H1): 제품들의 금속 재질 함유량 분산은 1.3이 아니다.
(2) 가설을 양측 검정하시오.
import pandas as pd
import numpy as np
df = pd.read_csv('data/metalicity.csv')
print(df)
import scipy.stats as stats
print(stats.shapiro(df['metalicity']))
## 정규분포이며, 해당 데이터의 평균을 갖고 분산이 1.3인 150행의 데이터를 만드록 등분산 검정을 진행
test = np.random.normal(45.32, 1.3**0.5, 150) # 평균: 45.32, n: 150
print(test)
stats.levene(df['metalicity'], test)
→ 원래 카이제곱이 더 정확하지만, 라이브러리가 없으니 패스(?)


→ p-value 값이 0.05 보다 크므로, 정규성 가정 만족

→ p-value 값이 0.05 보다 작으므로, 귀무가설을 기각하여 분산은 1.3이 아니라고 할 수 있음
2. 제품 200개의 Lot별 불량 제품 수량 데이터에 대해 p 관리도*를 구하고 시각화하시오.
*p 관리도 구하는 방법
– n: lot 별 생산수량
– p: lot 별 불량수량 %
– CL(관리중심선): 전체 불량수량 / 전체 생산수량
– 관리 상하한선: p ± 3 √p(1-p) / n
(1) p 관리도에 따라 관리중심선(Center Line), 관리 상한선, 하한선을 구하시오.
import pandas as pd
import numpy as np
df = pd.read_csv('data/lot_quality.csv')
df = df.set_index('lot')
print(df)
df['p'] = df['불량수량'] / df['생산수량']
df['UCL'] = df['p'] + (3 * (df['p'] * (1 - df['p']) / df['생산수량'])**0.5)
df['LCL'] = df['p'] - (3 * (df['p'] * (1 - df['p']) / df['생산수량'])**0.5)
CL = df['불량수량'].sum() / df['생산수량'].sum()
print('관리중심선: ', CL)
print(df)

(2) 관리도를 시각화하시오.
import matplotlib.pyplot as plt
plt.figure(figsize=(14,10))
plt.plot(df['UCL'])
plt.plot(df['LCL'])
plt.plot(df['p'], marker='o')
plt.hlines(CL, 1, 200)
plt.legend(['UCL', 'p', 'CL', 'LCL'])
plt.show()

3. 제품 1, 2를 만드는 데 재료 a, b, c가 일부 사용되며, 제품 1과 2를 만들 때 12만원과 18만원을 벌 수 있다. 재료는 한정적으로 주어지는데, 이때 최대 수익을 낼 수 있을 때의 제품 1과 제품 2의 개수를 구하라.
재료 공급량 { a: 1300, b: 1000, c: 1200 }

# 제품2를 만들 수 있는 최대 수량은 32, 남은 원재료는 a: 20, b: 40, c: 240
x = 0
y = 32
max_profit = 32 * 18
material_a = 20
material_b = 40
material_c = 240
while((material_a > 0) or (material_b > 0) or (material_c > 0)):
y -= 1
material_a += 40
material_b += 30
material_c += 30
while((material_a > 20) or (material_b > 20) or (material_c > 20)):
x += 1
material_a -= 20
material_b -= 20
material_c -= 20
if(y*18 + x*12) > max_profit:
max_profit = (y*18 + x*12)
result_x = x
result_y = y
if y==0:
break
print('최대 수익: ', max_profit)
print('제품1 수량: ', result_x)
print('제품2 수량: ', result_y)

4. 상품 a와 b가 있을 때 다음과 같은 구매 패턴이 있다고 한다.
[‘a’,’a’,’b’,’b’,’a”a”a”a’,’b’,’b’,’b’,’b’,’b’,’a”a’,’b’,’b’,’a”b’,’b’]
(1) 구매 패턴으로 볼 때 두 상품이 연관이 있는지 가설을 세우고 검정하시오.
- 귀무가설(H0): 연속적인 관측값이 임의적이다. 즉, 연관성이 없다
- 대립가설(H1): 연속적인 관측값이 임의적이 아니다. 즉, 연관성이 있다
(2) 가설을 채택하시오.
import pandas as pd
from statsmodels.sandbox.stats.runs import runstest_1samp
data = ['a','a','b','b','a','a','a','a','b','b','b','b','b','a','a','b','b','a','b','b']
df = pd.DataFrame(data, columns=['product'])
df.loc[df['product']=='a', 'product'] = 1
df.loc[df['product']=='b', 'product'] = 0
print(df['product'])
print(runstest_1samp(df['product']))

→ p-value가 0.05보다 크므로, 귀무가설을 기각할 수 없다. 즉, 연관성이 없다고 할 수 있다
'데이터 분석 > ADP 자격증 공부' 카테고리의 다른 글
| [ADP 실기] NPV(Net Present Value, 순현재가치), IRR 구하기 (0) | 2026.04.06 |
|---|---|
| (파이썬 한권으로 끝내기) 모의고사 제3회 소스코드, 샘플 데이터 (0) | 2026.04.06 |
| [ADP 실기] (테스트 완료, 학습 데이터) 파이썬 비정형 텍스트마이닝 1편 – 영문 전처리, 워드클라우드(nltk) (0) | 2026.04.06 |
| (파이썬 한권으로 끝내기) 모의고사 제1회 소스코드, 샘플 데이터 (0) | 2026.04.06 |
| (파이썬 한권으로 끝내기) 시계열분석 (0) | 2026.04.06 |