Quantcast
Channel: CodeSection,代码区,Python开发技术文章_教程 - CodeSec
Viewing all articles
Browse latest Browse all 9596

数据挖掘实验2python编写贝叶斯分类器

$
0
0
1. Introduction

本文基于前文说的朴素贝叶斯原理,参考 圣地亚哥州立大学的实验 编写了一个简单的朴素贝叶斯分类器,并利用测试数据进行了测试。

项目地址:

2. 分类器编写 2.1数据说明

采用“adult”数据集,输入文件是adult.data,测试文件是adult.test。数据中一行为一个条目,表示一个人

数据集中的变量

变量名 意义 age 年龄 type_employer 职业类型,个体,政府等等 fnlwgt 该变量将被我们忽略 education 学历 education_num 学历的数字等级(和上一个一样,将被忽略) marital 婚姻状况 occupation 职业 relationship 不清楚如何表述 race 人种 sex 生理性别 capital_gain 资本收益 capital_loss 资本支出 hr_per_week 每周工作时长 country 国籍 income 年收入是否>50k

由于参考文章中使用的是R语言进行处理,R语言在数据挖掘和统计上优势极大,几乎就是为其而生。python中也有numpy库,但是这里仅用了numpy库的median取中位数功能,其他还是以python原生类型来处理。

2.2 框架规划

参考 使用Python编写朴素贝叶斯分类器 ,我们也主要使用字典来实现统计,但是可以分成两个字典,一个是>50k的dataset_high,一个是<=50k的dataset_low。

class DataSet:
def __init__(self):
# 存储读入的原始数据
self.data = []
# 支出的中位数
self.loss_mid = 0
# 收入的中位数
self.gain_mid = 0
# 工作时长的中位数
self.hours_mid = 0
# 年龄的中位数
self.age_mid = 0
# 统计的数据,主要部分
self.classfied_dataset = None
# 总数据条目
self.len_data = 0

最后的计算是前文说的:

最后两者取大者,则就是所建模型的判定,是否大于50k。

公式化简:

由于P(输入数据的特征)对于一条数据,两个公式来说,是相同的,所以略去计算。

2.3 输入数据预处理 a = ["age", "type_employer", "fnlwgt", "education", "education_num", "marital", "occupation", "relationship", "race",
"sex", "capital_gain", "capital_loss", "hr_per_week", "country", "income"]
classfiled_data = {}
loss_median = loss
gain_median = gain
for node in a:
classfiled_data[node] = {}
for line in data:
if len(line) < 10:
continue
for node in a:
if line[a.index(node)] in classfiled_data[node]:
classfiled_data[node][line[a.index(node)]] += 1
else:
classfiled_data[node][line[a.index(node)]] = 1

列表a就是所有的字段,将所有的数据都按照对应字段,统计到classfiled_data上去,最后形成的形式如下:

# 打印classfiled_data的输出,这是已经简化过的输出
{education:
{'Prof-school': 153, 'dropout': 4009, 'Doctorate': 107, 'HS-grad': 8826, 'Bachelors': 3134, 'Assoc': 1823, 'Some-college': 5904, 'Masters': 764},
marital:
{'Widowed': 908, 'Never-married': 10192, 'not-married': 5323, 'Married': 8297},
country:
{'other': 133, 'United-States': 21999, 'British-Commonwealth': 230, 'SE-Asia': 242, 'Euro_1': 159, 'Euro_2': 122, '?': 437, 'South': 64, 'China': 100, 'Latin-America': 1027, 'South-America': 207},
income:
{'<=50K': 24720},
capital_gain:
{'low': 0, 'none': 23685, 'high': 1035},
relationship:
{'Not-in-family': 7449, 'Own-child': 5001, 'Other-relative': 944, 'Husband': 7275, 'Wife': 823, 'Unmarried': 3228},}

即classfiled_data的第一层字段是a里面的字段,每个字段又对应不同类型的子字段,数字是统计所有数据的出现次数。

2.4 字段简化

舍弃没用的 fnlwgt 和重复的 education_num 字段

对于职业类型字段,Never-worked和without-Pay可以合并为Not-working字段,类似的,也可以把其他一些字段进行合并,合并的步骤是先在classfiled_data['type_employer']里新建一个'not-working'的key,然后其value就是原来['Never-worked', 'Without-pay']的数值之和。在写了很长的代码以后,我将其提取出来做成了一个函数: def tiny(a_list, category, new_name):
if new_name not in classfiled_data[category]:
classfiled_data[category][new_name] = 0
for key in list(classfiled_data[category]):
if key in a_list and key != new_name:
classfiled_data[category][new_name] += classfiled_data[category][key]
del classfiled_data[category][key]
tiny(['Never-worked', 'Without-pay'], 'type_employer', 'not-working')
tiny(['Local-gov', 'State-gov'], 'type_employer', 'other-govt')
tiny(['Self-emp-inc', 'Self-emp-not-inc'], 'type_employer', 'self-employed')

同样对其他字段也进行了类似的化简。

这里有这样几个字段需要单独处理:

capital_gain 利用中位数划分成三部分:(-INF, 0] (0, mid] (mid, INF] capital_loss 同上 hr_per_week 工作时间按照10小时间隔划分了。最大值99,映射到100s上 age 按照5为间隔划分了20组, 3. 测试数据

由于前面对数据进行了化简,所以测试数据的输入也需要按照上面的划分进行映射,我代码里直接使用生成好的字典进行映射。

针对每条数据,计算P(输入数据的特征|>50k) 和P(输入数据的特征|<=50k),取大的返回结果。

最后测试结果如下:

模型的判断正确的次数: 13206
错误的次数 3075
正确率: 0.811130

Viewing all articles
Browse latest Browse all 9596

Trending Articles