카테고리 없음
내일배움캠프_[베이직반]파이썬 핵심 쏙쏙_3회차
iron-min
2025. 10. 28. 13:55
1. 오늘배운것.
결측치 처리 방법 3가지
1) 제거
개념 : 결측값이 포함된 행(row) 또는 열(column)을 제거하는 방법
사용경우
- 결측치가 매우 적고(5%), 제거해도 데이터 손실이 크지 않은 경우
- 해당 칼럼이 분석에서 중요하지 않을 경우(도메인 지식으로 볼때!)
예시코드)
# 1️⃣ 결측치가 있는 행 제거
df_dropped_rows = df.dropna()
# 여러개 칼럼 6개의 칼럼이 있는경우, 어떤행은 1번칼럼이 결측치 어떤행 2번칼럼
# 2️⃣ 결측치가 있는 열 제거 (특정 칼럼이 결측치가 많을 경우)
df_dropped_columns = df.dropna(axis=1)
2) 대체
개념 : 결측치를 해당 칼럼의 평균, 중앙값, 최빈값으로 대체,
연속형 변수(숫자) 에는 평균/중앙값, 범주형 변수(문자)에는 최빈값을 사용
사용경우
- 데이터가 정규 분포를 따를 경우 → 평균 ⇒ plot을그려라 (KDE plot)
- 이상치가 많거나 비대칭 분포를 가질 경우 → 중앙값 ⇒ 비정규분포인지 확인필요, boxplot
- 범주형 데이터 → 최빈값
코드예시)
import pandas as pd
import numpy as np
# 샘플 데이터 생성
data = {
"sensor_value": [10, 12, np.nan, 15, 14, np.nan, 13],
"category": ["A", "B", None, "A", "C", "B", None]
}
df = pd.DataFrame(data)
print("=== 원본 데이터 ===")
print(df)
# 1️⃣ 평균으로 대체 (연속형 데이터)
df["sensor_value_mean"] = df["sensor_value"].fillna(df["sensor_value"].mean())
# 2️⃣ 중앙값으로 대체 (이상치가 있을 때 추천)
df["sensor_value_median"] = df["sensor_value"].fillna(df["sensor_value"].median())
# 3️⃣ 최빈값으로 대체 (범주형 데이터)
df["category_mode"] = df["category"].fillna(df["category"].mode()[0])
print("\n=== 결측치 처리 후 데이터 ===")
print(df)
3) 예측모델 사용 - KNN Imputation (K-최근접 이웃 대체)
개념: 결측값이 있는 샘플과 가장 유사한 샘플( 몇(k)개)을 찾아 평균값을 사용하여 결측치를 채우는 방법
사용 경우:
- 연속형 데이터에서 패턴이 있을 때
- 데이터 간의 유사성이 높을 때
코드예시)
import pandas as pd
import numpy as np
from sklearn.impute import KNNImputer #모델
# 샘플 데이터프레임 생성
data = {
"A": [1, 2, np.nan, 4, 5],
"B": [5, np.nan, np.nan, 8, 10],
"C": [2, 4, 6, 8, np.nan]
}
df = pd.DataFrame(data)
print("=== 원본 데이터 ===")
print(df)
# KNN Imputation (이웃 개수 k=3)
imputer_knn = KNNImputer(n_neighbors=3) #하이퍼파라미터 벌점, l1_비율
# 기본적으로 3~5라는값을 많이 사용합니다.
# 데이터가 많으면 많을수록 k 크게, 데이터가 작으면 k 작게
# 데이터가 1000~5000 3~5
# 5000~ 10000 7~10
df_knn_imputed = imputer_knn.fit_transform(df)
# numpy → DataFrame 변환
df_knn_imputed = pd.DataFrame(df_knn_imputed, columns=df.columns)
print("\n=== KNN으로 결측치 보간된 데이터 ===")
print(df_knn_imputed)
이상치 탐지 및 처리 방법론 (3가지)
- 시각적 탐지: Box Plot, Histogram, Scatter Plot 등을 사용하여 시각적으로 이상치를 확인합니다.
- IQR(Interquartile Range) 기준: (Q1 - 1.5×IQR, Q3 + 1.5×IQR) 밖의 데이터를 이상치로 정의하고 처리합니다.
- Z-Score 기준: 데이터가 평균으로부터 표준편차의 3배(±3σ)를 초과해 벗어나는 경우 이상치로 판단합니다. (+1, +2, +3)
1) 이상치를 제거
사용 경우
- 이상치가 센서 오류, 입력 실수 (9999) 등으로 발생했으며 실제 의미가 없는 경우
- 이상치가 전체 데이터의 1~5% 이하로 매우 적을 때
- 이상치가 불량과 관련되지 않은 경우 (실질적으로 이게 공정에 이상치랑 맞지않다라는부분)
import pandas as pd
# 샘플 데이터
data = {
"sensor_value": [10, 12, 11, 13, 12, 500, 14, 13, 600, 12] # 500, 600은 이상치
}
df = pd.DataFrame(data)
print("=== 원본 데이터 ===")
print(df)
# IQR 계산
Q1 = df["sensor_value"].quantile(0.25) # 1사분위수
Q3 = df["sensor_value"].quantile(0.75) # 3사분위수
IQR = Q3 - Q1 # 사분위 범위
# 이상치 경계 정의
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
# 이상치 제거
df_filtered = df[(df["sensor_value"] >= lower) & (df["sensor_value"] <= upper)]
print("\n=== 이상치 제거 후 데이터 ===")
print(df_filtered)
2) 이상치를 경계값으로 대체
개념: 이상치 값을 최대/최소 경계값(Q1 - 1.5×IQR, Q3 + 1.5×IQR)로 대체하는 방법
사용 경우
- 이상치를 제거하면 데이터 손실이 클 경우
- 이상치가 극단적인 값이지만 완전히 무시할 수는 없을 때
코드예시)
import pandas as pd
import numpy as np
# 샘플 데이터
data = {
"sensor_value": [10, 12, 11, 13, 12, 500, 14, 13, 600, 12]
}
df = pd.DataFrame(data)
print("=== 원본 데이터 ===")
print(df)
# IQR 계산
Q1 = df["sensor_value"].quantile(0.25)
Q3 = df["sensor_value"].quantile(0.75)
IQR = Q3 - Q1
# 이상치 경계값 계산
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# Winsorizing 적용 (경계값으로 이상치 대체)
df["sensor_value"] = np.where(df["sensor_value"] < lower_bound, lower_bound,
np.where(df["sensor_value"] > upper_bound, upper_bound,
df["sensor_value"]))
print("\n=== Winsorizing 적용 후 데이터 ===")
print(df)
3) Z-Score 이상치 처리
개념
- 데이터가 평균에서 표준편차 3배 이상 (|Z| > 3) 벗어나면 이상치로 판단
- 이상치를 평균 ± 3σ 범위로 대체하거나 제거 가능
사용경우
- 데이터가 정규분포에 가깝고 이상치가 평균과 표준편차에 큰 영향을 줄 때
- 센서 데이터, 실험값 등 숫자형 데이터 이상치 탐지에 활용
코드예시)
import pandas as pd
import numpy as np
# 샘플 데이터 생성
data = {
"sensor_value": [10, 12, 11, 13, 12, 50, 14, 13, 60, 12] # 50, 60은 이상치 가정
}
df = pd.DataFrame(data)
print("=== 원본 데이터 ===")
print(df)
# 평균과 표준편차 계산
mean = df["sensor_value"].mean()
std = df["sensor_value"].std()
# Z-Score 계산
z_scores = (df["sensor_value"] - mean) / std
# 이상치 기준 설정 (±3)
threshold = 3
# 이상치 경계값 계산
lower_limit = mean - threshold * std # threshold * std => 3sigma
upper_limit = mean + threshold * std # threshold * std => 3sigma
# 이상치 처리 (경계값으로 대체)
df["sensor_value"] = np.where(df["sensor_value"] > upper_limit, upper_limit,
np.where(df["sensor_value"] < lower_limit, lower_limit,
df["sensor_value"]))
print("\n=== Z-Score 기준 이상치 처리 결과 ===")
print(df)
2. 오늘 시도해본것
1) VIF_실습_1번. VIF 계산 및 다중공선성 진단
문제)
| import pandas as pd import numpy as np from statsmodels.stats.outliers_influence import variance_inflation_factor import statsmodels.api as sm # 결정적 데이터 생성 (강한 상관 구조 포함) n = 100 i = np.arange(n) X1 = 40 + 20 * i / (n - 1) X2 = 2 * X1 + 0.1 * np.sqrt(i) # X1과 강한 상관 X3 = 30 + 8 * np.sin(i / 5) # 독립적 패턴 X4 = 0.5 * X1 + 0.5 * X2 + 0.05 * np.sin(i) # X1+X2 조합 data = pd.DataFrame({ 'X1': X1, 'X2': X2, 'X3': X3, 'X4': X4 }) # 👉 왜 상수항을 추가하는가? # VIF 계산 시 statsmodels는 회귀 모델 내부 구조를 사용하므로, # 모델 stability를 위해 반드시 X = sm.add_constant(data)를 통해 상수항을 추가해야 한다. # 다음을 수행하시오. # 1) 상수항(const)을 추가한 뒤 각 독립변수(X1~X4)의 VIF 값을 계산하시오. (소수점 둘째자리) |
정답)
import pandas as pd
import numpy as np
from statsmodels.stats.outliers_influence import variance_inflation_factor
import statsmodels.api as sm
# 결정적 데이터 생성 (강한 상관 구조 포함)
n = 100
i = np.arange(n)
X1 = 40 + 20 * i / (n - 1)
X2 = 2 * X1 + 0.1 * np.sqrt(i) # X1과 강한 상관
X3 = 30 + 8 * np.sin(i / 5) # 독립적 패턴
X4 = 0.5 * X1 + 0.5 * X2 + 0.05 * np.sin(i) # X1+X2 조합
data = pd.DataFrame({
'X1': X1,
'X2': X2,
'X3': X3,
'X4': X4
})
X = data[['X1', 'X2', 'X3','X4']]
X = sm.add_constant(X)
vif = pd.DataFrame()
vif["변수"] = X.columns
vif['VIF'] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]
vif['VIF'] = round(vif['VIF'], 2)
vif_drop = vif.drop(index=0)
print('VIF 값')
print(vif_drop.to_string(index=False))
2) 회귀_실습_1번. 다중 선형 회귀 모델 구축
문제
| import numpy as np import pandas as pd from sklearn.linear_model import LinearRegression from sklearn.model_selection import train_test_split # 화학 공정의 예시 데이터 생성 # 온도, 압력, 촉매량이 화학 반응의 순도에 영향을 준다고 가정 n = 200 t = np.linspace(0, 1, n) 온도 = 150 + 100 * t 압력 = 1 + 4 * (t ** 2) 촉매량 = 10 + 40 * np.sqrt(t) 순도 = 20 + 0.3온도 + 5압력 + 0.1촉매량 + 2np.sin(3*t) df = pd.DataFrame({ '온도': 온도, '압력': 압력, '촉매량': 촉매량, '순도': 순도 }) # 다음을 수행하시오. 위 내용은 그대로 복붙하여 사용 할 것. # 1) 독립변수(온도, 압력, 촉매량)와 종속변수(순도)를 분리하시오. # 2) train_test_split을 사용하여 데이터를 학습용과 테스트용으로 분리하시오. (test_size=0.2, random_state=42) # 3) 다중 선형 회귀 모델을 학습시키고 절편과 회귀 계수 값을 출력하시오. (소수점 둘째자리) 최종 출력 절편(Intercept): 8.46 계수(Coefficients): 온도: 0.39 압력: 2.96 촉매량: 0.08 |
정답)
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
# 화학 공정의 예시 데이터 생성
# 온도, 압력, 촉매량이 화학 반응의 순도에 영향을 준다고 가정
n = 200
t = np.linspace(0, 1, n)
온도 = 150 + 100 * t
압력 = 1 + 4 * (t ** 2)
촉매량 = 10 + 40 * np.sqrt(t)
순도 = 20 + 0.3*온도 + 5*압력 + 0.1*촉매량 + 2*np.sin(3*t)
df = pd.DataFrame({
'온도': 온도,
'압력': 압력,
'촉매량': 촉매량,
'순도': 순도
})
X = [[df['온도'][i], df['압력'][i], df['촉매량'][i]] for i in range(n)]
y = df['순도']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print("절편(Intercept):", round(model.intercept_,2))
print("계수(Coefficients):")
print('온도:', round(model.coef_[0],2))
print('압력:', round(model.coef_[1],2))
print('촉매량:', round(model.coef_[2],2))
3) 성능평가_실습_1번. 회귀 모델 성능 지표 계산
| import numpy as np import pandas as pd from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error # 결정적 데이터 생성 n = 100 t = np.linspace(0, 1, n) X0 = 10 * t X1 = 10 * (t ** 2) X2 = 10 * np.sqrt(t) X = np.column_stack([X0, X1, X2]) y = 3X0 + 2X1 - 1X2 + np.sin(5t) # 결정적 잡음(sin) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) model = LinearRegression() model.fit(X_train, y_train) y_pred = model.predict(X_test) # 다음을 수행하시오. # 1) 테스트 데이터에 대한 MSE를 소수점 둘째자리까지 출력하시오. # 2) 테스트 데이터에 대한 RMSE를 소수점 둘째자리까지 출력하시오. |
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
# 결정적 데이터 생성
n = 100
t = np.linspace(0, 1, n)
X0 = 10 * t
X1 = 10 * (t ** 2)
X2 = 10 * np.sqrt(t)
X = np.column_stack([X0, X1, X2])
y = 3*X0 + 2*X1 - 1*X2 + np.sin(5*t) # 결정적 잡음(sin)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
print(f'MSE: {mse:.2f}')
print(f'RMSE: {rmse:.2f}')
4) 성능평가_실습_1번. 회귀 모델 성능 지표 계산
문제
| import numpy as np import pandas as pd from sklearn.model_selection import train_test_split from sklearn.linear_model import Ridge, LinearRegression from sklearn.metrics import mean_squared_error # 결정적 데이터 생성(다중공선성 포함) n = 100 t = np.linspace(0, 1, n) X1 = 10 * t X2 = X1 + 0.5 * t # 강한 상관 X3 = 10 * np.sin(2np.pit) # 비선형 패턴 X = np.column_stack([X1, X2, X3]) y = 2X1 + 3X2 + 1.5X3 + np.sin(3t) # 결정적 잡음(sin) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 다음을 수행하시오. # 1) LinearRegression을 학습하고 테스트 RMSE를 소수점 둘째자리까지 출력하시오. # 2) Ridge(alpha=10.0) 모델을 학습하고 테스트 데이터에 대한 예측값을 소수점 둘째자리까지 모두 출력하시오. (리스트 형태) |
정답)
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Ridge, LinearRegression
from sklearn.metrics import mean_squared_error
# 결정적 데이터 생성(다중공선성 포함)
n = 100
t = np.linspace(0, 1, n)
X1 = 10 * t
X2 = X1 + 0.5 * t # 강한 상관
X3 = 10 * np.sin(2*np.pi*t) # 비선형 패턴
X = np.column_stack([X1, X2, X3])
y = 2*X1 + 3*X2 + 1.5*X3 + np.sin(3*t) # 결정적 잡음(sin)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
# MSE 계산
mse = mean_squared_error(y_test, y_pred)
# RMSE 계산 (MSE의 제곱근)
rmse = np.sqrt(mse)
# 결과 출력
print("LinearRegression Test RMSE:", round(rmse,2))
ridge_reg = Ridge(alpha=10.0) #alpha는 벌점을 얼마나 강하게 적용할지 결정하는 값
ridge_reg.fit(X_train, y_train)
y_pred = ridge_reg.predict(X_test)
Coefficients = ridge_reg.predict(X_test)
print('')
print('Ridge(alpha=10.0) 예측값:')
print(np.round(Coefficients,2).tolist())
5) Lasso_실습_1번. Lasso 회귀 계수 확인
| import numpy as np import pandas as pd from sklearn.model_selection import train_test_split from sklearn.linear_model import Lasso from sklearn.preprocessing import StandardScaler # 결정적 데이터 생성 (일부 변수는 노이즈 역할) n = 150 t = np.linspace(0, 1, n) X1 = 10 * t X2 = 10 * np.sqrt(t) X3 = np.sin(4 * np.pi * t) X4 = 10 * (t ** 2) X5 = np.cos(3 * np.pi * t) X6 = np.log1p(9 * t) X = np.column_stack([X1, X2, X3, X4, X5, X6]) y = 3 * X1 + 2 * X2 + 1.5 * X4 + np.sin(5*t) # X3, X5, X6는 중요도 낮음 # 표준화 후 분할 scaler = StandardScaler() X_scaled = scaler.fit_transform(X) X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42) |
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Lasso
from sklearn.preprocessing import StandardScaler
# 결정적 데이터 생성 (일부 변수는 노이즈 역할)
n = 150
t = np.linspace(0, 1, n)
X1 = 10 * t
X2 = 10 * np.sqrt(t)
X3 = np.sin(4 * np.pi * t)
X4 = 10 * (t ** 2)
X5 = np.cos(3 * np.pi * t)
X6 = np.log1p(9 * t)
X = np.column_stack([X1, X2, X3, X4, X5, X6])
y = 3 * X1 + 2 * X2 + 1.5 * X4 + np.sin(5*t) # X3, X5, X6는 중요도 낮음
# 표준화 후 분할
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)
lasso_reg = Lasso(alpha=0.5)
lasso_reg.fit(X_train, y_train)
y_pred = lasso_reg.predict(X)
print('Lasso 회귀 계수:')
print("X1:", round(lasso_reg.coef_[0],1))
print("X2:", round(lasso_reg.coef_[1],1))
print('X3:', round(lasso_reg.coef_[2],1))
print('X4:', round(lasso_reg.coef_[3],1))
print('X5:', round(lasso_reg.coef_[4],1))
print('X6:', round(lasso_reg.coef_[5],1))
3. 느낀점
머신러닝모델로 변수들의 가중성을 확인하고 회귀계수를 산출해보면서 실제 요인들이 특정 변수에 미치는 영향이 무엇인지 확인하는 방법을 배울 수 있었습니다. 머신러닝 모델들의 구조가 약간 반복적인 면이 있어서 조금 더 익숙해지면 편하게 쓸 수 있을 것 같습니다.