실습에 사용할 데이터 셋은 ‘의료비 개인 데이터셋’이다.

데이터를 받으면 항상 문제부터 정의해야 된다!

먼저 EDA를 진행해보자.
import pandas as pd
# 데이터 경로 지정 및 읽어오기
data_path = '/content/insurance.csv'
insurance_data = pd.read_csv(data_path)
# 데이터 꼴 확인
insurance_data.head()

2.기본 정보 및 기초 통계
# 기본 정보
print('#'*20, '기본 정보', '#'*20)
insurance_data.info() # info() 안에서 자동으로 print를 진행
# 기초 통계량
summary_statistics = insurance_data.describe(include='all')
print('#'*20, '기초 통계량', '#'*20)
print(summary_statistics)

시각화는 범주형 데이터(남자/여자, 흡연여부 등)와 수치형 데이터(BMI, age 등)으로 나눠서 볼 예정이다.
import matplotlib.pyplot as plt
plt.figure(figsize=(14, 10))
# 나이 분포
plt.subplot(2, 2, 1) #2*2중 1번째에 들어가
plt.hist(insurance_data['age'], color='skyblue', edgecolor='black')
plt.title('Age Distribution')
plt.xlabel('Age')
plt.ylabel('Frequency')
# BMI 분포
plt.subplot(2, 2, 2)
plt.hist(insurance_data['bmi'], bins=30, color='olive', edgecolor='black')
plt.title('BMI Distribution')
plt.xlabel('BMI')
plt.ylabel('Frequency')
# 부양가족 분포
plt.subplot(2, 2, 3)
plt.hist(insurance_data['children'], color='gold', edgecolor='black')
plt.title('Number of Children Distribution')
plt.xlabel('Number of Children')
plt.ylabel('Frequency')
# 의료비 분포
plt.subplot(2, 2, 4)
plt.hist(insurance_data['charges'], bins=30, color='teal', edgecolor='black')
plt.title('Charges Distribution')
plt.xlabel('Charges')
plt.ylabel('Frequency')
plt.tight_layout()
plt.show()

.corr() 객체에서 바로 상관관계 분석 가능correlation_matrix = insurance_data.corr()
# 상관관계 메트릭스 시각화
plt.figure(figsize=(5, 4))
plt.matshow(correlation_matrix, fignum=1)
plt.colorbar()
plt.xticks(range(len(correlation_matrix.columns)), correlation_matrix.columns, rotation=90)
plt.yticks(range(len(correlation_matrix.columns)), correlation_matrix.columns)
plt.title('Correlation Matrix of Medical Cost Datasets', y=1.15)
plt.show()
# 상관관계 값 프린트
print('#'*20, '상관관계 값 확인', '#'*20)
print(correlation_matrix)

plt.figure(figsize=(18, 5))
# 성별에 따른 의료비용
plt.subplot(1, 3, 1)
plt.boxplot([insurance_data[insurance_data['sex']=='male']['charges'],
insurance_data[insurance_data['sex']=='female']['charges']],
labels=['Male', 'Female'])
plt.title('Charges by Sex')
plt.ylabel('Charges')
# 흡연 유무에 따른 의료비용
plt.subplot(1, 3, 2)
plt.boxplot([insurance_data[insurance_data['smoker']=='yes']['charges'],
insurance_data[insurance_data['smoker']=='no']['charges']],
labels=['Smoker', 'Non-smoker'])
plt.title('Charges by Smoker')
plt.ylabel('Charges')
# 거주 지역에 따른 의료비용
plt.subplot(1, 3, 3)
regions = insurance_data['region'].unique()
region_charges = [insurance_data[insurance_data['region']==region]['charges'] for region in regions]
plt.boxplot(region_charges, labels=regions)
plt.title('Charges by Region')
plt.ylabel('Charges')
plt.tight_layout()
plt.show()

카테고리형(범주형) 변수는 선형 모델에 입력으로 사용하기 위해 수치형으로 변경해야 함
이번 데이터에서는 성별, 흡연 유무, 지역이 이에 해당
일반적으로 원-핫 인코딩(one-hot encoding)방식을 사용
• 예를 들어, 성별이라면
• 성별남성과 성별여성 이라는 별도의 열을 만들고
• 각각을 0과 1의 값으로 표현
insurance_encoded = pd.get_dummies(insurance_data, drop_first=True)
insurance_encoded

각 문자열 데이터가 0(TRUE)과 1(FALSE)로 바뀐 것을 볼 수 있다.
만약 drop_first= 를 False로 둔다면 아래와 같이 나옴

사용할 데이터를 확정했다면 학습 및 평가 데이터로 분리
원래는 학습 / 검증 / 평가 과정으로 나누어야 하지만
실제 서비스 모델을 개발하는 과정이 아니므로 학습과 평가 데이터로만 분리하자.
from sklearn.model_selection import train_test_split
y_column = ['charges']
X = insurance_encoded.drop(y_column, axis=1)
y = insurance_encoded[y_column]
X_train, X_test, y_train, y_test = train_test_split(X, y,
test_size=0.2,
random_state=42)
print('#'*20, 'X_train', '#'*20)
print(X_train.head, end='\n')
print('#'*20, 'Y_train', '#'*20)
print(y_train.head, end='\n\n')
print('#'*20, 'X_test', '#'*20)
print(X_test.head, end='\n')
print('#'*20, 'Y_test', '#'*20)
print(y_test.head, end='\n')


서로 다른 수치형 데이터 특성 사이의 값 범위를 비슷하게 맞춰주는 과정
필수 단계는 아니지만 매우 권장되는 과정이다!
효과
• 특히 경사 하강법을 사용하는 과정에서 수렴 속도를 높일 수 있음
• 규제 모델을 사용한다면 일부 특성에 강하게 규제가 걸리는 과정을 회피할 수 있음
이번에는 StandardScaler를 이용하여 bmi, age, children 스케일링 진행!
charges의 경우 출력값이어야 되기 때문에 스케일링 하지 않는다.

from sklearn.preprocessing import StandardScaler
encoded_columns = list(set(insurance_encoded.columns) - set(insurance_data.columns)) # ['region_southwest', 'region_southeast', 'region_northwest', 'smoker_yes', 'sex_male']
continuous_columns = list(set(insurance_encoded.columns) - set(encoded_columns) - set(y_column)) # ['bmi', 'age', 'children']
scaler = StandardScaler()
# 수치형 데이터만 스케일링 진행
X_train_continuous = scaler.fit_transform(X_train[continuous_columns])
X_test_continuous = scaler.fit_transform(X_test[continuous_columns])
# 스케일 된 데이터와 스케일에 사용되지 않은 데이터 조합
X_train_continuous_df = pd.DataFrame(X_train_continuous, columns=continuous_columns)
X_test_continuous_df = pd.DataFrame(X_test_continuous, columns=continuous_columns)
X_train_categorical_df = X_train[encoded_columns].reset_index(drop=True)
X_test_categorical_df = X_test[encoded_columns].reset_index(drop=True)
X_train_final = pd.concat([X_train_continuous_df, X_train_categorical_df], axis=1)
X_test_final = pd.concat([X_test_continuous_df, X_test_categorical_df], axis=1)

각자 다른 범주의 값이 비슷한 분포로 바뀌게 된다