• Bayes决策:身高与体重特征进行性别分类


    代码与文件请从这里下载:Auorui/Pattern-recognition-programming: 模式识别编程 (github.com)

    简述

    分别依照身高、体重数据作为特征,在正态分布假设下利用最大似然法估计分布密度参数,建立最小错误率Bayes分类器,写出得到的决策规则,将该分类器应用到测试样本,考察测试错误情况。在分类器设计时考察采用不同先验概率(如0.5对0.5, 0.75对0.25, 0.9对0.1等)进行实验,考察对决策规则和错误率的影响。

    同时采用身高与体重数据作为特征,在正态分布假设下估计概率密度,建立最小错误率Bayes分类器,写出得到的决策规则,将该分类器应用到训练/测试样本,考察训练/测试错误情况。 比较相关假设和不相关假设下结果的差异。在分类器设计时可以考察采用不同先验概率进行实验,考察对决策和错误率的影响。

    最小错误率贝叶斯决策

    这里要对男性和女性的数据进行分类,先要求解先验概念P(x),这个概率是通过统计得到的,或者依据自身依据经验给出的一个概率值,所以这个值是可以进行设定的,可选择0.5对0.5,0.75对0.25,0.9对0.1这些进行测试。

    在贝叶斯统计中,后验概率是在考虑新信息之后事件发生的修正或更新概率。后验概率通过使用贝叶斯定理更新先验概率来计算。

    P(w_{i}|x)=\frac{p(x|w_{i})\times P(w_{i})}{p(x)}

    其中p(x)为x的概率密度函数,即是:

    p(x)=\sum_{i=1}^{2}p(x|w_{i})p(w_{i})

    贝叶斯决策可以使用下面的等式来等价表示为

    p(x|w_{1})P(w_{1})>p(x|w_{2})P(w_{2})

    如果满足上式条件,则x属于w_{1},否则就属于w_{2},这个就是最小错误贝叶斯决策规则。

    最小风险贝叶斯决策

    在实际的应用中,分类错误率最小并不一定是最好的标准,不同类别的分类错误可能会导致不同的后果。有时,某些类别的错误分类可能比其他类别更为严重。例如,在医疗诊断中,将疾病误诊为健康可能比将健康误诊为疾病更为严重。在有决策风险时候,根据风险重新选择区域R_{1}R_{2}从而使得P_{e}最小。与w_{k}相关的风险或损失定义为:

    r_{k}=\sum_{i=1}^{c}\lambda _{ki}\int_{R_{i}}p(x|w_{k})dx

    对于本数据,只有两类:

    l_{1}=\lambda _{11}p(x|w_{1})p(w_{1})+\lambda _{21}p(x|w_{2})p(w_{2})

    l_{2}=\lambda _{12}p(x|w_{1})p(w_{1})+\lambda _{22}p(x|w_{2})p(w_{2})

    l_{1}<l_{2},则x属于w_{i}类,即有

    (\lambda _{12}-\lambda _{11})p(x|w_{1})P(w_{1})>(\lambda _{21}-\lambda _{22})p(x|w_{2})P(w_{2})

    再经过简化,当w_{2}类的样本被错误的分类会产生更严重的后果,可设置为\lambda _{21}>\lambda _{12},所以若p(x|w_{2})>p(x|w_{1})\frac{\lambda _{12}}{\lambda _{21}},则判定为w_{2}类。

    数据预处理

    首先我们可以观察我们的数据:

    它大概是这样分布的,一行数据为身高和体重。你可以使用python文件按行读取进行数据清洗,这里可以直接使用np.loadtxt,它会返回一个二维的数组,使用切片的方法就能划分出身高和体重的特征并进行均值方差化。

    1. # @Auorui
    2. import numpy as np
    3. from scipy.stats import norm
    4. class Datasets:
    5. # 一个简单的数据加载器
    6. def __init__(self, datapath, t):
    7. self.datapath = datapath
    8. self.data = np.loadtxt(self.datapath) # 二维数组
    9. self.height = self.data[:, 0]
    10. self.weight = self.data[:, 1]
    11. self.length = len(self.data)
    12. self.t = t
    13. def __len__(self):
    14. return self.length
    15. def mean(self, data):
    16. # 均值,可以使用np.mean替换
    17. total = 0
    18. for x in data:
    19. total += x
    20. return total / self.length
    21. def var(self, data):
    22. # 方差,可以使用np.var替换
    23. mean = self.mean(data)
    24. sq_diff_sum = 0
    25. for x in data:
    26. diff = x - mean
    27. sq_diff_sum += diff ** 2
    28. return sq_diff_sum / self.length
    29. def retain(self, *args):
    30. # 保留小数点后几位
    31. formatted_args = [round(arg, self.t) for arg in args]
    32. return tuple(formatted_args)
    33. def __call__(self):
    34. mean_height = self.mean(self.height)
    35. var_height = self.var(self.height)
    36. mean_weight = self.mean(self.weight)
    37. var_weight = self.var(self.weight)
    38. return self.retain(mean_height, var_height, mean_weight, var_weight)

    数据加载

    1. def Dataloader(maledata,femaledata):
    2. mmh, mvh, mmw, mvw = maledata()
    3. fmh, fvh, fmw, fvw = femaledata()
    4. male_height_dist = norm(loc=mmh, scale=mvh**0.5)
    5. male_weight_dist = norm(loc=mmw, scale=mvw**0.5)
    6. female_height_dist = norm(loc=fmh, scale=fvh**0.5)
    7. female_weight_dist = norm(loc=fmw, scale=fvw**0.5)
    8. data_dist = {
    9. 'mh': male_height_dist,
    10. 'mw': male_weight_dist,
    11. 'fh': female_height_dist,
    12. 'fw': female_weight_dist
    13. }
    14. return data_dist

     这里使用字典的方式存储男女数据的正态分布化。

    计算概率密度函数(pdf值)以及贝叶斯决策

    这里我们将会采用身高进行最小风险贝叶斯决策,采用体重进行最小错误率贝叶斯决策,采用身高、体重进行最小错误率贝叶斯决策。

    1. def classify(height=None, weight=None, ways=1):
    2. """
    3. 根据身高、体重或身高与体重的方式对性别进行分类
    4. :param height: 身高
    5. :param weight: 体重
    6. :param ways: 1 - 采用身高
    7. 2 - 采用体重
    8. 3 - 采用身高与体重
    9. :return: 'Male' 或 'Female',表示分类结果
    10. """
    11. # 先验概率的公式 : P(w1) = m1 / m ,样本总数为m,属于w1类别的有m1个样本。
    12. p_male = 0.5
    13. p_female = 1 - p_male
    14. cost_male = 0 # 预测男性性别的成本,设为0就是不考虑了
    15. cost_female = 0 # 预测女性性别的成本
    16. cost_false_negative = 10 # 实际为男性但预测为女性的成本
    17. cost_false_positive = 5 # 实际为女性但预测为男性的成本
    18. assert ways in [1, 2, 3], "Invalid value for 'ways'. Use 1, 2, or 3."
    19. assert p_male + p_female == 1., "Invalid prior probability, the sum of categories must be 1"
    20. # if ways == 1:
    21. # assert height is not None, "If mode 1 is selected, the height parameter cannot be set to None"
    22. # p_height_given_male = male_height_dist.pdf(height)
    23. # p_height_given_female = female_height_dist.pdf(height)
    24. #
    25. #
    26. # return 1 if p_height_given_male * p_male > p_height_given_female * p_female else 2
    27. if ways == 1:
    28. assert height is not None, "If mode 1 is selected, the height parameter cannot be set to None"
    29. p_height_given_male = male_height_dist.pdf(height)
    30. p_height_given_female = female_height_dist.pdf(height)
    31. risk_male = cost_male + cost_false_negative if p_height_given_male * p_male <= p_height_given_female * p_female else cost_female
    32. risk_female = cost_female + cost_false_positive if p_height_given_male * p_male >= p_height_given_female * p_female else cost_male
    33. return 1 if risk_male <= risk_female else 2
    34. if ways == 2:
    35. assert height is not None, "If mode 2 is selected, the weight parameter cannot be set to None"
    36. p_weight_given_male = male_weight_dist.pdf(weight)
    37. p_weight_given_female = female_weight_dist.pdf(weight)
    38. return 1 if p_weight_given_male * p_male > p_weight_given_female * p_female else 2
    39. if ways == 3:
    40. assert height is not None, "If mode 3 is selected, the height and weight parameters cannot be set to None"
    41. p_height_given_male = male_height_dist.pdf(height)
    42. p_height_given_female = female_height_dist.pdf(height)
    43. p_weight_given_male = male_weight_dist.pdf(weight)
    44. p_weight_given_female = female_weight_dist.pdf(weight)
    45. return 1 if p_height_given_male * p_weight_given_male * p_male > p_height_given_female * p_weight_given_female * p_female else 2
    46. return 3

    使用测试集验证并计算预测准确率

    1. def test(test_path,ways=3):
    2. test_data = np.loadtxt(test_path)
    3. true_gender_label=[]
    4. pred_gender_label=[]
    5. for data in test_data:
    6. height, weight, gender = data
    7. true_gender_label.append(int(gender))
    8. pred_gender = classify(height, weight, ways)
    9. pred_gender_label.append(pred_gender)
    10. if pred_gender == 1:
    11. print('Male')
    12. elif pred_gender == 2:
    13. print('Female')
    14. else:
    15. print('Unknown\t')
    16. return true_gender_label, pred_gender_label
    17. def accuracy(true_labels, predicted_labels):
    18. assert len(true_labels) == len(predicted_labels), "Input lists must have the same length"
    19. correct_predictions = sum(1 for true, pred in zip(true_labels, predicted_labels) if true == pred)
    20. total_predictions = len(true_labels)
    21. accuracy = correct_predictions / total_predictions
    22. return accuracy

    预测结果

    采用身高进行最小风险贝叶斯决策

    当采用身高进行最小风险贝叶斯决策,准确率在test1数据上的准确率为94.29%,在test2数据上的准确率为91.0%。

    采用体重进行最小错误率贝叶斯决策

    当采用体重进行最小风险贝叶斯决策,准确率在test1数据上的准确率为94.29%,在test2数据上的准确率为85.33%。 

    采用身高、体重进行最小错误率贝叶斯决策

    当采用身高、体重进行最小错误率贝叶斯决策,准确率在test1数据上的准确率为97.14%,在test2数据上的准确率为90.33%。

    添加新的特征

    除了身高、体重的组合,我们也可以延伸出新的特征,比如bmi。

    1. def calculate_bmi(height,weight):
    2. # 计算BMI作为新特征
    3. height_meters = height / 100 # 将身高从厘米转换为米
    4. bmi = weight / (height_meters ** 2) # BMI计算公式
    5. return bmi

    这样能做出的特征就更多了,感兴趣的不妨沿着这个思路继续做。

  • 相关阅读:
    mysql 快速上传数据
    代码随想录算法训练营DAY29(记录)|C++回溯算法Part.5|491.递增子序列、46.全排列、47.全排列II
    文本的设置
    React嵌套路由的使用
    【Linux】进程 && 进程控制块PCB && 查看进程
    LeetCode220726_52、腐烂的橘子
    不破楼兰终不还——Go 延迟语句defer指南
    08-流媒体-RTMP拉流
    从table1 里获取每个person_id最大end_date的数据。(inner join)
    Leetcode150二刷总结
  • 原文地址:https://blog.csdn.net/m0_62919535/article/details/134065370