在当今竞争激烈的市场中,保险公司的利润来源于收到的保费与支付的索赔之间的差额。本文旨在为那些希望利用传统机器学习解决现实问题的人提供一个良好的起点。手头有大约1338条观测数据(行)和7个特征(列),包括年龄、性别、BMI(体重指数)、子女数量、所属地区以及是否吸烟。任务是揭示个人医疗费用与家庭状况、健康因素或居住地点之间可能存在的关系。
在开始探索数据之前,必须记住“垃圾进,垃圾出”的原则。即使使用最好的机器学习模型,如果数据质量不佳,结果也不会理想。因此,进行彻底的数据分析至关重要。从左侧的计数图中可以了解到,数据中非吸烟者比吸烟者多。尽管如此,从右侧的图中可以看出,吸烟者的医疗费用高于非吸烟者。可以清楚地看到特征“吸烟者”与目标“医疗费用”之间的模式。
让来看下一个特征,子女数量(表示一个人有多少子女)。在绘制上述图表之前,认为随着子女数量的增加,医疗费用也会增加,但数据并不支持最初的假设。从右侧的散点图中可以看到,有些情况下,没有子女的观测值的医疗费用比有5个子女的观测值还要高。数据在“子女”特征上也是不平衡的,从左侧的计数图中观察到,拥有0个子女的人最多,拥有5个子女的人最少。
继续可视化“年龄”和“BMI”特征。左侧的图表建立了年龄与费用之间的直接比例关系,随着年龄的增长,可以看到在大多数情况下费用也在增加。BMI和费用的折线图右侧并没有显示出任何模式,可以看到一些BMI较高但费用较低的情况,对于BMI特征,可以确定的是数据中的最低值是15,最高值达到60。
需要查看的最后一个特征是“性别”。上面的计数图显示,就性别而言,数据是平衡的。男性和女性的数量几乎相等。为了进一步了解输入特征(年龄、BMI、地区、性别、吸烟者)对目标变量费用的影响,绘制了一个相关性矩阵。从上面的相关性矩阵中,建立了以下结论:费用与年龄之间的相关性最高,其次是吸烟者和费用;BMI和费用也显示出良好的相关性。让进一步使用这些来预测医疗费用。
在将数据输入模型之前,需要进行一些检查,换句话说,预处理数据。1. 处理缺失数据(参考:)。目前使用的数据集没有任何缺失数据,这就是为什么不需要执行这一步。2. 编码分类数据。机器学习模型只能处理数值数据,这就是为什么需要将数据集中的分类特征逻辑编码为数值。有许多方法可以执行编码,在这个案例研究中使用了sklearn库中的LabelEncoder。
from sklearn.preprocessing import LabelEncoder
label = LabelEncoder()
df.iloc[:,1] = label.fit_transform(df.iloc[:,1])
df.iloc[:,5] = label.fit_transform(df.iloc[:,5])
df.iloc[:,4] = label.fit_transform(df.iloc[:,4])
以上代码片段显示了使用LabelEncoder对分类特征地区、吸烟者和性别进行编码。在本文的末尾,也会提供整个笔记本供参考。
机器学习涉及大量的实验,尝试使用不同的特征组合,发现性别和地区特征对目标(费用)变量的贡献不大。考虑到这一点,将数据框架分为X和Y如下。
X = df[['bmi','age','smoker','children']]
Y = df['expenses']
使用sklearn内置的train_test_split函数,将数据分为训练和验证数据。为什么需要将数据分为训练和验证?简短的答案是为了避免过拟合并正确评估模型。有关详细解释,建议参考。
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.25)
问题是回归问题,因为试图预测费用,这是一个实数值。将为此任务使用DecisionTreeRegressor和LinearRegression模型。
from sklearn.tree import DecisionTreeRegressor
from sklearn.model_selection import cross_val_score
regressor = DecisionTreeRegressor(random_state=0)
#cross_val_score(regressor, X_train, y_train, cv=10)
regressor.fit(X_train, y_train)
y_predict = regressor.predict(X_test)
mse_dt = mean_squared_error(y_test, y_predict, squared=False)
print(mse_dt)
6900.60117589873
from sklearn.linear_model import LinearRegression
regressor = LinearRegression()
#cross_val_score(regressor, X_train, y_train, cv=10)
regressor.fit(X_train, y_train)
y_predict = regressor.predict(X_test)
mse_dt = mean_squared_error(y_test, y_predict, squared=False)
print(mse_dt)
5908.41334052373
使用线性回归得到的均方误差比决策树回归器低。可以通过使用网格搜索和随机搜索等超参数调整方法进一步降低MSE(均方误差)或提高模型性能。
!pip install gradio
import gradio as gr
def greet(bmi, age, smoker, children):
if smoker:
is_smoker = 1
else:
is_smoker = 0
X_test = pd.DataFrame.from_dict({'bmi':[bmi],'age':[age],'smoker':[is_smoker],'children':[children]})
print(X_test)
y_predict = regressor.predict(X_test)
print(y_predict)
return y_predict[0]
iface = gr.Interface(
fn=greet,
inputs=['text','text','checkbox','text'],
outputs="number")
iface.launch(share=True)