Python贝叶斯心脏预测,结果不准确
Posted
技术标签:
【中文标题】Python贝叶斯心脏预测,结果不准确【英文标题】:Python Bayes heart prediction, results are not accurate 【发布时间】:2017-11-18 16:05:12 【问题描述】:我正在尝试使用朴素贝叶斯制作心脏病预测程序。当我完成分类器时,交叉验证显示平均准确率为 80% 但是当我尝试对给定样本进行预测时,预测全错了!该数据集是来自 UCI 存储库的心脏病数据集,它包含 303 个样本。有两类 0:健康和 1:生病,当我尝试对数据集中的样本进行预测时,除了极少数样本外,它不会预测其真实值。代码如下:
import pandas as pd
import numpy as np
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import cross_val_score, train_test_split
from sklearn.preprocessing import Imputer, StandardScaler
class Predict:
def Read_Clean(self,dataset):
header_row = ['Age', 'Gender', 'Chest_Pain', 'Resting_Blood_Pressure', 'Serum_Cholestrol',
'Fasting_Blood_Sugar', 'Resting_ECG', 'Max_Heart_Rate',
'Exercise_Induced_Angina', 'OldPeak',
'Slope', 'CA', 'Thal', 'Num']
df = pd.read_csv(dataset, names=header_row)
df = df.replace('[?]', np.nan, regex=True)
df = pd.DataFrame(Imputer(missing_values='NaN', strategy='mean', axis=0)
.fit_transform(df), columns=header_row)
df = df.astype(float)
return df
def Train_Test_Split_data(self,dataset):
Y = dataset['Num'].apply(lambda x: 1 if x > 0 else 0)
X = dataset.drop('Num', axis=1)
validation_size = 0.20
seed = 42
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=validation_size, random_state=seed)
return X_train, X_test, Y_train, Y_test
def Scaler(self, X_train, X_test):
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
return X_train, X_test
def Cross_Validate(self, clf, X_train, Y_train, cv=5):
scores = cross_val_score(clf, X_train, Y_train, cv=cv, scoring='f1')
score = scores.mean()
print("CV scores mean: %.4f " % (score))
return score, scores
def Fit_Score(self, clf, X_train, Y_train, X_test, Y_test, label='x'):
clf.fit(X_train, Y_train)
fit_score = clf.score(X_train, Y_train)
pred_score = clf.score(X_test, Y_test)
print("%s: fit score %.5f, predict score %.5f" % (label, fit_score, pred_score))
return pred_score
def ReturnPredictionValue(self, clf, sample):
y = clf.predict([sample])
return y[0]
def PredictionMain(self, sample, dataset_path='dataset/processed.cleveland.data'):
data = self.Read_Clean(dataset_path)
X_train, X_test, Y_train, Y_test = self.Train_Test_Split_data(data)
X_train, X_test = self.Scaler(X_train, X_test)
self.NB = GaussianNB()
self.Fit_Score(self.NB, X_train, Y_train, X_test, Y_test, label='NB')
self.Cross_Validate(self.NB, X_train, Y_train, 10)
return self.ReturnPredictionValue(self.NB, sample)
当我跑步时:
if __name__ == '__main__':
sample = [41.0, 0.0, 2.0, 130.0, 204.0, 0.0, 2.0, 172.0, 0.0, 1.4, 1.0, 0.0, 3.0]
p = Predict()
print "Prediction value: ".format(p.PredictionMain(sample))
结果是:
NB:拟合分数 0.84711,预测分数 0.83607 CV 分数均值:0.8000
预测值:1
我得到 1 而不是 0(这个样本已经是数据集样本之一)。 我对数据集中的多个样本进行了此操作,并且大多数时候我得到错误的结果,就好像准确率不是 80%!
任何帮助将不胜感激。 提前致谢。
编辑: 使用管道解决了问题。最终代码为:
import pandas as pd
import numpy as np
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import cross_val_score, train_test_split
from sklearn.preprocessing import Imputer, StandardScaler, OneHotEncoder
from sklearn.pipeline import Pipeline
class Predict:
def __init__(self):
self.X = []
self.Y = []
def Read_Clean(self,dataset):
header_row = ['Age', 'Gender', 'Chest_Pain', 'Resting_Blood_Pressure', 'Serum_Cholestrol',
'Fasting_Blood_Sugar', 'Resting_ECG', 'Max_Heart_Rate',
'Exercise_Induced_Angina', 'OldPeak',
'Slope', 'CA', 'Thal', 'Num']
df = pd.read_csv(dataset, names=header_row)
df = df.replace('[?]', np.nan, regex=True)
df = pd.DataFrame(Imputer(missing_values='NaN', strategy='mean', axis=0)
.fit_transform(df), columns=header_row)
df = df.astype(float)
return df
def Split_Dataset(self, df):
self.Y = df['Num'].apply(lambda x: 1 if x > 0 else 0)
self.X = df.drop('Num', axis=1)
def Create_Pipeline(self):
estimators = []
estimators.append(('standardize', StandardScaler()))
estimators.append(('bayes', GaussianNB()))
model = Pipeline(estimators)
return model
def Cross_Validate(self, clf, cv=5):
scores = cross_val_score(clf, self.X, self.Y, cv=cv, scoring='f1')
score = scores.mean()
print("CV scores mean: %.4f " % (score))
def Fit_Score(self, clf, label='x'):
clf.fit(self.X, self.Y)
fit_score = clf.score(self.X, self.Y)
print("%s: fit score %.5f" % (label, fit_score))
def ReturnPredictionValue(self, clf, sample):
y = clf.predict([sample])
return y[0]
def PredictionMain(self, sample, dataset_path='dataset/processed.cleveland.data'):
print "dataset: "+ dataset_path
data = self.Read_Clean(dataset_path)
self.Split_Dataset(data)
self.model = self.Create_Pipeline()
self.Fit_Score(self.model, label='NB')
self.Cross_Validate(self.model, 10)
return self.ReturnPredictionValue(self.model, sample)
现在对问题中的相同样本进行预测会返回 [0],这是真实值。实际上通过运行以下方法:
def CheckTrue(self):
clf = self.Create_Pipeline()
out = cross_val_predict(clf, self.X, self.Y)
p = [out == self.Y]
c = 0
for i in range(303):
if p[0][i] == True:
c += 1
print "Samples with true values: ".format(c)
我使用管道代码获得了 249 个真实样本,而之前我只获得了 150 个。
【问题讨论】:
大多数时候结果都是错误的 - 你能量化整个样本或多个子集吗?对单个数据点进行测试(在ReturnPredictionValue
中返回 y[0]
)可能不足以得出任何具有约束力的结论,无论您的分类器是否有效。 旁注: 你的代码都很好地包装在一个类中,但是方法就像函数一样,即你几乎没有在Predict
属性中存储任何信息。将来,充分利用 OOP 的强大功能可能会节省您的时间。
实际上我编写了一个小代码来计算真实值,它们是 303 中的 150,准确度不是 80%。谢谢你的建议,你是对的,我真的没有注意到。
【参考方案1】:
您没有将 StandardScaler 应用于示例。分类器需要在 StandardScaler.transform 输出上训练的缩放数据,但样本的缩放方式与训练中不同。
手动组合多个步骤(缩放、预处理、分类)时很容易犯这样的错误。为避免此类问题,最好使用 scikit-learn Pipeline。
【讨论】:
感谢Pipeline,我遇到了它,但从没想过它可以解决我的问题,更不用说减少代码了,非常感谢!但是我仍然不知道我的代码出了什么问题,我在将 X_train 和 X_test 提供给分类器之前对其进行了缩放:X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
您已经扩展了 X_train
和 X_test
(这就是交叉验证中质量很好的原因),但不是 sample
(==> 个别示例质量差)。
我明白了,谢谢!但是使用管道我没有缩放样本并且效果很好。它是否也处理样本缩放?
管道确保应用所有步骤 - 您已经使用 StandardScaler 和 GaussianNB 创建了一个管道,因此它们都适用于训练和测试。以上是关于Python贝叶斯心脏预测,结果不准确的主要内容,如果未能解决你的问题,请参考以下文章
如何在 python 的朴素贝叶斯分类器中对用户输入测试集进行分类?
数据分享|R语言逻辑回归Naive Bayes贝叶斯决策树随机森林算法预测心脏病|附代码数据