| 컬럼명 | 설명 |
|---|---|
| age | 나이 (숫자) |
| job | 직업 (범주형) |
| marital | 결혼 여부 (범주형) |
| education | 교육 수준 (범주형) |
| default | 신용 불량 여부 (범주형) |
| housing | 주택 대출 여부 (범주형) |
| loan | 개인 대출 여부 (범주형) |
| contact | 연락 유형 (범주형) |
| month | 마지막 연락 월 (범주형) |
| day_of_week | 마지막 연락 요일 (범주형) |
| duration | 마지막 연락 지속 시간, 초 단위 (숫자) |
| campaign | 캠페인 동안 연락 횟수 (숫자) |
| pdays | 이전 캠페인 후 지난 일수 (숫자) |
| previous | 이전 캠페인 동안 연락 횟수 (숫자) |
| poutcome | 이전 캠페인의 결과 (범주형) |
| emp.var.rate | 고용 변동률 (숫자) |
| cons.price.idx | 소비자 물가지수 (숫자) |
| cons.conf.idx | 소비자 신뢰지수 (숫자) |
| euribor3m | 3개월 유리보 금리 (숫자) |
| nr.employed | 고용자 수 (숫자) |
| y | 정기 예금 가입 여부 (이진: yes=1, no=0) |
def fill_unknown_values(df, target_column):
# Create a copy of the DataFrame to avoid modifying the original
df = df.copy()
# Separate rows with and without 'unknown' in the target column
known_rows = df[df[target_column] != 'unknown']
unknown_rows = df[df[target_column] == 'unknown']
# Encode categorical target column if it's categorical
target_is_categorical = df[target_column].dtype == 'object' and target_column != 'unknown'
if target_is_categorical:
label_encoder = LabelEncoder()
known_rows[target_column] = label_encoder.fit_transform(known_rows[target_column])
# Prepare training features (X) and target (y)
X = known_rows.drop(columns=[target_column])
y = known_rows[target_column]
# Prepare the features for unknown rows
X_unknown = unknown_rows.drop(columns=[target_column])
# Handle categorical features
X = pd.get_dummies(X)
X_unknown = pd.get_dummies(X_unknown)
# Align columns in case dummy variables are mismatched
X, X_unknown = X.align(X_unknown, join='left', axis=1)
X_unknown = X_unknown.fillna(0) # Fill missing dummies with 0
# Train the model
if target_is_categorical:
model = RandomForestClassifier(random_state=42)
else:
model = RandomForestRegressor(random_state=42)
model.fit(X, y)
# Predict the 'unknown' values
predictions = model.predict(X_unknown)
# Convert predictions back to original labels if target was categorical
if target_is_categorical:
predictions = label_encoder.inverse_transform(predictions.astype(int))
# Replace 'unknown' values in the original DataFrame
df.loc[df[target_column] == 'unknown', target_column] = predictions
return df

def fill_unknown_values(df, target_column):
# Create a copy of the DataFrame to avoid modifying the original
df = df.copy()
# Separate rows with and without 'unknown' in the target column
known_rows = df[df[target_column] != 'unknown']
unknown_rows = df[df[target_column] == 'unknown']
# Encode categorical target column if it's categorical
target_is_categorical = df[target_column].dtype == 'object' and target_column != 'unknown'
if target_is_categorical:
label_encoder = LabelEncoder()
known_rows[target_column] = label_encoder.fit_transform(known_rows[target_column])
# Prepare training features (X) and target (y)
X = known_rows.drop(columns=[target_column])
y = known_rows[target_column]
# Prepare the features for unknown rows
X_unknown = unknown_rows.drop(columns=[target_column])
# Handle categorical features
X = pd.get_dummies(X)
X_unknown = pd.get_dummies(X_unknown)
# Align columns in case dummy variables are mismatched
X, X_unknown = X.align(X_unknown, join='left', axis=1)
X_unknown = X_unknown.fillna(0) # Fill missing dummies with 0
# Train the model
if target_is_categorical:
model = RandomForestClassifier(random_state=42)
else:
model = RandomForestRegressor(random_state=42)
model.fit(X, y)
# Predict the 'unknown' values
predictions = model.predict(X_unknown)
# Convert predictions back to original labels if target was categorical
if target_is_categorical:
predictions = label_encoder.inverse_transform(predictions.astype(int))
# Replace 'unknown' values in the original DataFrame
df.loc[df[target_column] == 'unknown', target_column] = predictions
return df

