[数据挖掘] 朴素贝叶斯 以及西瓜集特征工程
朴素贝叶斯 以及西瓜数据集的特征工程
朴素贝叶斯的基本思想
- 先验概率: 通过已知事实, 推论出未知事务出现的概率
例如: 通过硬币有两面, 推论出抛一次硬币可能出现正面的概率 - 后验概率: 通过结果, 推论出导致该结果的原因的概率
例如: 通过硬币抛出来之后是正面, 需要你来判断该硬币被你做手法了的概率
关于先验概率 与 后验概率的理解: https://www.cnblogs.com/yemanxiaozu/p/7680761.html
- 贝叶斯公式:
- 其中, B 是 该事件最后的结果, A 是表示导致该结果的原因, 再结合我们之前对后验概率的理解, 可以知道, 贝叶斯公式的结果就是导致结果B出现的可能性
- 在机器学习中, 对于一个需要预测的数据, 我们知道的是它的各种已知信息相当于公式中的A, 而我们要求的是最后对他的各个分类的概率, 这个分类就相当于公式中的 B, 于是 我们的公式可以表示为:
- 机器学习—朴素贝叶斯: 对于上述的贝叶斯公式, 其中已知的 A 可以看作该数据的特征, 而我们假定该数据的各个特征是独立的, 所以对于p(特征|类别), 我们可以分解为 p(特征1|类别) * p(特征2|类别) * p(特征3|类别) … 这就是朴素的意思, 而对于需预测的数据来说, 我们p(特征), p(类别) 是很容易通过大量数据得到的已知值
- 引用西瓜书上说的:
其中ck表示第k 个分类, xj 表示第j个特征值, Y是该数据最终的分类结果
- 因此 我们需要训练的是什么呢:
每个特征属于每个分类的概率 - 通过被预测数据的特征, 从训练出来的分类器中查找每个特征在每个分类的概率相乘(朴素)
- 得到该数据最终属于每个分类的概率, 选出概率最大的为其最后的分类
- 引用西瓜书上说的:
- 本文算法代码只讨论二分类情况
朴素贝叶斯分类的过程
- 数据获取: 任意方式获取
- 数据分析: 得到其独立同分布的特征, 应用朴素这一条件
- 训练过程:
- 若是离散值: 获取每一个特征在每一个分类下的可能性
- 若是连续值: 假定其符合正态分布, 计算其一维正态分布值:
![]()
- 预测过程: 获取数据各个特征, 计算其属于每个分类的概率, 选出最大概率作为其分类结果
- 模型评估: 本章采用 留出法, k折交叉验证法(留一法), 自助法, 结果为
[真正例, 假正例, 真负例, 假负例]- 性能评估: 准确率
数据集:
1,青绿,蜷缩,浊响,清晰,凹陷,硬滑,0.697,0.46,是
2,乌黑,蜷缩,沉闷,清晰,凹陷,硬滑,0.774,0.376,是
3,乌黑,蜷缩,浊响,清晰,凹陷,硬滑,0.634,0.264,是
4,青绿,蜷缩,沉闷,清晰,凹陷,硬滑,0.608,0.318,是
5,浅白,蜷缩,浊响,清晰,凹陷,硬滑,0.556,0.215,是
6,青绿,稍蜷,浊响,清晰,稍凹,软粘,0.403,0.237,是
7,乌黑,稍蜷,浊响,稍糊,稍凹,软粘,0.481,0.149,是
8,乌黑,稍蜷,浊响,清晰,稍凹,硬滑,0.437,0.211,是
9,乌黑,稍蜷,沉闷,稍糊,稍凹,硬滑,0.666,0.091,否
10,青绿,硬挺,清脆,清晰,平坦,软粘,0.243,0.267,否
11,浅白,硬挺,清脆,模糊,平坦,硬滑,0.245,0.057,否
12,浅白,蜷缩,浊响,模糊,平坦,软粘,0.343,0.099,否
13,青绿,稍蜷,浊响,稍糊,凹陷,硬滑,0.639,0.161,否
14,浅白,稍蜷,沉闷,稍糊,凹陷,硬滑,0.657,0.198,否
15,乌黑,稍蜷,浊响,清晰,稍凹,软粘,0.36,0.37,否
16,浅白,蜷缩,浊响,模糊,平坦,硬滑,0.593,0.042,否
17,青绿,蜷缩,沉闷,稍糊,稍凹,硬滑,0.719,0.103,否
- 特征包含了离散值与连续值, 最后是数据标签
- 可看到连续值已经处于 (0,1)之间了, 因此不需要归一化处理
版本1
- 这个版本只完成了最基础的西瓜数据集的朴素贝叶斯分类
- 写的时候发现每次预测都要训练, 然后, 想到把训练与预测分类, 就可以多次使用分类器了, 然后有了版本2
记录一下代码有多烂:
import numpy as np
import math
def label_count(dataset):
"""
计算每个分类结果的概率
:param dataset:[ [feat], [feat], [feat], ... , [label], ]
:return: p(label) : {label: prob, }
"""
label = {}
for i in dataset:
if i[-1] not in label.keys():
label[i[-1]] = 0
label[i[-1]] += 1
return label
def feat_count(dataset, item, label, labels):
"""
计算某个特征向量被分类为label的概率
:param dataset:
:param labels 每种分类的概率
:param item: 特征向量
:return:
"""
feat_num = np.array([0 for _ in item], np.float32)
for i in range(len(item)):
if isinstance(item[i], (float, int)):
set_i = np.array([j[i] for j in dataset])
u = set_i.mean()
std = set_i.std()
feat_num[i] = (1/(math.sqrt(2*math.pi)*std)) * math.pow(math.e, -1*(feat_num[i] - u)**2 / (2*(std**2)))
else:
for j in dataset:
if item[i] == j[i] and j[-1] == label:
feat_num[i] += 1
feat_num[i] /= labels[label]
return feat_num
def classification(item, dataset):
"""
返回属于每一种分类的可能性
:param item:
:param dataset:
:return:
"""
labels = label_count(dataset)
data_num = len(dataset)
ans = {}
for label in labels:
feat_num = feat_count(dataset, item, label, labels)
ans[label] = 1
for i in feat_num:
ans[label] *= i
ans[label] *= float(labels[label]) / float(data_num)
return sorted(ans.items(), key=lambda j: j[1], reverse=True)
def fun(i):
i = i.strip()
try:
i = float(i)
except ValueError:
pass
return i
def read_data(path):
dataset = []
with open(path, 'r', encoding='utf8') as f:
for line in f.readlines():
split_ = line.strip().split(',')[1:]
dataset.append([i for i in map(fun, split_)])
return dataset
if __name__ == '__main__':
path = "xigua.txt"
dataset = read_data(path)
pre_data = '青绿,蜷缩,浊响,清晰,凹陷,硬滑,0.697, 0.460'
item = [i for i in pre_data.strip().split(',')]
item = [i for i in map(fun, item)]
print(item)
l = classification(item, dataset)
print(l)
结果:
评估
把数据集放进去, 分出测试集与训练集, 进行评估即可
结果:
[真正例, 假正例, 真负例, 假负例]
版本2
- 这个版本把训练过程 与测试过程分开了
- 加入了拉普拉斯假设: 即把为0的特征进行+1, 避免了该分类可能性为0
- 最后给每个特征概率的结果相乘改成了: 最后求log后相加, 避免了特征很多的时候出现的大误差
- 写的时候想到了是不是可以用矩阵运算来避免遍历过程, 以及面向对象.于是出现了版本3
训练
- 训练返回结果的数据结构:
- 离散型, feat_pos_count, feat_neg_count, 表示分类结果为正例和负例的计数
{
特征1:{value1: count, value2: count},
特征2:{value1: count, value2: count},
…
} - 连续型, numer_feat
{
连续型特征: {‘u’: 平均数, ‘std’: 标准差},
…
} - pos_prob: 正例占总数的可能性, 负例直接 1-pos_prob
- 离散型, feat_pos_count, feat_neg_count, 表示分类结果为正例和负例的计数
- 训练过程就是计数而已, 很简单
def n_attribute(u, std, x):
return (1/(sqrt(2*pi)*std)) * pow(e, -1*(x - u)**2 / (2*(std**2)))
def train_bayesian_2_classify(dataset):
"""
2分类器, 1--正, 0--负
训练贝叶斯分类器, 即得到每个特征值的条件概率
:param dataset:最后一列是label 其他作为特征值
:return:
"""
# 初始化每个特征有一个计数,避免最后概率为0. 拉普拉斯校准
feat_num = len(dataset[0])-1
feat_pos_count = [dict() for _ in range(feat_num)]
feat_neg_count = [dict() for _ in range(feat_num)]
# 获取正负例数
pos_num = 0.0
neg_num = 0.0
data_num = len(dataset)
numer_feat = []
for i in range(feat_num):
if isinstance(dataset[0][i], (float,)):
numer_feat.append(i)
for i in range(data_num):
for j in range(feat_num):
if j not in numer_feat:
if dataset[i][j] not in feat_pos_count[j].keys():
feat_pos_count[j][dataset[i][j]] = 0
feat_neg_count[j][dataset[i][j]] = 0
if dataset[i][-1] == 1: # 在正例条件下,对该特征计数
feat_pos_count[j][dataset[i][j]] += 1
else:
feat_neg_count[j][dataset[i][j]] += 1
if dataset[i][-1] == 1:
pos_num += 1
else:
neg_num += 1
pos_prob = pos_num / float(data_num)
for i in range(feat_num):
if i not in numer_feat:
for k in feat_pos_count[i]:
if feat_pos_count[i][k] == 0:
feat_pos_count[i][k] = 1
pos_num += 1
if feat_neg_count[i][k] == 0:
feat_neg_count[i][k] = 1
neg_num += 1
for i in range(feat_num):
if i not in numer_feat:
for k in feat_pos_count[i]:
feat_pos_count[i][k] /= float(pos_num)
feat_neg_count[i][k] /= float(neg_num)
# 计算标称属性的均值与方差
for i in numer_feat:
set_i = np.array([j[i] for j in dataset])
u = set_i.mean()
std = set_i.std()
feat_pos_count[i]['u'] = u
feat_pos_count[i]['std'] = std
feat_neg_count[i]['u'] = u
feat_neg_count[i]['std'] = std
return pos_prob, feat_pos_count, feat_neg_count, numer_feat
预测:
- 预测对于离散特征, 直接从训练结果中查询,
对于连续型特征, 从训练结果中查询出u 与 std, 计算结果即可 - 代码
def prediction(pos_prob, feat_pos_count, feat_neg_count, numer_feat, item):
feat_num = len(item)
# log 化 去除精度问题
res_p = 0
res_n = 0
for i in range(feat_num):
if i not in numer_feat:
res_p += log2(feat_pos_count[i][item[i]])
res_n += log2(feat_neg_count[i][item[i]])
else:
res_p += log2(n_attribute(feat_pos_count[i]['u'], feat_pos_count[i]['std'], item[i]))
res_n += log2(n_attribute(feat_neg_count[i]['u'], feat_neg_count[i]['std'], item[i]))
res_p += log2(pos_prob)
res_n += log2(1-pos_prob)
l = [(1, res_p,), (0, res_n)]
l.sort(key=lambda i:i[1], reverse=True)
return l
结果即评估:
- 预测结果:
- 评估结果
版本3
简介:
- 面向对象,
- 分类器一个对象
- 特征工程一个对象
- 模型评估为一个对象
- 因为想到对离散特征每一个值都需要进行计数, 因此想到直接使用独热编码, 扩展维度: 把每个特征值当成一个新的维度
- pandas来存储数据以及数据处理, 减少了很多遍历, 直接矩阵方法运算\
- 哇, 写不下去了, 想到我在写这个代码的时候因为pandas用得不熟, 各种bug, 各种查资料, 大部分时间都在解决pandas的bug去了, 直接看代码吧, 这个代码的鲁棒性很大提高,应该可以用到很多数据集上了…但是, 数据集太小, 也不知道实际模型效果如何, 实在没时间弄了,
数据集特征工程
OneHotEncoder 与LabelEncoder
-
sklearn.preprocessing 里面包含了两种对离散数据的编码工具:
-
OneHotEncoder: 只能对数字进行处理, 所以在处理string数据的时候必须先转化成数字形式, 例:
from sklearn.preprocessing import LabelEncoder from sklearn.preprocessing import OneHotEncoder enc = OneHotEncoder() # 训练 传入二维数据集 enc.fit_transform([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2],[1,1,1]]) print(enc.n_values_) # 打印每个特征的值的个数 enc.transform([[0,1,3]]).toarray()
结果:
[2 3 4] array([[1., 0., 0., 1., 0., 0., 0., 0., 1.]])
- LabelEncoder: 对离散的文本或者数字进行编号, 可以对字符串的特征向量进行处理, 可以进行逆编码: 即把编码之后的编号还原成特征值描述 inverse_transform()
-
-
pandas 自带的编码方法::
-
独热编码: pd.get_dummies(), 可以对字符串进行处理, 而连续型的特征会自动忽略.
例:print(dataset.head(3)) new_dataset = pd.get_dummies(dataset) print(new_dataset.head(3))
结果:
-
标签编码: pd.Categorical().codes
不知道这个方法与 sklearn的有什么不一样, 具体待查阅资料 -
结论: 如果只需要对数据进行处理, 那么 pandas自带的方法更好用
-
如果需要获取训练出来的编码器, 那么 sklearn会保存这个编码器, 在你对新的数据进行处理的时候, 可以直接使用该编码器得到跟训练数据一样的编码
-
pandas 给我弄晕了的方法:
取值
- pd.loc[index] -->return Series
- pd.loc[[index]] / pd.reindex([]) -->return DataFrame , 一般用后一种方法 reindex
- pd.iloc[] 跟loc 一样, 获取某一行, 不过传入的是行的下标
- pd.iloc[[]]
- pd[col_name] --> , return Series 直接获取某一列, 的值
- pd[[col_name]] --> return DataFrame
- pd.at[index, col_name] --> 获取某一个数据点
集合
并集: append
差集: 比如 求 df1 与 df2 的差集
df1.append(df2).append(df2).drop_duplicates(keep=False)
即: 对其中一个元素 append两次, 然后再在最后去重, 参数表示把重复的元素都删掉, 如果 keep=True, 会保留重复元素的第一个
赋值
- pd.at[r, c] = x
- pd.[col_name] = Series, 如果, 这一列不存在 则添加新的一列
- pd.loc[[index]] = Series, 给某一行赋值, 不存在这一行报错
- DataFrame.append --> 与下面一样
- series.append(series) --> 在series下面拼接, 不改变原元素, 返回新的Series
特殊索引 *** 我记得numpy 也是这样
- 在df[]的中括号里面传入与 df 的列数匹配的Series, 返回里面为 True 的值
- 看两个例子
>>> import pandas as pd >>> pd.DataFrame([[1,2,3], [2,3,4]]) 0 1 2 0 1 2 3 1 2 3 4 >>> pd <module 'pandas' from 'D:\\software\\Python3.6\\lib\\site->packages\\pandas\\__init__.py'> >>> df = pd.DataFrame([[1,2,3], [2,3,4]]) >>> s = pd.Series([True, True, False]) >>> s 0 True 1 True 2 False dtype: bool >>> df[s] __main__:1: UserWarning: Boolean Series key will be reindexed to match >DataFrame index. 0 1 2 0 1 2 3 1 2 3 4 >>> s = pd.Series([True,False, False]) >>> df[s] 0 1 2 0 1 2 3 >>>
代码
- 特征工程方法
def feat_handle(dataset, dis_cols, cont_cols, v_col):
"""
特征工程,
:param dataset: DataFrame原始数据集 pd.DataFrame
:param dis_cols: list 离散特征列 [clo1, col2, col3 ...]
:param cont_cols: list 连续特征列 [col1, col2, col3]
:param v_col: int/str 数据标签(类别) 所在的列名
:return:
"""
values = dataset[v_col]
discrete_data = dataset[dis_cols]
# print('原始数据')
# print(dataset.head())
enc = OneHotEncoder()
X = enc.fit_transform(discrete_data)
discrete_data = pd.DataFrame(X.toarray())
# discrete_data = pd.get_dummies(discrete_data)
# print('\n编码后')
# print(discrete_data.head())
continuous_data = dataset[cont_cols]
# print('连续特征')
# print(continuous_data.head())
# 给最终分类结果 标签编码 1, 0:
# values = values.apply(lambda x: pd.Categorical(x).codes)[v_col]
le = LabelEncoder()
Y = le.fit_transform(values)
values = pd.Series(Y)
# print('数据标签 y向量:')
# print(values.head())
return continuous_data, discrete_data, values, enc, le
- 二分类分类器:
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder
import numpy as np
import pandas as pd
class Bayes_2:
def __init__(self, discrete_data, continuous_data, values):
self.dis_data = discrete_data
self.con_data = continuous_data
# 这个是series类型
self.V = values
self.feat_prob = pd.DataFrame(columns=discrete_data.keys(), index=[0, 1])
self.con_charct_1 = pd.DataFrame(columns=continuous_data.keys(), index=['std', 'mean'])
self.con_charct_0 = pd.DataFrame(columns=continuous_data.keys(), index=['std', 'mean'])
self.prob_0 = 0.0
self.prob_1 = 0.0
def train(self):
# 拉普拉斯校准的计数
count1_off = 0
count0_off = 0
for key in self.feat_prob.keys():
# print(self.dis_data.loc[self.dis_data[key] == 1].index)
# print(self.V[self.V == 1].index)
# print(self.V[self.V == 1].index & self.dis_data.loc[self.dis_data[key] == 1].index)
self.feat_prob.at[1, key] = self.dis_data[key].reindex(self.V[self.V == 1].index & self.dis_data.loc[self.dis_data[key] == 1].index).count()
if self.feat_prob.at[1, key] == 0:
count1_off += 1
self.feat_prob.at[0, key] = self.dis_data[key].reindex(self.V[self.V == 0].index & self.dis_data.loc[self.dis_data[key] == 1].index).count()
if self.feat_prob.at[0, key] == 0:
count0_off += 1
# print(self.feat_prob)
p1 = self.V[self.V == 1].count()
count = self.V.count()
p0 = count - p1
self.prob_1 = p1 / float(count)
self.prob_0 = p0 / float(count)
self.feat_prob.loc[1] /= float(p1 + count1_off)
self.feat_prob.loc[0] /= float(p0 + count0_off)
# 计算连续型数据的标准差和平均值
for key in self.con_data.keys():
self.con_charct_1.at['std', key] = self.con_data[key].reindex(self.V[self.V == 1].index).std()
self.con_charct_0.at['std', key] = self.con_data[key].reindex(self.V[self.V == 0].index).std()
self.con_charct_1.at['mean', key] = self.con_data[key].reindex(self.V[self.V == 1].index).mean()
self.con_charct_0.at['mean', key] = self.con_data[key].reindex(self.V[self.V == 0].index).mean()
def predict(self, dis_feat, conti_feat):
# 获取预测数据每个特征值取得的概率
feat_1 = self.feat_prob.loc[1] * dis_feat
feat_0 = self.feat_prob.loc[0] * dis_feat
# log化
feat_1 = feat_1.apply(lambda x: np.log2(np.float64(x.values)) if x.values > 0 else 0)
feat_0 = feat_0.apply(lambda x: np.log2(np.float64(x.values)) if x.values > 0 else 0)
# 获取预测数据离散特征值的正太分布函数值 并log化
# print(self.con_charct_1)
conti_feat_1 = conti_feat.apply(lambda x: self._norm_value(x, self.con_charct_1.at['std', x.name], self.con_charct_1.at['mean', x.name]))
conti_feat_0 = conti_feat.apply(lambda x: self._norm_value(x, self.con_charct_0.at['std', x.name], self.con_charct_0.at['mean', x.name]))
# print(conti_feat)
# log结果 累加 相当于非log的累乘
pre_1 = feat_1.sum() + conti_feat_1.values.sum() + np.log2(self.prob_1)
pre_0 = feat_0.sum() + conti_feat_0.values.sum() + np.log2(self.prob_0)
return sorted([(1, pre_1), (0, pre_0)],key=lambda x: x[1], reverse=True)
def _norm_value(self, x, std, u):
return (1/(np.sqrt(2*np.pi)*std)) * pow(np.e, -1*(x - u)**2 / (2*(std**2)))
def evolut_hold_out(self, t=0.3):
pass
- 评估, 这块的代码.鲁棒性不强, 不知道其他数据集上能不能用
class Evolutor:
def __init__(self, learner, dataset, cont_cols, dis_cols, v_col):
self.learner = learner
self.dataset = dataset
self.dis_cols = dis_cols
self.cont_cols = cont_cols
self.v_col = v_col
def feat_handle(self):
# 进行特征工程
self.continuous_data, self.discrete_data, self.values, self.enc, self.le = feat_handle(self.dataset, self.dis_cols, self.cont_cols,
self.v_col)
def hold_out(self, t=0.3, times=1):
self.feat_handle()
# 真正例, 假正例, 真负例, 假付例
assem = [0, 0, 0, 0]
testset = list()
trainset = list()
for _ in range(times):
test1num = int(len(self.values[self.values == 1]) * t)
test0num = int(len(self.values[self.values == 0]) * t)
testnum = test1num + test0num
# 随机选择 testnum个数据
test1_index = np.random.choice(self.discrete_data.iloc[self.values[self.values == 1].index].index, test1num)
test0_index = np.random.choice(self.discrete_data.iloc[self.values[self.values == 0].index].index, test0num)
testset.append(self.discrete_data.reindex(np.append(test1_index, test0_index)))
testset.append(self.continuous_data.reindex(np.append(test1_index, test0_index)))
testset.append(self.values[np.append(test1_index, test0_index)]) # 这里有 bug
# 得到dataset与testset的差集
tmp = self.discrete_data.append(testset[0]).append(testset[0])
trainset.append(tmp.drop_duplicates(keep=False))
tmp = self.continuous_data.append(testset[1]).append(testset[1])
trainset.append(tmp.drop_duplicates(keep=False))
trainset.append(self.values[list(filter(lambda x: x not in testset[2].index, self.values.index))])
## 进行贝叶斯分类
for i in range(testnum):
self.learner = Bayes_2(trainset[0], trainset[1], trainset[2])
self.learner.train()
pre_dis_v = testset[0].iloc[[i]]
pre_cont_v = testset[1].iloc[[i]]
res = self.learner.predict(pre_dis_v, pre_cont_v)
# print(testset[2].iloc[i])
# print(res)
if testset[2].iloc[i] == '是' or testset[2].iloc[i] == 1:
if res[0][0] == '是' or res[0][0] == 1:
assem[0] += 1
else:
assem[3] += 1
elif testset[2].iloc[i] == '否' or testset[2].iloc[i] == 0:
if res[0][0] == '否' or res[0][0] == 0:
assem[2] += 1
else:
assem[1] += 1
# assem = [0,0,0,0]
# assem = [i / times for i in assem]
print('留出法,测试集比例:t={0},结果:{1}'.format(t, assem))
return assem
def cross_validate(self):
"""
留一法
:return:
"""
# 真正例, 假正例, 真负例, 假负例
assem = [0, 0, 0, 0]
datanum = len(self.dataset)
for i in range(datanum):
item = self.dataset.iloc[[i]]
trainset = self.dataset.iloc[:i]
trainset = trainset.append(self.dataset.iloc[i + 1:])
# 进行特征工程
continuous_data, discrete_data, values, enc, le = feat_handle(self.dataset, self.dis_cols, self.cont_cols,
self.v_col)
self.learner = Bayes_2(discrete_data, continuous_data, values)
self.learner.train()
pre_dis_v = pd.DataFrame(enc.transform(item[self.dis_cols]).toarray())
pre_cont_v = item[self.cont_cols]
res = self.learner.predict(pre_dis_v, pre_cont_v)
if item.iloc[0][self.v_col] == '是' or item.iloc[0][self.v_col] == 1:
if res[0][0] == '是' or res[0][0] == 1:
assem[0] += 1
else:
assem[3] += 1
elif item.iloc[0][self.v_col] == '否' or item.iloc[0][self.v_col] == 0:
if res[0][0] == '否' or res[0][0] == 0:
assem[2] += 1
else:
assem[1] += 1
print('留1法:{0}'.format(assem))
return assem
def bootstrap(self):
assem = [0, 0, 0, 0]
data_num = len(self.dataset)
test_index = np.random.randint(0, data_num-1, data_num)
testset = self.dataset.iloc[test_index]
trainset = self.dataset.copy()
# 进行特征工程
continuous_data, discrete_data, values, enc, le = feat_handle(self.dataset, self.dis_cols, self.cont_cols,
self.v_col)
self.learner = Bayes_2(discrete_data, continuous_data, values)
self.learner.train()
for i in range(len(testset)):
item = testset.iloc[[i]]
pre_dis_v = pd.DataFrame(enc.transform(item[self.dis_cols]).toarray())
pre_cont_v = item[self.cont_cols]
res = self.learner.predict(pre_dis_v, pre_cont_v)
if item.iloc[0][self.v_col] == '是' or item.iloc[0][self.v_col] == 1:
if res[0][0] == '是' or res[0][0] == 1:
assem[0] += 1
else:
assem[3] += 1
elif item.iloc[0][self.v_col] == '否' or item.iloc[0][self.v_col] == 0:
if res[0][0] == '否' or res[0][0] == 0:
assem[2] += 1
else:
assem[1] += 1
print('自助法:{0}'.format(assem))
return assem
- 主函数
if __name__ == '__main__':
path = r"D:\Workspace\Pyworkspase\DataMining\Bayesian\xigua.txt"
# 数据获取
dataset = pd.read_csv(path, ",", header=None, usecols=[i for i in range(1, 10)])
dis_cols = [i for i in range(1, 7)]
cont_cols = [7, 8]
v_col = 9
print('特征工程','-'*100)
# 特征工程, 获取 one-hot编码器 与 label编码器, 还有数据里面的编码后的离散值与连续值向量 以及 最后每条数据的标签向量
continuous_data, discrete_data, values, enc, le = feat_handle(dataset, dis_cols, cont_cols, v_col)
print('-'*100)
# 训练
print('训练:', '-'*100)
bayes = Bayes_2(discrete_data, continuous_data, values)
bayes.train()
print('-'*100)
print('预测', '-'*100)
# 1,青绿,蜷缩,浊响,清晰,凹陷,硬滑,0.697,0.46
pre_data = pd.DataFrame([['1','青绿','蜷缩','浊响','清晰','凹陷','硬滑',0.697,0.46]])
print('预测数据:', pre_data.values)
# 给预测数据进行处理
pre_dis_v = pd.DataFrame(enc.transform(pre_data[dis_cols]).toarray())
pre_cont_v = pre_data[cont_cols]
# 预测
res = bayes.predict(pre_dis_v, pre_cont_v)
print('预测结果:', res)
print('-'*100)
# 模型评估
print('评估结果:')
evolutor = Evolutor(None, dataset, cont_cols, dis_cols, v_col)
evolutor.hold_out(times=1)
evolutor.cross_validate()
evolutor.bootstrap()
- 结果
特征工程 ----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
训练: ----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
预测 ----------------------------------------------------------------------------------------------------
预测数据: [['1' '青绿' '蜷缩' '浊响' '清晰' '凹陷' '硬滑' 0.697 0.46]]
预测结果: [(1, -5.644075586912031), (0, -8.912675295359993)]
----------------------------------------------------------------------------------------------------
评估结果:
留出法,测试集比例:t=0.3,结果:[2, 2, 0, 0]
留1法:[6, 3, 6, 2]
自助法:[8, 3, 5, 1]