一、基于PaddlePaddle的中风患者线性模型预测
1.背景描述
中风是一种医学疾病,由于流向大脑的血液不足导致细胞死亡。中风主要有两种类型:缺血性中风(缺乏血液流动导致)和出血性中风(出血导致)。两者都会导致大脑的某些部分停止正常运作。
中风的体征和症状可能包括一侧身体无法移动或感觉,理解或说话问题,头晕或一侧视力丧失。症状和体征通常在中风发生后不久就会出现。
如果症状持续不到一两个小时,中风就是短暂性脑缺血发作(TIA),也称为小中风。
出血性中风还可能伴有严重的头痛。中风的症状可能是永久性的。长期并发症可能包括肺炎和膀胱失控。
中风的主要危险因素是高血压。
其他危险因素包括高血胆固醇、吸烟、肥胖、糖尿病、以前的TIA、终末期肾病和心房颤动。
缺血性中风通常是由血管堵塞引起的,尽管也有一些不太常见的原因。
出血性中风是由出血直接进入大脑或进入大脑膜之间的空间引起的。
出血可能是由于脑动脉瘤破裂引起的。诊断通常基于身体检查,并辅以医学成像,如CT扫描或MRI扫描。
CT扫描可以排除出血,但不一定排除缺血,早期的CT扫描通常不会显示缺血。其他检查,如心电图(ECG)和血液检查,以确定危险因素和排除其他可能的原因。低血糖也可能引起类似的症状。
2.数据说明
《中国成人超重和肥胖症预防控制指南》的BMI分类:
| BMI | 身体质量指数说明 |
|---|---|
| < 18.5 | 体重过轻 |
| 18.5 - 23.9 | 体重正常 |
| 24 - 27.9 | 超重 |
| > 28 | 肥胖 |
-
血糖水平
正常空腹血糖浓度的预期值介于 70 mg/dL 到 100 mg/dL 之间。或:3.9 mmol/L 和 5.6 mmol/L 之间
二、数据分析
1.基础分析
import numpy as np
import pandas as pd
data = pd.read_csv('data/data225165/brain_stroke.csv',encoding='gbk')
data.head()
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
| 性别 | 年龄 | 是否患有高血压 | 是否患有心脏病 | 是否有过婚姻 | 工作类型 | 住宅类型 | 血糖水平 | BMI | 吸烟状况 | 是否中风 | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 男性 | 67.0 | 0 | 1 | 1 | 私人企业 | 城市 | 228.69 | 36.6 | 以前吸烟 | 1 |
| 1 | 男性 | 80.0 | 0 | 1 | 1 | 私人企业 | 农村 | 105.92 | 32.5 | 从不吸烟 | 1 |
| 2 | 女性 | 49.0 | 0 | 0 | 1 | 私人企业 | 城市 | 171.23 | 34.4 | 吸烟 | 1 |
| 3 | 女性 | 79.0 | 1 | 0 | 1 | 自雇人士 | 农村 | 174.12 | 24.0 | 从不吸烟 | 1 |
| 4 | 男性 | 81.0 | 0 | 0 | 1 | 私人企业 | 城市 | 186.21 | 29.0 | 以前吸烟 | 1 |
data[data.duplicated()]
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
| 性别 | 年龄 | 是否患有高血压 | 是否患有心脏病 | 是否有过婚姻 | 工作类型 | 住宅类型 | 血糖水平 | BMI | 吸烟状况 | 是否中风 |
|---|
data.isnull().sum()
性别 0
年龄 0
是否患有高血压 0
是否患有心脏病 0
是否有过婚姻 0
工作类型 0
住宅类型 0
血糖水平 0
BMI 0
吸烟状况 0
是否中风 0
dtype: int64
data.shape
(4981, 11)
# 判断data中各个字段的取值是否与数据字典中一致
# 以及判断是否存在额外的空值,如空格表示的空值
for column in data.columns:
print(column + ":" + str(data[column].unique()))
性别:['男性' '女性']
年龄:[6.70e+01 8.00e+01 4.90e+01 7.90e+01 8.10e+01 7.40e+01 6.90e+01 7.80e+01 6.10e+01 5.40e+01 5.00e+01 6.40e+01 7.50e+01 6.00e+01 7.10e+01 5.20e+01 8.20e+01 6.50e+01 5.70e+01 4.20e+01 4.80e+01 7.20e+01 5.80e+01 7.60e+01 3.90e+01 7.70e+01 6.30e+01 7.30e+01 5.60e+01 4.50e+01 7.00e+01 5.90e+01 6.60e+01 4.30e+01 6.80e+01 4.70e+01 5.30e+01 3.80e+01 5.50e+01 4.60e+01 3.20e+01 5.10e+01 1.40e+01 3.00e+00 8.00e+00 3.70e+01 4.00e+01 3.50e+01 2.00e+01 4.40e+01 2.50e+01 2.70e+01 2.30e+01 1.70e+01 1.30e+01 4.00e+00 1.60e+01 2.20e+01 3.00e+01 2.90e+01 1.10e+01 2.10e+01 1.80e+01 3.30e+01 2.40e+01 3.60e+01 6.40e-01 3.40e+01 4.10e+01 8.80e-01 5.00e+00 2.60e+01 3.10e+01 7.00e+00 1.20e+01 6.20e+01 2.00e+00 9.00e+00 1.50e+01 2.80e+01 1.00e+01 1.80e+00 3.20e-01 1.08e+00 1.90e+01 6.00e+00 1.16e+00 1.00e+00 1.40e+00 1.72e+00 2.40e-01 1.64e+00 1.56e+00 7.20e-01 1.88e+00 1.24e+00 8.00e-01 4.00e-01 8.00e-02 1.48e+00 5.60e-01 1.32e+00 1.60e-01 4.80e-01]
是否患有高血压:[0 1]
是否患有心脏病:[1 0]
是否有过婚姻:[1 0]
工作类型:['私人企业' '自雇人士' '政府部门' '儿童']
住宅类型:['城市' '农村']
血糖水平:[228.69 105.92 171.23 ... 191.15 95.02 83.94]
BMI:[36.6 32.5 34.4 24. 29. 27.4 22.8 24.2 29.7 36.8 27.3 28.2 30.9 37.5 25.8 37.8 22.4 48.9 26.6 27.2 23.5 28.3 44.2 25.4 22.2 30.5 26.5 33.7 23.1 32. 29.9 23.9 28.5 26.4 20.2 33.6 38.6 39.2 27.7 31.4 36.5 33.2 32.8 40.4 25.3 30.2 47.5 20.3 30. 28.9 28.1 31.1 21.7 27. 24.1 45.9 44.1 22.9 29.1 32.3 41.1 25.6 29.8 26.3 26.2 29.4 24.4 28. 28.8 34.6 19.4 30.3 41.5 22.6 27.1 31.3 31. 31.7 35.8 28.4 20.1 26.7 38.7 34.9 25. 23.8 21.8 27.5 24.6 32.9 26.1 31.9 34.1 36.9 37.3 45.7 34.2 23.6 22.3 37.1 45. 25.5 30.8 37.4 34.5 27.9 29.5 46. 42.5 35.5 26.9 45.5 31.5 33. 23.4 30.7 20.5 21.5 40. 28.6 42.2 29.6 35.4 16.9 26.8 39.3 32.6 35.9 21.2 42.4 40.5 36.7 29.3 19.6 18. 17.6 17.7 35. 22. 39.4 19.7 22.5 25.2 41.8 23.7 24.5 31.2 16. 31.6 25.1 24.8 18.3 20. 19.5 36. 35.3 40.1 43.1 21.4 34.3 27.6 16.5 24.3 25.7 21.9 38.4 25.9 18.6 24.9 48.2 20.7 39.5 23.3 35.1 43.6 21. 47.3 16.6 21.6 15.5 35.6 16.7 41.9 16.4 17.1 29.2 37.9 44.6 39.6 40.3 41.6 39. 23.2 18.9 36.1 36.3 46.5 16.8 46.6 35.2 20.9 31.8 15.3 38.2 45.2 17. 27.8 23. 22.1 26. 44.3 39.7 34.7 21.3 41.2 34.8 19.2 35.7 40.8 24.7 19. 32.4 34. 28.7 32.1 20.4 30.6 19.3 40.9 17.2 16.1 16.2 40.6 18.4 21.1 42.3 32.2 17.5 42.1 47.8 20.8 30.1 17.3 36.4 36.2 14.4 43. 41.7 33.8 43.9 22.7 18.7 37. 38.5 16.3 44. 32.7 40.2 33.3 17.4 41.3 14.6 17.8 46.1 33.1 18.1 43.8 38.9 43.7 39.9 15.9 19.8 38.3 41. 42.6 43.4 15.1 20.6 33.5 43.2 19.1 30.4 38. 33.4 44.9 44.7 37.6 39.8 42. 37.2 42.8 18.8 42.9 14.3 37.7 48.4 46.2 43.3 33.9 18.5 44.5 45.4 19.9 17.9 15.6 15.2 18.2 48.5 14.1 15.7 44.8 38.1 44.4 38.8 39.1 41.4 14.2 15.4 45.1 48.7 42.7 48.8 15.8 45.3 14.8 40.7 48. 46.8 48.3 14.5 15. 47.4 47.9 45.8 47.6 14. 46.4 46.9 47.1 48.1 46.3 14.9]
吸烟状况:['以前吸烟' '从不吸烟' '吸烟' '不详']
是否中风:[1 0]
三、特征处理
1.特征分类变量序列化
data.head()
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
| 性别 | 年龄 | 是否患有高血压 | 是否患有心脏病 | 是否有过婚姻 | 工作类型 | 住宅类型 | 血糖水平 | BMI | 吸烟状况 | 是否中风 | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 男性 | 67.0 | 0 | 1 | 1 | 私人企业 | 城市 | 228.69 | 36.6 | 以前吸烟 | 1 |
| 1 | 男性 | 80.0 | 0 | 1 | 1 | 私人企业 | 农村 | 105.92 | 32.5 | 从不吸烟 | 1 |
| 2 | 女性 | 49.0 | 0 | 0 | 1 | 私人企业 | 城市 | 171.23 | 34.4 | 吸烟 | 1 |
| 3 | 女性 | 79.0 | 1 | 0 | 1 | 自雇人士 | 农村 | 174.12 | 24.0 | 从不吸烟 | 1 |
| 4 | 男性 | 81.0 | 0 | 0 | 1 | 私人企业 | 城市 | 186.21 | 29.0 | 以前吸烟 | 1 |
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
# 除去序号列
columns=data.columns
print(len(columns))
for column in columns:
print(column)
11
性别
年龄
是否患有高血压
是否患有心脏病
是否有过婚姻
工作类型
住宅类型
血糖水平
BMI
吸烟状况
是否中风
label_colum_encoder = ['性别', '工作类型', '住宅类型', '吸烟状况' ]
for column in label_colum_encoder:
print(f"完成 {column} 列序列化")
data[column]=le.fit_transform(data[column])
完成 性别 列序列化
完成 工作类型 列序列化
完成 住宅类型 列序列化
完成 吸烟状况 列序列化
data.head()
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
| 性别 | 年龄 | 是否患有高血压 | 是否患有心脏病 | 是否有过婚姻 | 工作类型 | 住宅类型 | 血糖水平 | BMI | 吸烟状况 | 是否中风 | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 67.0 | 0 | 1 | 1 | 2 | 1 | 228.69 | 36.6 | 2 | 1 |
| 1 | 1 | 80.0 | 0 | 1 | 1 | 2 | 0 | 105.92 | 32.5 | 1 | 1 |
| 2 | 0 | 49.0 | 0 | 0 | 1 | 2 | 1 | 171.23 | 34.4 | 3 | 1 |
| 3 | 0 | 79.0 | 1 | 0 | 1 | 3 | 0 | 174.12 | 24.0 | 1 | 1 |
| 4 | 1 | 81.0 | 0 | 0 | 1 | 2 | 1 | 186.21 | 29.0 | 2 | 1 |
2.数据标准化
columns=['年龄','工作类型','血糖水平','BMI','吸烟状况']
for column in columns:
col = data[column]
col_min = col.min()
col_max = col.max()
normalized = (col - col_min) / (col_max - col_min)
data[column] = normalized
data.head()
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
| 性别 | 年龄 | 是否患有高血压 | 是否患有心脏病 | 是否有过婚姻 | 工作类型 | 住宅类型 | 血糖水平 | BMI | 吸烟状况 | 是否中风 | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0.816895 | 0 | 1 | 1 | 0.666667 | 1 | 0.801265 | 0.647564 | 0.666667 | 1 |
| 1 | 1 | 0.975586 | 0 | 1 | 1 | 0.666667 | 0 | 0.234512 | 0.530086 | 0.333333 | 1 |
| 2 | 0 | 0.597168 | 0 | 0 | 1 | 0.666667 | 1 | 0.536008 | 0.584527 | 1.000000 | 1 |
| 3 | 0 | 0.963379 | 1 | 0 | 1 | 1.000000 | 0 | 0.549349 | 0.286533 | 0.333333 | 1 |
| 4 | 1 | 0.987793 | 0 | 0 | 1 | 0.666667 | 1 | 0.605161 | 0.429799 | 0.666667 | 1 |
3.数据集切分
from sklearn.model_selection import train_test_split
# 切分数据集为 训练集 、 测试集
train, test = train_test_split(data, test_size=0.2, random_state=2023)
3.协相关
data.corr()
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
| 性别 | 年龄 | 是否患有高血压 | 是否患有心脏病 | 是否有过婚姻 | 工作类型 | 住宅类型 | 血糖水平 | BMI | 吸烟状况 | 是否中风 | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 性别 | 1.000000 | -0.026538 | 0.021485 | 0.086476 | -0.028971 | -0.075975 | -0.004301 | 0.055796 | -0.012093 | -0.000653 | 0.008870 |
| 年龄 | -0.026538 | 1.000000 | 0.278120 | 0.264852 | 0.677137 | 0.583042 | 0.017155 | 0.236763 | 0.373703 | 0.305230 | 0.246478 |
| 是否患有高血压 | 0.021485 | 0.278120 | 1.000000 | 0.111974 | 0.164534 | 0.140098 | -0.004755 | 0.170028 | 0.158762 | 0.104703 | 0.131965 |
| 是否患有心脏病 | 0.086476 | 0.264852 | 0.111974 | 1.000000 | 0.114765 | 0.108356 | 0.002125 | 0.166847 | 0.060926 | 0.085429 | 0.134610 |
| 是否有过婚姻 | -0.028971 | 0.677137 | 0.164534 | 0.114765 | 1.000000 | 0.455567 | 0.008191 | 0.150724 | 0.371690 | 0.287190 | 0.108398 |
| 工作类型 | -0.075975 | 0.583042 | 0.140098 | 0.108356 | 0.455567 | 1.000000 | 0.004053 | 0.100118 | 0.378679 | 0.318605 | 0.091301 |
| 住宅类型 | -0.004301 | 0.017155 | -0.004755 | 0.002125 | 0.008191 | 0.004053 | 1.000000 | 0.001346 | 0.013185 | 0.026798 | 0.016494 |
| 血糖水平 | 0.055796 | 0.236763 | 0.170028 | 0.166847 | 0.150724 | 0.100118 | 0.001346 | 1.000000 | 0.186348 | 0.079654 | 0.133227 |
| BMI | -0.012093 | 0.373703 | 0.158762 | 0.060926 | 0.371690 | 0.378679 | 0.013185 | 0.186348 | 1.000000 | 0.245660 | 0.056926 |
| 吸烟状况 | -0.000653 | 0.305230 | 0.104703 | 0.085429 | 0.287190 | 0.318605 | 0.026798 | 0.079654 | 0.245660 | 1.000000 | 0.054793 |
| 是否中风 | 0.008870 | 0.246478 | 0.131965 | 0.134610 | 0.108398 | 0.091301 | 0.016494 | 0.133227 | 0.056926 | 0.054793 | 1.000000 |
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
sns.set_style('whitegrid')
# 热力图
plt.figure(figsize=(20,12))
sns.heatmap(train.corr(), annot=True)
<matplotlib.axes._subplots.AxesSubplot at 0x7f3592d83dd0>
四、模型训练
1.网络定义
import paddle
import paddle.nn.functional as F
# 定义动态图
class Net(paddle.nn.Layer):
def __init__(self):
super(Net, self).__init__()
# 定义一层全连接层,输出维度是1,激活函数为None,即不使用激活函数
self.fc = paddle.nn.Linear(in_features=10,out_features=2)
# 网络的前向计算函数
def forward(self, inputs):
pred = self.fc(inputs)
return pred
net=Net()
2.超参设置
# 设置迭代次数
epochs = 6
# paddle.nn.loss.CrossEntropyLoss正常
# paddle.nn.CrossEntropyLoss不正常
loss_func = paddle.nn.CrossEntropyLoss()
#优化器
opt = paddle.optimizer.Adam(learning_rate=0.1,parameters=net.parameters())
3.模型训练
#训练程序
for epoch in range(epochs):
all_acc = 0
for i in range(train.shape[0]):
x = paddle.to_tensor([train.iloc[i,:-1]])
y = paddle.to_tensor([train.iloc[i,-1]])
infer_y = net(x)
loss = loss_func(infer_y,y)
loss.backward()
y=label = paddle.to_tensor([y], dtype="int64")
acc= paddle.metric.accuracy(infer_y, y)
all_acc=all_acc+acc.numpy()
opt.step()
opt.clear_gradients#清除梯度
# print("epoch: {}, loss is: {},acc is:{}".format(epoch, loss.numpy(),acc.numpy())) #由于输出过长,这里注释掉了
print("第{}次正确率为:{}".format(epoch+1,all_acc/i))
第1次正确率为:[0.906352]
第2次正确率为:[0.913884]
第3次正确率为:[0.9131308]
第4次正确率为:[0.9131308]
第5次正确率为:[0.9199096]
第6次正确率为:[0.9113733]
五、模型评估
1.评估
#测试集数据运行
net.eval()#模型转换为测试模式
all_acc = 0
for i in range(test.shape[0]):
x = paddle.to_tensor([test.iloc[i,:-1]])
y = paddle.to_tensor([test.iloc[i,-1]])
infer_y = net(x)
y=label = paddle.to_tensor([y], dtype="int64")
# 计算损失与精度
loss = loss_func(infer_y, y)
acc = paddle.metric.accuracy(infer_y, y)
all_acc = all_acc+acc.numpy()
# 打印信息
#print("loss is: {}, acc is: {}".format(loss.numpy(), acc.numpy()))
print("测试集正确率:{}".format(all_acc/i))
测试集正确率:[0.87650603]
2.预测
#预测结果展示
net.eval()
x = paddle.to_tensor([test.iloc[0,:-1]])
y = paddle.to_tensor([test.iloc[0,-1]])
infer_y = net(x)
y=label = paddle.to_tensor([y], dtype="int64")
# 计算损失与精度
loss = loss_func(infer_y, y)
# 打印信息
print("test[0] is :{}\n y_test[0] is :{}\n predict is {}".format(test.iloc[0,:-1] ,test.iloc[0,-1], np.argmax(infer_y.numpy()[0])))
test[0] is :性别 0.000000
年龄 0.218750
是否患有高血压 0.000000
是否患有心脏病 0.000000
是否有过婚姻 0.000000
工作类型 0.666667
住宅类型 1.000000
血糖水平 0.202613
BMI 0.329513
吸烟状况 0.666667
Name: 4121, dtype: float64
y_test[0] is :0
predict is 0
六、注意事项
paddle.metric.accuracy使用时要注意维度对齐,不然会出错。
例如这里给他套了一层:
y=label = paddle.to_tensor([y], dtype="int64")