1. 오늘의 학습 목표
오늘은 통계와 머신러닝 개인과제를 마무리했다.
이번 과제는 AI4I 설비 데이터를 활용해서 설비 고장 여부를 통계적으로 분석하고, 머신러닝 모델로 예측하는 흐름으로 구성되어 있었다.
단순히 모델 하나를 학습시키는 문제가 아니라, 데이터 탐색부터 기초통계, T-test, 선형회귀, RandomForest, 로지스틱 회귀, 상관관계 분석, 박스플롯, 카이제곱 검정, Feature Engineering까지 지금까지 배운 내용을 한 번에 적용하는 과제였다.
오늘의 목표는 크게 두 가지였다.
첫 번째는 정상 설비와 고장 설비가 어떤 특성에서 차이를 보이는지 통계적으로 확인하는 것이다. 평균과 중앙값, T-test, 상관관계, 카이제곱 검정을 통해 변수별 차이와 연관성을 분석했다.
두 번째는 머신러닝 모델을 활용해 설비 고장 여부를 예측하는 것이다. 선형회귀로 공정 온도를 예측하고, RandomForest와 로지스틱 회귀로 고장 여부를 분류했다. 마지막으로 파생 변수를 추가해 모델 성능이 좋아지는지도 비교했다.
2. 오늘 학습한 내용
통계
데이터셋 기본 확인
먼저 AI4I 데이터를 불러오고 컬럼명을 정리했다.
사용한 데이터는 총 10,000개 행으로 구성되어 있었고, 결측치는 없었다. 주요 변수는 공기 온도, 공정 온도, 회전 속도, 토크, 공구 마모도, 제품 등급, 설비 고장 여부였다.
이번 분석에서 가장 중요한 타깃 변수는 machine_failure다.
machine_failure는 정상 설비와 고장 설비를 구분하는 변수이며, 값은 0과 1로 구성되어 있다.
데이터 분포를 확인해보니 정상 설비는 9,661개, 고장 설비는 339개였다. 비율로 보면 정상은 96.6%, 고장은 3.4%였다.
이 부분에서 바로 클래스 불균형이 보였다. 고장 데이터가 전체에서 매우 적기 때문에, 이후 머신러닝 모델을 평가할 때 정확도만 보면 위험할 수 있겠다는 생각이 들었다.
정확도가 높아도 대부분을 정상으로 예측하면 높은 점수가 나올 수 있기 때문이다.
df.info()
df.isnull().sum()
df.describe()
df['machine_failure'].value_counts()
기초 통계 분석
먼저 정상 설비와 고장 설비를 나누고, 각 변수의 평균과 중앙값을 비교했다.
온도 관련 변수는 air_temp, process_temp를 확인했다.
정상 설비의 air_temp 평균은 299.97, 중앙값은 300.00이었다. 고장 설비의 air_temp 평균은 300.89, 중앙값은 301.60이었다.
process_temp도 정상 설비 평균은 310.00, 중앙값은 310.00이었고, 고장 설비 평균은 310.29, 중앙값은 310.40이었다.
온도 변수는 고장 설비 쪽이 조금 더 높게 나타났다. 차이가 엄청 크게 보이지는 않았지만, 고장 설비에서 온도가 더 높은 방향으로 움직이는 경향은 확인할 수 있었다.
동력 관련 변수는 rotational_speed, torque를 확인했다.
정상 설비의 rotational_speed 평균은 1540.26, 중앙값은 1507.00이었다. 고장 설비의 평균은 1496.49, 중앙값은 1365.00이었다.
반대로 torque는 차이가 크게 나타났다. 정상 설비의 torque 평균은 39.63, 중앙값은 39.90이었고, 고장 설비의 평균은 50.17, 중앙값은 53.70이었다.
즉, 고장 설비는 회전 속도는 낮고 토크는 높은 경향을 보였다. 이 부분은 설비에 부하가 크게 걸리는 상황과 연결해서 생각할 수 있었다.
공구 마모 변수인 tool_wear도 차이가 있었다. 정상 설비의 평균은 106.69, 중앙값은 107.00이었고, 고장 설비의 평균은 143.78, 중앙값은 165.00이었다.
공구 마모가 누적될수록 고장 가능성이 커질 수 있다는 점에서 자연스럽게 이해됐다.
feature_groups = {
'온도': ['air_temp', 'process_temp'],
'동력': ['rotational_speed', 'torque'],
'공구 마모': ['tool_wear']
}
for group_name, features in feature_groups.items():
result = df.groupby('machine_failure')[features].agg(['mean', 'median']).round(2)
display(result)
T-test 분석
기초 통계에서 보인 평균 차이가 통계적으로 유의한지 확인하기 위해 독립표본 T-test를 수행했다.
정상 설비와 고장 설비를 나누고, 각 변수별로 평균 차이를 검정했다. 분산이 다를 수 있으므로 Welch 방식으로 진행했다.
normal_df = df[df['machine_failure'] == 0]
failure_df = df[df['machine_failure'] == 1]
t_score, p_value = stats.ttest_ind(
normal_df[feature],
failure_df[feature],
equal_var=False,
nan_policy='omit'
)
결과를 보면 모든 변수에서 p-value가 0.05보다 작게 나타났다.
air_temp는 t-score가 -7.9817, p-value는 0.000000이었다.
process_temp는 t-score가 -3.8984, p-value는 0.000115였다.
rotational_speed는 t-score가 2.0868, p-value는 0.037647이었다.
torque는 t-score가 -11.7808, p-value는 0.000000이었다.
tool_wear는 t-score가 -9.2643, p-value는 0.000000이었다.
모든 변수에서 귀무가설을 기각할 수 있었다. 즉, 정상 설비와 고장 설비 사이에는 평균 차이가 있다고 볼 수 있다.
절댓값 기준 t-score가 가장 컸던 변수는 torque였다. 그다음은 tool_wear, air_temp, process_temp, rotational_speed 순서였다.
이 결과를 보면 고장 여부를 설명하는 데 있어 토크와 공구 마모가 특히 중요해 보였다.
상관관계 분석
다음으로 연속형 변수들과 machine_failure 사이의 피어슨 상관계수를 확인했다.
corr_features = [
'air_temp',
'process_temp',
'rotational_speed',
'torque',
'tool_wear',
'machine_failure'
]
corr = df[corr_features].corr().round(2)
sns.heatmap(corr, annot=True, fmt='.2f', cmap='coolwarm', center=0)
machine_failure와의 상관계수는 다음과 같았다.
torque가 0.19로 가장 높았다.
tool_wear는 0.11이었다.
air_temp는 0.08이었다.
rotational_speed는 -0.04였다.
process_temp는 0.04였다.
전체적으로 상관계수가 아주 높지는 않았다. 하지만 그중에서는 torque와 tool_wear가 상대적으로 고장 여부와 더 관련이 있어 보였다.
T-test 결과와 비교해보면, T-test에서도 torque와 tool_wear가 중요한 변수로 나타났고, 상관관계에서도 두 변수가 상위권에 있었다.
다만 T-test와 상관관계는 보는 관점이 다르다. T-test는 정상 그룹과 고장 그룹의 평균 차이를 보는 것이고, 상관관계는 변수와 고장 여부 사이의 선형 관계를 보는 것이다. 그래서 두 결과를 같이 봐야 조금 더 안정적으로 해석할 수 있다.
박스플롯 시각화
기초 통계와 T-test 결과를 시각적으로 확인하기 위해 박스플롯을 그렸다.
machine_failure를 x축으로 두고, 각 연속형 변수의 분포를 비교했다.
box_features = ['air_temp', 'process_temp', 'rotational_speed', 'torque', 'tool_wear']
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
axes = axes.flatten()
for i, feature in enumerate(box_features):
sns.boxplot(
x='machine_failure',
y=feature,
hue='machine_failure',
data=df,
ax=axes[i],
palette=['steelblue', 'tomato'],
legend=False
)
박스플롯을 통해 정상 설비와 고장 설비의 중앙값과 분포 차이를 확인할 수 있었다.
특히 torque는 고장 설비 쪽에서 중앙값이 더 높게 나타났다. tool_wear도 고장 설비 쪽에서 더 높은 값으로 분포하는 모습이 보였다.
반면 일부 변수는 분포가 많이 겹쳐 보였다. 이 경우 해당 변수만으로 고장 여부를 구분하기는 어려울 수 있다.
그래서 시각화는 통계 결과를 보조하는 역할을 했다. 숫자로만 보면 감이 잘 안 오는 차이를 그래프로 보면 조금 더 직관적으로 확인할 수 있었다.
카이제곱 검정
범주형 변수인 Type과 machine_failure 사이의 연관성을 확인하기 위해 카이제곱 검정을 수행했다.
먼저 교차표를 만들었다.
contingency_table = pd.crosstab(df['Type'], df['machine_failure'])
교차표를 보면 H 등급은 정상 982개, 고장 21개였다. L 등급은 정상 5765개, 고장 235개였고, M 등급은 정상 2914개, 고장 83개였다.
이후 카이제곱 검정을 수행했다.
chi2, p, dof, expected = chi2_contingency(contingency_table)
결과는 chi2-score가 13.7517, p-value가 0.001032, 자유도는 2였다.
p-value가 0.05보다 작으므로 귀무가설을 기각했다. 즉, 제품 등급과 고장 여부는 서로 독립이라고 보기 어렵고, 통계적으로 연관성이 있다고 판단할 수 있다.
등급별 고장률도 계산했다.
H 등급의 고장률은 2.09%였다.
L 등급의 고장률은 3.92%였다.
M 등급의 고장률은 2.77%였다.
이 결과에서는 L 등급의 고장률이 가장 높게 나타났다. 다만 제품 등급 하나만으로 고장을 단정하기보다는, 온도, 토크, 공구 마모 같은 다른 변수들과 함께 보는 것이 더 적절해 보였다.
머신러닝
선형회귀 모델
머신러닝 첫 번째 문제는 air_temp를 이용해 process_temp를 예측하는 선형회귀였다.
독립변수는 air_temp, 종속변수는 process_temp로 설정했다.
from sklearn.linear_model import LinearRegression
X = df[['air_temp']]
y = df['process_temp']
linear_model = LinearRegression()
linear_model.fit(X, y)
모델 학습 결과 결정계수 R²는 0.7676이었다.
회귀식은 다음과 같았다.
process_temp = 0.6499 × air_temp + 115.0410
air_temp가 305K일 때 예측된 process_temp 값은 313.25K였다.
R²가 0.7676이라는 것은 공기 온도가 공정 온도의 변동을 어느 정도 잘 설명한다고 볼 수 있다. 두 변수는 실제로 상관계수도 0.88로 높았기 때문에 선형 관계가 꽤 강하게 나타났다.
RandomForest 모델
다음으로 동력 및 마모 관련 특성과 제품 등급을 사용해 설비 고장 여부를 예측하는 RandomForest 모델을 만들었다.
사용한 변수는 다음과 같다.
- rotational_speed
- torque
- tool_wear
- Type_encoded
Type은 범주형 변수이기 때문에 LabelEncoder로 변환했다.
le = LabelEncoder()
rf_df['Type_encoded'] = le.fit_transform(rf_df['Type'])
인코딩 결과는 H가 0, L이 1, M이 2로 변환되었다.
그다음 train/test 데이터를 7:3으로 분리하고 RandomForestClassifier를 학습했다.
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
test_size=0.3,
random_state=42
)
rf_model = RandomForestClassifier(random_state=42)
rf_model.fit(X_train, y_train)
모델 정확도는 98.17%로 높게 나왔다.
하지만 분류 리포트를 보면 정상 데이터에 비해 고장 데이터의 recall은 0.47로 낮았다. 전체 정확도는 높지만, 고장 데이터를 모두 잘 잡아낸다고 보기는 어려웠다.
이 부분은 데이터 불균형 때문일 가능성이 있다. 전체 데이터 중 고장 데이터가 3.4%밖에 되지 않기 때문에, 정확도만 보면 모델 성능을 과대평가할 수 있다.
Feature Importance는 다음과 같았다.
torque가 0.41로 가장 높았다.
rotational_speed는 0.29였다.
tool_wear는 0.26이었다.
Type_encoded는 0.05였다.
즉, RandomForest 모델에서는 토크가 가장 중요한 변수로 나타났다. 그다음은 회전 속도와 공구 마모였다. 제품 등급은 상대적으로 중요도가 낮았다.
로지스틱 회귀 모델
다음으로 온도 및 동력 관련 특성을 사용해 설비 고장 여부를 예측하는 로지스틱 회귀 모델을 만들었다.
사용한 변수는 다음과 같다.
- air_temp
- process_temp
- torque
타깃 변수는 machine_failure다.
log_features = ['air_temp', 'process_temp', 'torque']
X = df[log_features]
y = df['machine_failure']
log_model = LogisticRegression(max_iter=1000)
log_model.fit(X_train, y_train)
모델 정확도는 97.07%였다.
로지스틱 회귀 계수는 air_temp가 0.75, torque가 0.11, process_temp가 -0.75로 나타났다.
계수가 양수인 변수는 값이 증가할수록 고장 확률을 높이는 방향으로 작용한다. 반대로 음수인 변수는 값이 증가할수록 고장 확률을 낮추는 방향으로 작용한다.
다만 로지스틱 회귀 계수는 변수 스케일의 영향을 받을 수 있으므로, 단순히 절댓값만 보고 영향력을 확정하기는 어렵다.
새로운 설비 데이터도 예측했다.
조건은 다음과 같았다.
- air_temp : 302K
- process_temp : 310K
- torque : 72Nm
new_sample = pd.DataFrame(
[[302, 310, 72]],
columns=log_features
)
log_model.predict_proba(new_sample)
예측 결과 정상 확률은 28.84%, 고장 확률은 71.16%였다.
토크가 72Nm로 높은 편이기 때문에 고장 확률이 높게 나온 것으로 해석할 수 있었다.
Feature Engineering
마지막으로 파생 변수를 만들어 모델 성능이 좋아지는지 확인했다.
생성한 파생 변수는 power와 temp_diff다.
power는 회전 속도와 토크를 이용해 계산한 전력 변수다.
fe_df['power'] = 2 * np.pi * fe_df['rotational_speed'] * fe_df['torque'] / 60
temp_diff는 공정 온도와 공기 온도의 차이다.
fe_df['temp_diff'] = fe_df['process_temp'] - fe_df['air_temp']
파생 변수의 기술통계를 확인해보니 power의 평균은 6279.74, 표준편차는 1067.42였다. 최솟값은 1148.44, 최댓값은 10469.92였다.
temp_diff의 평균은 10.00, 표준편차는 1.00이었다. 최솟값은 7.60, 최댓값은 12.10이었다.
이후 rotational_speed, torque, tool_wear, power, temp_diff를 사용해 RandomForest 모델을 다시 학습했다.
모델 정확도는 98.87%였다.
도전 1의 RandomForest 모델 정확도는 98.17%였기 때문에, 파생 변수를 추가한 모델이 0.70%p 더 높은 정확도를 보였다.
Feature Importance는 다음과 같았다.
power가 0.26으로 가장 높았다.
temp_diff는 0.22였다.
rotational_speed는 0.20이었다.
torque는 0.18이었다.
tool_wear는 0.15였다.
이 결과를 보면 파생 변수인 power와 temp_diff가 모델에서 꽤 중요하게 사용되었다. 기존 변수의 조합으로 만든 변수가 고장 예측에 도움이 되었을 가능성이 있다.
특히 power는 회전 속도와 토크를 결합한 변수라 설비가 실제로 받는 동력 상태를 더 직접적으로 표현한다고 볼 수 있다.
3. 나의 간단 소감
오늘은 개인과제를 실제로 마무리하면서 지금까지 배운 통계와 머신러닝 내용을 한 번에 연결해볼 수 있었다.
처음에는 문제 수가 많아서 조금 복잡하게 느껴졌다. 기초통계, T-test, 선형회귀, RandomForest, 로지스틱 회귀, 상관관계, 박스플롯, 카이제곱 검정, Feature Engineering까지 한 과제 안에 들어가 있어서 어디서부터 정리해야 할지 살짝 막막했다.
그런데 하나씩 풀다 보니 흐름이 보였다. 먼저 정상 설비와 고장 설비가 어떤 특성에서 차이를 보이는지 통계로 확인하고, 그다음 머신러닝 모델로 고장 여부를 예측하는 구조였다.
통계 파트에서는 torque와 tool_wear가 계속 눈에 띄었다. 기초통계에서도 차이가 보였고, T-test에서도 유의하게 나왔으며, 상관관계에서도 상대적으로 높은 편이었다. 특히 torque는 RandomForest에서도 가장 중요한 변수로 나타나서 설비 고장과 꽤 관련이 있어 보였다.
머신러닝 파트에서는 정확도만 보면 안 된다는 점이 가장 크게 남았다. RandomForest 모델의 정확도는 98.17%로 높았지만, 고장 데이터의 recall은 0.47이었다. 전체 데이터에서 정상 설비가 대부분이기 때문에 정확도만 보고 모델이 좋다고 판단하면 위험할 수 있다. 고장을 잡아내는 것이 목표라면 recall이나 F1-score를 같이 봐야 한다는 점이 중요했다.
로지스틱 회귀에서는 새로운 설비의 고장 확률을 직접 계산해본 것이 기억에 남았다. air_temp=302, process_temp=310, torque=72인 설비의 고장 확률이 71.16%로 나왔는데, 숫자로 확률이 나오니까 모델 결과를 해석하는 느낌이 더 분명했다.
Feature Engineering도 재미있었다. 단순히 기존 변수를 그대로 넣는 것이 아니라 power, temp_diff처럼 설비 상태를 더 잘 설명할 수 있는 파생 변수를 만들어봤다. 그 결과 정확도가 98.17%에서 98.87%로 올라갔고, 변수 중요도에서도 파생 변수가 상위에 나왔다. 이걸 보면서 모델 성능은 알고리즘만 바꾼다고 좋아지는 게 아니라, 어떤 변수를 만들어 넣느냐도 중요하다는 걸 느꼈다.
오늘 과제는 단순히 코드를 실행하는 것보다 결과를 해석하는 과정이 더 중요했다. p-value가 작다는 것, 상관계수가 높다는 것, Feature Importance가 크다는 것, 정확도와 recall이 다르게 나온다는 것 모두 그냥 숫자가 아니라 분석 결론으로 이어져야 했다.
이번 과제를 통해 통계와 머신러닝이 따로 떨어져 있는 내용이 아니라는 걸 다시 느꼈다. 통계는 데이터의 차이를 설명하고, 머신러닝은 그 차이를 활용해 예측하는 과정이었다. 그리고 그 사이에서 시각화와 해석이 결과를 이해할 수 있게 만들어준다.
아직 모든 개념이 완벽하게 편한 것은 아니지만, 그래도 이번 과제를 끝내면서 전체 분석 흐름은 확실히 조금 더 잡힌 것 같다. 데이터를 보고, 비교하고, 검정하고, 모델을 만들고, 성능을 해석하는 흐름을 한 번 직접 연결해본 하루였다.
'내일배움캠프' 카테고리의 다른 글
| [본캠프] 데이터기반 QA/QC 부트캠프 38일차 (0) | 2026.07.07 |
|---|---|
| [본캠프] 데이터기반 QA/QC 부트캠프 37일차 (0) | 2026.07.02 |
| [본캠프] 데이터기반 QA/QC 부트캠프 35일차 (0) | 2026.06.30 |
| [본캠프] 데이터기반 QA/QC 부트캠프 34일차 (1) | 2026.06.29 |
| [본캠프] 데이터기반 QA/QC 부트캠프 33일차 (0) | 2026.06.26 |