211 KiB
- Определить бизнес-цели Бизнес-цели: а. Прогнозирование цены страховки б. Оценка влияния данных страхователя на цену страховки
- Определить цели технического проета для каждой бизнес-цели а. Построить можедь, которая на основе данных страхователя будет предсказывать цену страховки б. Провести анализ для выявления факторов, которые наиболее сильно влияют на итоговую цену страховки
- Подготовка данных
import pandas as pd
df = pd.read_csv("../dataset.csv")
print(df.shape[0])
данных достаточно чтобы шумы усреднились
print("было ", df.shape[0])
for column in df.select_dtypes(include=['int', 'float']).columns:
mean = df[column].mean()
std_dev = df[column].std()
print(column, mean, std_dev)
lower_bound = mean - 3 * std_dev
upper_bound = mean + 3 * std_dev
df = df[(df[column] <= upper_bound) & (df[column] >= lower_bound)]
print("стало ", df.shape[0])
df = df.reset_index(drop=True)
были устранены выбросы, отобранные по правилу трех сигм
print(df.isnull().sum())
Пропущенных значений нет
- Разбиение на выборки
from sklearn.model_selection import train_test_split
train_df, temp_df = train_test_split(df, test_size=0.3, random_state=52)
val_df, test_df = train_test_split(temp_df, test_size=0.5, random_state=52)
print(train_df.shape[0], val_df.shape[0], test_df.shape[0])
print(df.shape[0], train_df.shape[0] + val_df.shape[0] + test_df.shape[0])
test_df = test_df.reset_index(drop=True)
val_df = val_df.reset_index(drop=True)
train_df = train_df.reset_index(drop=True)
данные были разделены на обучающую (70%), контрольную (15%) и тестовую (15%) выборки
- Оценка сбалансированности выборок
import matplotlib.pyplot as plt
import seaborn as sns
def draw(data, title):
sns.histplot(data['charges'], kde=True)
plt.title(title)
plt.show()
draw(train_df, 'Распределение цен в обучающей выборке')
draw(val_df, 'Распределение цен в контрольной выборке')
draw(test_df, 'Распределение цен в тестовой выборке')
6,7. Конструирование признаков
print(df['region'].unique())
print(df['children'].unique())
from sklearn.preprocessing import OneHotEncoder
import numpy as np
encoder = OneHotEncoder(sparse_output=False, drop="first")
encoded_values = encoder.fit_transform(train_df[["smoker", "sex", "region", "children"]])
encoded_columns = encoder.get_feature_names_out(["smoker", "sex", "region", "children"])
encoded_values_df = pd.DataFrame(encoded_values, columns=encoded_columns)
train_df = pd.concat([train_df, encoded_values_df], axis=1)
encoded_values = encoder.fit_transform(test_df[["smoker", "sex", "region", "children"]])
encoded_columns = encoder.get_feature_names_out(["smoker", "sex", "region", "children"])
encoded_values_df = pd.DataFrame(encoded_values, columns=encoded_columns)
test_df = pd.concat([test_df, encoded_values_df], axis=1)
encoded_values = encoder.fit_transform(val_df[["smoker", "sex", "region", "children"]])
encoded_columns = encoder.get_feature_names_out(["smoker", "sex", "region", "children"])
encoded_values_df = pd.DataFrame(encoded_values, columns=encoded_columns)
val_df = pd.concat([val_df, encoded_values_df], axis=1)
print(test_df.columns)
print(val_df.columns)
print(train_df.columns)
Было совершено унитарное кодирование признаков Пол (sex), Курильщик (smoker) и Регион (region). Полученные признаки были добавлены в исходный сет.
print('age', min(df['age']), max(df['age']))
#print('charges', min(df['charges']), max(df['charges']))
print('bmi', min(df['bmi']), max(df['bmi']))
labels_age = ['young', 'middle-aged', 'old']
labels_bmi = ['underweight', 'normal weight', 'overweight']
#labels_charges = ['low_charges', 'medium_charges', 'high_charges']
hist_age, bins_age = np.histogram(test_df['age'], bins = [0, 27, 45, 100])
age_df = pd.concat([test_df['age'], pd.cut(test_df['age'], list(bins_age), labels = labels_age)], axis=1)
test_df['age_category'] = pd.cut(test_df['age'], bins=bins_age, labels=labels_age)
hist_bmi, bins_bmi = np.histogram(test_df['bmi'], bins = [0, 18.5, 25, 100])
bmi_df = pd.concat([test_df['bmi'], pd.cut(test_df['bmi'], list(bins_bmi), labels = labels_bmi)], axis=1)
test_df['bmi_category'] = pd.cut(test_df['bmi'], bins=bins_bmi, labels=labels_bmi)
hist_age, bins_age = np.histogram(train_df['age'], bins = [0, 27, 45, 100])
age_df = pd.concat([train_df['age'], pd.cut(train_df['age'], list(bins_age), labels = labels_age)], axis=1)
train_df['age_category'] = pd.cut(train_df['age'], bins=bins_age, labels=labels_age)
hist_bmi, bins_bmi = np.histogram(train_df['bmi'], bins = [0, 18.5, 25, 100])
bmi_df = pd.concat([train_df['bmi'], pd.cut(train_df['bmi'], list(bins_bmi), labels = labels_bmi)], axis=1)
train_df['bmi_category'] = pd.cut(train_df['bmi'], bins=bins_bmi, labels=labels_bmi)
hist_age, bins_age = np.histogram(val_df['age'], bins = [0, 27, 45, 100])
age_df = pd.concat([val_df['age'], pd.cut(val_df['age'], list(bins_age), labels = labels_age)], axis=1)
val_df['age_category'] = pd.cut(val_df['age'], bins=bins_age, labels=labels_age)
hist_bmi, bins_bmi = np.histogram(val_df['bmi'], bins = [0, 18.5, 25, 100])
bmi_df = pd.concat([val_df['bmi'], pd.cut(val_df['bmi'], list(bins_bmi), labels = labels_bmi)], axis=1)
val_df['bmi_category'] = pd.cut(val_df['bmi'], bins=bins_bmi, labels=labels_bmi)
category_counts = val_df['bmi_category'].value_counts()
print(category_counts)
print('========================')
category_counts = test_df['bmi_category'].value_counts()
print(category_counts)
print('========================')
category_counts = train_df['bmi_category'].value_counts()
print(category_counts)
Была выполнена дискретизация числовых признаков Индекс массы тела (bmi) и Возраст (age)
train_df['parent_yes'] = train_df['children'] > 0
train_df['parent_yes'] = train_df['parent_yes'].map({True: 1.0, False: 0.0})
test_df['parent_yes'] = test_df['children'] > 0
test_df['parent_yes'] = test_df['parent_yes'].map({True: 1.0, False: 0.0})
val_df['parent_yes'] = val_df['children'] > 0
val_df['parent_yes'] = val_df['parent_yes'].map({True: 1.0, False: 0.0})
print(train_df['parent_yes'].head(20))
print('========================')
print(test_df['parent_yes'].head(20))
print('========================')
print(val_df['parent_yes'].head(20))
Был выполнен ручной синтез признака Родитель, на основе того, есть ли дети у страхователя или нет
from sklearn import preprocessing
scaler = preprocessing.MinMaxScaler()
test_df['age_norm'] = scaler.fit_transform(test_df[['age']])
print(test_df['age_norm'].head(10))
print('========================')
train_df['age_norm'] = scaler.fit_transform(train_df[['age']])
print(train_df['age_norm'].head(10))
print('========================')
val_df['age_norm'] = scaler.fit_transform(val_df[['age']])
print(val_df['age_norm'].head(10))
Было выполнено маштабирование признака Возраст (age) на основе нормировки.
scaler = preprocessing.StandardScaler()
train_df['age_stand'] = scaler.fit_transform(train_df[['age']])
print(train_df['age_stand'].head(10))
print('========================')
test_df['age_stand'] = scaler.fit_transform(test_df[['age']])
print(test_df['age_stand'].head(10))
print('========================')
val_df['age_stand'] = scaler.fit_transform(val_df[['age']])
print(val_df['age_stand'].head(10))
Было выполнено маштабирование признака Возраст (age) на основе стандартизации.
- Использование Featuretools
import featuretools as ft
es = ft.EntitySet(id='insurance')
es = es.add_dataframe(dataframe_name="insurance_data", dataframe=df, index='index')
agg_primitives = ["sum", "mean", "median", "std", "max", "min", "count"]
trans_primitives = ["add_numeric", "multiply_numeric", "divide_numeric", "subtract_numeric"]
feature_matrix, feature_defs = ft.dfs(
entityset=es,
target_dataframe_name='insurance_data',
agg_primitives=agg_primitives,
trans_primitives=trans_primitives,
max_depth=2
)
feature_matrix
Были сконструированы признаки с помощью Featuretools
train_X = train_df.drop("charges", axis=1)
train_Y = train_df['charges']
test_X = test_df.drop("charges", axis=1)
test_Y = test_df['charges']
val_X = val_df.drop("charges", axis=1)
val_Y = val_df['charges']
train_X = train_X.drop(['smoker', 'sex', 'region', 'age_category', 'bmi_category'], axis=1)
test_X = test_X.drop(['smoker', 'sex', 'region', 'age_category', 'bmi_category'], axis=1)
val_X = val_X.drop(['smoker', 'sex', 'region', 'age_category', 'bmi_category'], axis=1)
print(train_X.columns)
from sklearn.linear_model import LinearRegression
import time
from sklearn.metrics import mean_squared_error, r2_score
model = LinearRegression()
start_time = time.time()
model.fit(train_X, train_Y)
train_time = time.time() - start_time
val_predictions = model.predict(val_X)
mse = mean_squared_error(val_Y, val_predictions)
r2 = r2_score(val_Y, val_predictions)
print(train_time, mse, r2)
plt.scatter(val_Y, val_predictions, alpha=0.5)
plt.plot([val_Y.min(), val_Y.max()], [val_Y.min(), val_Y.max()], 'k--', lw=1)
plt.xlabel('Фактическая цена')
plt.ylabel('Прогнозируемая цена')
Обученная модель довольно точно предсказывает цены ниже двух тысяч, для цен более двух тысяч модель занижает или завышает цены