코드설명
1. unknown 값이 있는 행과 없는 행 분리
- kwnon_rows : target_column 에 unknown 이 아닌 값을 가진 행
- unknown_rows : target_column 에 unknown 값을 가진 행
- 대상 열이 범주형인지 확인
- target_is_categorical : 대상 열(target_column)이 범주형(string) 인지 확인
- 범주형인 경우, LabelEncoder를 사용해 문자열 값을 숫자로 변환한다. 이는 머신러닝 모델이 숫자 데이터를 더 잘 처리하기 때문이다.
- 학습용 데이터 타켓 데이터 준비
- X : 대상 열을 제외한 모든 열(독립변수)
- y : 대상 열 (종속변수)
- 예측용 데이터 준비
- X_unknown : 대상 열을 제외한 unknown 행의 모든 열
- 범주형 열 처리
- pd.get_dummies : 범주형 데이터를 원-핫 인코딩하여 숫자형 데이터로 변환
- 열 정렬 : 원-핫 인코딩 후 X와 X_unknown 의 열 구성을 일치 시킨다. 만약 X_unknown에 없는 열이 있다면 0으로 채운다.
- 모델학습
- RandomForestClassifier : 대상 열이 범주형일 때 사용
- RandomForestRegressor : 대상 열이 숫자형일 때 사용
- X와 y를 사용하여 모델을 학습시킨다.
- unknown 값 예측
- 학습된 모델을 사용해 target_column에 unknown 값을 가진 행을 예측한다.
- 예측값을 원래 레이블로 변환
- 대상 열이 범주형이라면, 예측된 숫자값에 원래 레이블(문자열)로 변환
- unknown 값 대체
- 원본 데이터프레임에서 target_column의 unknown 값을 예측된 값으로 교체.
labels=df['y'].value_counts().index
values=df['y'].value_counts().values
plt.figure(figsize = (8, 6))
ax = sns.barplot(x=labels, y=values)
for i, p in enumerate(ax.patches):
height = p.get_height()
ax.text(p.get_x()+p.get_width()/2., height + 0.1, values[i],ha="center")
plt.xlabel('')
plt.title('Has The Client Subscribed a Term Deposit?')
plt.tight_layout()
plt.show()

plt.figure(figsize = (10, 12))
plt.style.use('default')
g = sns.displot(data=df, x='age', hue='y', bins=30, kde = False, legend=False)
plt.title('Age Distribution')
plt.xlabel('Age')
plt.legend(title='Subscribed Term', loc='upper right', labels=['yes', 'no'])
plt.show()

fig, axes = plt.subplots(1, 2)
plt.style.use('default')
#define figure size
sns.set(rc={"figure.figsize":(8, 4)})
sns.histplot(df.loc[df['y']=='yes']['age'], bins=30, kde = True,color='#ffa54c' , ax=axes[0])
axes[0].set_xlabel("Age", fontsize = 10)
axes[0].set_title('Age Distribution (Yes)')
sns.histplot(df.loc[df['y']=='no']['age'], bins=30, kde = True, color='#539100', ax=axes[1])
axes[1].set_xlabel("Age", fontsize = 10)
axes[1].set_ylabel('')
axes[1].set_title('Age Distribution (No)')
plt.show()

yes_data = df.loc[df['y']=='yes']
sns.set_style('darkgrid')
g = sns.boxplot(data=yes_data,y='y',x='age',orient = 'h', color = '#bb1587')
g.set_title('Age Distribution (Yes)')
plt.show(g)

grid_layout = sns.FacetGrid(df, col = 'job', hue='y', col_wrap = 3)
grid_layout.map(plt.hist, 'age')
plt.title('Job Distribution')
plt.show()

grid_layout = sns.FacetGrid(df, col = 'education', hue='y', col_wrap = 4)
grid_layout.map(plt.hist, 'age');

grid_layout = sns.FacetGrid(df, col = 'marital', hue='y', col_wrap = 4)
grid_layout.map(plt.hist, 'age');

palette = sns.color_palette("tab10", n_colors=df['education'].nunique())
# Countplot with the generated palette
sns.countplot(data=df, y='education', order=df['education'].value_counts().index, palette=palette)
plt.ylabel('Education')
plt.title('Education Level')
plt.show()

sns.set_style('darkgrid')
# Use a palette to assign different colors to each education level
palette = sns.color_palette("husl", n_colors=yes_data['education'].nunique())
g = sns.boxplot(data=yes_data, y='education', x='age', orient='h', palette=palette)
g.set_xlabel('Age')
g.set_ylabel('Education Level')
g.set_title('Age Distribution of Education of those Subscribed Loan Deposit')
plt.show()

소비자 물가지수와 고용 변동률간의 상관계수는 여전히 높아 모델링시 유의해야한다.