1. 오늘의 학습 목표
오늘은 머신러닝 개인과제 리뷰 자료를 보면서, 과제에서 사용했던 통계와 머신러닝 흐름을 다시 정리했다.
이번 과제의 핵심은 설비 데이터를 보고 고장과 관련 있는 변수들을 찾고, 그 변수들을 활용해 고장 여부를 예측하는 것이었다.
처음 과제를 풀 때는 코드 하나하나에 집중했다면, 오늘은 전체 구조를 다시 보는 데 초점을 두었다. 머신러닝을 처음 공부할 때 중요한 건 코드를 무작정 외우는 것이 아니라, 지금 내가 왜 이 코드를 쓰는지 이해하는 것이라는 점을 다시 확인했다.
오늘은 크게 네 가지를 정리했다.
첫 번째는 데이터에서 예측 대상과 입력 변수를 구분하는 것이다.
두 번째는 정상 설비와 고장 설비를 비교하고, 통계적으로 차이가 있는지 확인하는 흐름이다.
세 번째는 회귀와 분류 모델을 구분하고, 머신러닝 모델을 학습·예측·평가하는 기본 구조다.
네 번째는 파생변수와 변수 중요도를 통해 모델 결과를 해석하는 방법이다.
2. 오늘 학습한 내용
머신러닝
이번 과제의 전체 구조
이번 과제는 AI4I 설비 데이터를 사용했다.
데이터에는 공기 온도, 공정 온도, 회전 속도, 토크, 공구 마모도, 제품 등급, 설비 고장 여부가 들어 있었다.
가장 중요한 컬럼은 machine_failure다.
machine_failure는 설비가 정상인지 고장인지 나타내는 변수다.
- 0: 정상
- 1: 고장
즉, 이번 과제는 결국 다음 질문으로 이어진다.
어떤 변수들이 설비 고장과 관련이 있을까?
그리고 한 단계 더 나아가면 이런 질문이 된다.
이 변수들을 사용해서 설비 고장을 예측할 수 있을까?
전체 흐름은 다음과 같이 정리할 수 있다.
데이터 확인 → 정상/고장 비교 → 통계 검정 → 관계 확인 → 시각화 → 머신러닝 예측 → 파생변수 생성 → 성능 비교
이 흐름을 다시 보니, 과제가 단순히 모델 하나를 돌리는 문제가 아니라 데이터 분석 전체 과정을 한 번에 연결하는 문제였다는 게 보였다.
X와 y 구분하기
머신러닝에서 가장 먼저 잡아야 하는 것은 X와 y다.
X는 입력값이고, y는 예측하고 싶은 정답값이다.
이번 과제에서는 machine_failure가 고장 여부를 나타내는 정답값이므로 y가 된다.
y = df['machine_failure']
그리고 고장 여부를 예측하는 데 사용할 변수들이 X가 된다.
X = df[['air_temp', 'process_temp', 'rotational_speed', 'torque', 'tool_wear']]
처음에는 X와 y를 나누는 것이 단순한 코드처럼 보였는데, 사실 이 단계가 문제 정의에 가깝다.
내가 무엇을 예측하고 싶은지 정해야 y가 정해지고, 무엇을 보고 예측할지 정해야 X가 정해진다.
그래서 머신러닝 과제를 받으면 먼저 이렇게 생각해야 한다.
내가 맞히고 싶은 값이 무엇인가?
그다음에 이렇게 이어진다.
그 값을 예측하기 위해 어떤 변수를 사용할 것인가?
이 구조를 잡아야 이후 모델 학습도 자연스럽게 이어진다.
데이터 탐색은 기본 건강검진
모델을 만들기 전에 데이터 구조를 확인해야 한다.
대표적으로 info(), isnull().sum(), describe(), value_counts()를 사용한다.
df.info()
df.isnull().sum()
df.describe()
df['machine_failure'].value_counts()
info()는 데이터의 행 개수, 컬럼 개수, 자료형, 결측치 여부를 확인할 때 사용한다.
isnull().sum()은 결측치가 몇 개 있는지 확인한다.
describe()는 수치형 변수의 평균, 표준편차, 최솟값, 최댓값, 사분위수 등을 보여준다.
value_counts()는 특정 컬럼의 값이 각각 몇 개 있는지 확인할 수 있다.
이번 과제에서는 machine_failure의 분포를 확인하는 것이 중요했다. 정상 데이터가 훨씬 많고 고장 데이터가 적었기 때문이다.
이런 상황을 클래스 불균형이라고 한다.
예를 들어 정상 데이터가 9,661개이고 고장 데이터가 339개라면, 모델이 전부 정상이라고 예측해도 정확도가 높게 나올 수 있다.
그래서 고장 예측 문제에서는 정확도만 보면 위험하다. 정확도가 높아도 실제 고장을 잘 못 잡을 수 있기 때문이다.
이 부분은 앞으로도 계속 조심해야 할 것 같다.
정상 설비와 고장 설비 비교하기
통계 파트에서는 먼저 정상 설비와 고장 설비를 나누어 평균과 중앙값을 비교했다.
df.groupby('machine_failure')[features].agg(['mean', 'median'])
groupby('machine_failure')는 데이터를 정상 설비 그룹과 고장 설비 그룹으로 나누는 코드다.
그다음 mean, median을 구하면 각 그룹의 평균과 중앙값을 비교할 수 있다.
여기서 평균과 중앙값을 같이 보는 이유도 중요하다.
평균은 전체적인 수준을 보기 좋지만 이상치에 영향을 많이 받는다.
반면 중앙값은 데이터의 가운데 값이라 이상치에 덜 흔들린다.
이번 과제에서는 고장 설비에서 torque와 tool_wear가 높게 나타났다. 반대로 rotational_speed는 고장 설비에서 낮아지는 경향이 있었다.
기계적으로 생각해보면 어느 정도 자연스럽다. 회전 속도는 낮은데 토크가 높다면 설비에 부하가 걸린 상태일 수 있고, 공구 마모도가 높으면 고장 가능성이 커질 수 있다.
다만 여기서 조심할 점이 있다.
평균이 다르다고 해서 바로 “이 변수가 고장의 원인이다”라고 단정하면 안 된다.
더 안전한 표현은 이렇다.
고장 설비에서 해당 변수의 값이 다르게 나타났고, 고장 여부와 관련이 있어 보인다.
데이터 분석에서는 이런 표현 차이도 중요하다는 생각이 들었다.
T-test로 평균 차이 검정하기
기초 통계에서는 평균 차이를 눈으로 확인했다.
하지만 평균이 다르다고 해서 그 차이가 항상 의미 있는 것은 아니다.
그래서 T-test를 사용한다.
T-test는 두 그룹의 평균 차이가 우연인지, 아니면 통계적으로 의미 있는 차이인지 확인하는 검정이다.
이번 과제에서는 정상 그룹과 고장 그룹을 나누고, 각 변수에 대해 독립표본 T-test를 수행했다.
from scipy import stats
stats.ttest_ind(failure_group['torque'], normal_group['torque'])
가설은 이렇게 세울 수 있다.
귀무가설은 정상 설비와 고장 설비의 평균 차이가 없다는 것이다.
대립가설은 정상 설비와 고장 설비의 평균 차이가 있다는 것이다.
여기서 가장 먼저 봐야 할 값은 p-value다.
p-value가 0.05보다 작으면 귀무가설을 기각하고, 두 그룹의 평균 차이가 통계적으로 있다고 판단한다.
이번 과제에서는 여러 변수에서 p-value가 0.05보다 작게 나왔다.
특히 torque는 정상 설비와 고장 설비의 차이가 크게 나타난 변수였다.
정리하면 기초 통계가 “평균이 달라 보인다”를 확인하는 단계라면, T-test는 “그 차이가 우연이라고 보기 어려운가?”를 확인하는 단계다.
이 둘을 같이 봐야 분석이 더 설득력 있어진다.
회귀와 분류 구분하기
이번 과제에서 꼭 잡아야 하는 개념 중 하나는 회귀와 분류의 차이다.
회귀는 숫자를 예측하는 문제다.
예를 들어 air_temp를 보고 process_temp를 예측하는 문제는 회귀다.
X = df[['air_temp']]
y = df['process_temp']
이 경우 모델은 공정 온도가 몇 K인지 예측한다.
반면 분류는 카테고리를 예측하는 문제다.
이번 과제에서 machine_failure를 예측하는 문제는 분류다.
X = df[['rotational_speed', 'torque', 'tool_wear']]
y = df['machine_failure']
이 경우 모델은 정상인지 고장인지 예측한다.
즉, 숫자 값을 예측하면 회귀, 정상/고장처럼 범주를 예측하면 분류라고 볼 수 있다.
처음에는 모델 이름이 헷갈릴 수 있다. 특히 로지스틱 회귀는 이름에 회귀가 들어가지만 실제로는 분류 모델로 많이 사용된다.
그래서 모델 이름보다 먼저 y가 어떤 형태인지 확인해야 한다.
y가 연속적인 숫자인가, 아니면 범주인가?
이 질문을 먼저 던지면 회귀와 분류를 구분하기 쉬워진다.
머신러닝 기본 코드 흐름
이번 리뷰에서 가장 중요하게 다시 정리한 부분은 머신러닝 기본 흐름이다.
대부분의 머신러닝 코드는 다음 구조를 가진다.
X = df[['변수1', '변수2', '변수3']]
y = df['예측대상']
먼저 입력 변수 X와 예측 대상 y를 나눈다.
그다음 train/test 데이터를 분리한다.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
test_size=0.3,
random_state=42
)
train 데이터는 모델이 공부하는 데이터이고, test 데이터는 모델을 평가하는 데이터다.
모델이 공부한 문제로 바로 시험을 보면 성능이 과대평가될 수 있기 때문에, 학습용과 평가용 데이터를 나누는 것이 중요하다.
그다음 모델을 만들고 학습한다.
model = RandomForestClassifier(random_state=42)
model.fit(X_train, y_train)
fit()은 모델이 데이터를 보고 규칙을 배우는 과정이다.
학습이 끝나면 예측한다.
y_pred = model.predict(X_test)
predict()는 모델이 새로운 데이터를 보고 답을 내는 과정이다.
마지막으로 실제값과 예측값을 비교해 평가한다.
accuracy = accuracy_score(y_test, y_pred)
이 구조는 앞으로 어떤 모델을 쓰더라도 계속 반복될 것 같다.
X와 y 설정 → train/test 분리 → 모델 생성 → fit → predict → 평가
이 흐름은 꼭 익혀야 한다.
RandomForest와 변수 중요도
RandomForest는 여러 개의 의사결정나무를 조합해 예측하는 모델이다.
초보 단계에서는 내부 수식을 깊게 외우기보다, 여러 판단 기준을 조합해서 예측하는 모델이라고 이해하면 된다.
RandomForest의 장점 중 하나는 변수 중요도를 볼 수 있다는 점이다.
model.feature_importances_
변수 중요도는 모델이 예측할 때 어떤 변수를 많이 참고했는지 보여준다.
이번 과제에서는 torque, rotational_speed, tool_wear 같은 변수들이 중요하게 나타났다.
여기서도 주의할 점이 있다.
Feature Importance가 높다고 해서 그 변수가 반드시 고장의 원인이라는 뜻은 아니다.
정확히는 모델이 예측할 때 해당 변수를 많이 참고했다는 뜻이다.
그래서 해석할 때는 이렇게 말하는 것이 더 안전하다.
모델은 고장 여부를 예측할 때 torque를 상대적으로 중요하게 사용했다.
이런 식으로 표현하면 원인과 예측 기여도를 구분할 수 있다.
로지스틱 회귀와 확률 예측
로지스틱 회귀는 분류 모델이다.
이번 과제에서는 air_temp, process_temp, torque를 사용해 설비 고장 여부를 예측했다.
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(max_iter=1000)
model.fit(X_train, y_train)
로지스틱 회귀의 장점은 확률을 볼 수 있다는 점이다.
model.predict_proba(new_sample)
predict()가 정상 또는 고장처럼 최종 결과를 알려준다면, predict_proba()는 정상일 확률과 고장일 확률을 알려준다.
예를 들어 어떤 설비의 고장 확률이 71%로 나온다면, 단순히 고장이라고 예측하는 것보다 훨씬 실무적으로 활용하기 좋다.
현장에서는 이런 식으로 사용할 수 있을 것 같다.
고장 확률이 높은 설비를 먼저 점검한다.
즉, 로지스틱 회귀는 단순한 분류 결과뿐만 아니라, 위험도를 확률로 해석할 수 있다는 점에서 의미가 있다.
상관관계와 시각화
상관관계는 두 변수의 관계를 숫자로 보는 방법이다.
corr = df[features].corr()
상관계수는 -1에서 1 사이 값을 가진다.
1에 가까우면 양의 상관관계가 강하고, -1에 가까우면 음의 상관관계가 강하다. 0에 가까우면 선형 관계가 약하다고 볼 수 있다.
이번 과제에서는 torque가 machine_failure와 상대적으로 높은 양의 상관을 보였다.
하지만 상관관계도 원인을 의미하지는 않는다.
상관관계가 있다고 해서 “torque가 높아서 고장이 났다”라고 말하면 안 된다.
더 적절한 표현은 “torque가 고장 여부와 관련이 있는 방향으로 나타났다” 정도다.
박스플롯도 중요한 시각화였다.
박스플롯은 정상 설비와 고장 설비의 분포 차이를 눈으로 확인할 수 있게 해준다.
sns.boxplot(x='machine_failure', y='torque', data=df)
표로 평균과 중앙값을 보고, T-test로 차이를 검정하고, 박스플롯으로 분포를 확인하면 해석이 훨씬 자연스러워진다.
숫자만 보는 것보다 그래프를 같이 보면 데이터 차이가 더 직관적으로 보인다.
카이제곱 검정
T-test는 수치형 변수의 평균 차이를 검정할 때 사용했다.
반면 카이제곱 검정은 범주형 변수끼리 관계가 있는지 확인할 때 사용한다.
이번 과제에서는 Type과 machine_failure의 관계를 확인했다.
contingency_table = pd.crosstab(df['Type'], df['machine_failure'])
먼저 교차표를 만든다.
교차표는 제품 등급별로 정상과 고장이 몇 개인지 세는 표다.
그다음 카이제곱 검정을 수행한다.
chi2, p, dof, expected = chi2_contingency(contingency_table)
여기서 p-value가 0.05보다 작으면 Type과 machine_failure 사이에 연관성이 있다고 판단할 수 있다.
이때 단순히 고장 개수만 보면 안 된다.
Type마다 전체 데이터 개수가 다를 수 있기 때문에 고장률을 같이 봐야 한다.
failure_rate = contingency_table[1] / contingency_table.sum(axis=1) * 100
고장 개수보다 고장률을 보는 것이 더 정확한 비교가 될 수 있다.
Feature Engineering
Feature Engineering은 기존 변수를 조합해 새로운 변수를 만드는 과정이다.
이번 과제에서는 power와 temp_diff를 만들었다.
df['power'] = 2 * np.pi * df['rotational_speed'] * df['torque'] / 60
df['temp_diff'] = df['process_temp'] - df['air_temp']
power는 회전 속도와 토크를 조합한 변수다.
기계공학적으로 생각하면 회전 속도와 토크를 따로 보는 것보다, 둘을 조합한 동력 관련 지표가 설비 상태를 더 잘 설명할 수 있다.
temp_diff는 공정 온도와 공기 온도의 차이다.
단순히 온도 두 개를 따로 보는 것보다, 공정 과정에서 온도가 얼마나 차이 나는지 보는 변수가 될 수 있다.
파생변수를 추가한 뒤 모델 성능이 좋아졌다면, 새 변수가 기존 변수만으로는 담기 어려웠던 정보를 어느 정도 보완했다고 볼 수 있다.
이번 과제에서는 파생변수 추가 후 정확도가 조금 더 높아졌다.
이 부분에서 느낀 것은, 머신러닝 성능은 모델만 바꾼다고 좋아지는 게 아니라는 점이다.
좋은 변수를 만드는 것도 모델 성능을 높이는 중요한 방법이다.
3. 나의 간단 소감
오늘은 개인과제 리뷰 자료를 보면서, 과제를 단순히 풀고 끝내는 것이 아니라 전체 흐름을 다시 정리했다.
처음 과제를 할 때는 코드가 많아서 정신이 없었다. groupby, ttest_ind, LinearRegression, RandomForestClassifier, LogisticRegression, chi2_contingency까지 한 번에 나오니까 각각을 따로 외우려는 느낌이 강했다.
그런데 리뷰를 보면서 다시 보니 결국 구조는 단순했다.
먼저 데이터를 확인하고, 정상 설비와 고장 설비를 비교한다. 그 차이가 통계적으로 의미 있는지 검정하고, 그래프로 분포를 확인한다. 이후 머신러닝 모델로 고장 여부를 예측하고, 어떤 변수가 중요한지 해석한다.
즉, 이번 과제는 비교 → 검정 → 시각화 → 예측 → 해석의 흐름이었다.
개인적으로 가장 중요하게 느낀 부분은 X와 y를 구분하는 것이다. 내가 예측하려는 값이 무엇인지 정해야 y가 정해지고, 무엇을 보고 예측할지 정해야 X가 정해진다. 이걸 놓치면 코드가 아무리 맞아도 분석 방향이 흔들릴 수 있다.
또 하나 기억에 남은 부분은 정확도 해석이다. 설비 고장 데이터처럼 고장 비율이 낮은 데이터에서는 정확도가 높아도 모델이 진짜 고장을 잘 잡는다고 말하기 어렵다. 정상 데이터가 대부분이면 전부 정상이라고 찍어도 정확도가 높게 나올 수 있기 때문이다. 앞으로는 정확도뿐 아니라 recall, precision, F1-score도 같이 봐야겠다는 생각이 들었다.
Feature Engineering도 다시 보니 꽤 중요했다. 특히 power는 회전 속도와 토크를 조합한 변수라 기계공학 전공자로서 더 직관적으로 이해됐다. 단순히 데이터를 모델에 넣는 것보다, 도메인 지식을 활용해서 의미 있는 변수를 만드는 것이 훨씬 중요할 수 있다는 점이 와닿았다.
오늘 정리하면서 머신러닝은 단순히 모델을 돌리는 일이 아니라는 걸 다시 느꼈다. 데이터를 이해하고, 변수 차이를 확인하고, 통계적으로 검정하고, 모델 결과를 해석하는 전체 과정이 머신러닝이었다.
아직 모든 코드를 완전히 외운 것은 아니지만, 적어도 앞으로 과제를 보면 어떤 순서로 접근해야 할지는 조금 더 선명해진 것 같다.
머신러닝은 코드를 외우는 것보다, 지금 이 코드가 분석 흐름에서 어떤 역할을 하는지 이해하는 것이 먼저다.
'내일배움캠프' 카테고리의 다른 글
| [본캠프] 데이터기반 QA/QC 부트캠프 39일차 (0) | 2026.07.08 |
|---|---|
| [본캠프] 데이터기반 QA/QC 부트캠프 38일차 (0) | 2026.07.07 |
| [본캠프] 데이터기반 QA/QC 부트캠프 36일차 (0) | 2026.07.01 |
| [본캠프] 데이터기반 QA/QC 부트캠프 35일차 (0) | 2026.06.30 |
| [본캠프] 데이터기반 QA/QC 부트캠프 34일차 (1) | 2026.06.29 |