朴素贝叶斯:
基于贝叶斯定理,朴素贝叶斯方法是用于分类的概率模型。当数据集的维数很高时,它们非常有用。
贝叶斯定理:
使用贝叶斯定理,假设事件B已经发生,我们可以找到事件A发生的概率。在这里,我们认为事件A和事件B是彼此独立的 “ 天真 ”假设。对于我们考虑的所有特征向量均保持该假设。
因此,要计算给定变量 y的概率,我们将得到特征向量 x 1 至x n,则贝叶斯定理可以应用为:
根据我们拥有的数据类型,我们可以应用以下定理:
- 高斯朴素贝叶斯
- 多项式朴素贝叶斯(用于多项式数据)
- 补充朴素贝叶斯(用于不平衡多项式数据)
- Bernoulli Naive Bayes(用于布尔值数据)
- 分类朴素贝叶斯(用于分类分布的数据)
在下面的示例中,我们将看高斯朴素贝叶斯。
标准朴素贝叶斯问题
我们只能对分类数据使用朴素贝叶斯,即,如果我们不想继续将数据存储到类别中。在这种情况下,实现高斯朴素贝叶斯非常有用,因为它可以处理具有连续值的数据集。
高斯朴素贝叶斯
在这里,我们假设特征集本质上是高斯的:
高斯朴素贝叶斯帮助我们处理连续数据。在我们的数据集中,如果我们有以正态(或高斯)形式分布的数据,我们将根据它们各自的类值来分离数据。然后,我们计算它们的均值和方差,这将有助于我们进一步计算该特定属性的概率值。
代码实现:
# import required packages
import torch
import syft as sy
现在,我们将创建一个名为bob,alice和bill的虚拟工作节点。
# create a hook
hook = sy.TorchHook(torch)
# create a worker
bob = sy.VirtualWorker(hook, id="bob")
alice = sy.VirtualWorker(hook, id="alice")
bill = sy.VirtualWorker(hook, id="bill")
对于此代码演练,我们将生成一些数据并将其发送给bob和alice,而bill将是加密提供者。
# a random dataset
data = torch.tensor([[3.393533211, 2.331273381],
[3.110073483, 1.781539638],
[1.343808831, 3.368360954],
[3.582294042, 4.67917911],
[2.280362439, 2.866990263],
[7.423436942, 4.696522875],
[5.745051997, 3.533989803],
[9.172168622, 2.511101045],
[7.792783481, 3.424088941],
[7.939820817, 0.791637231]])
# class values of the dataset
target = torch.tensor([[0],[0],[0],[0],[0],[1],[1],[1],[1],[1]])
# send the data and target labes to the workers
data = data.fix_precision().share(bob, alice, crypto_provider=bill)
target = target.fix_precision().share(bob, alice, crypto_provider=bill)
以下函数将帮助我们计算数据集的统计信息,我们需要进一步计算其概率值。
# calculate mean of list
def mean(numbers):
s = sum(numbers) / len(numbers)
return s
# calculate standard deviation of list
def stddev(numbers):
num_copy = numbers
avg = mean(numbers)
for n in range(len(num_copy)):
num_copy[n] = (num_copy[n] - avg) * (num_copy[n] - avg)
variance = sum(num_copy) / (len(num_copy) - 1)
std = torch.sqrt(variance.get().float_precision())
std = std.fix_precision().share(bob, alice, crypto_provider=bill)
return std
# calculate stats(mean, stddev, total) for each attribute of the dataset
def summarize_dataset(rows):
numAttributes = len(rows[0])
summaries = []
for n in range(numAttributes):
elements = []
for r in range(len(rows)):
elements.append(rows[r][n])
m = mean(elements)
s = stddev(elements)
l = torch.tensor([len(elements)]).fix_precision().share(bob, alice, crypto_provider=bill)
summaries.append([m, s, l])
return summaries
由于标签也被加密,因此我们将定义一个函数来存储标签中的唯一值。
# generate list of labels for our datset
def getLabels(target):
labels = []
for t in range(len(target)):
same = 0
for l in range(len(labels)):
same = (target[t] == labels[l]).get()
if same:
break
if not same:
labels.append(target[t])
return labels
现在,我们将根据属性的类值对其进行隔离。为此,我们将创建一个名为split的字典, 并以键作为其类值存储属性。
# separate the dataset according to the class values
separated = dict()
labels = getLabels(target)
# initialize the labels as keys for
# separated dictionary
for label in labels:
separated[label] = list()
# loop over the rows of the dataset and apped the rows to the dictionary
# according to their class values
for i in range(len(target)):
for l in range(len(labels)):
same = target[i] == labels[l]
if same.get():
separated[labels[l]].append(data[i])
在下面的代码中,我们使用之前定义的函数计算数据集的统计信息,并将这些值以字典的形式存储。
# initialize the stats dictionary and
# calculate the stats for the values in
# the separated dictionary
summaries = dict()
for class_value, rows in separated.items():
for l in range(len(labels)):
same = class_value == labels[l]
if same.get():
summaries[labels[l]] = summarize_dataset(rows)
由于计算概率的方程具有一些常数值,因此我们将这些值加密并将其发送给bob和alice以避免除法过程中的任何问题。
# import pi value and squareroot function from math library
from math import pi, sqrt
# encrypt the constants and send their values to virtual workers
sq_pi = sqrt(2 * pi)
sq_pi = torch.tensor([sqrt(2 * pi)]).fix_precision().share(bob, alice, crypto_provider=bill)
one = torch.tensor([1]).fix_precision().share(bob, alice, crypto_provider=bill)
我们将定义一个函数来计算高斯概率。
# Calculate the Gaussian probability distribution function for given row
def calculate_probability(x, mean, stdev):
numerator = (x-mean)**2
denominator = 2 * (stdev**2)
exponent = torch.exp(-(numerator / denominator))
p = ((one / (sq_pi * stdev)) * exponent)
return p
现在是我们的主要功能,我们使用上面定义的所有功能实现高斯朴素贝叶斯。
# Calculate the probabilities of predicting each class for a given row
def calculate_class_probabilities(summaries, row):
total_rows = len(target)
probabilities = dict()
for class_value, class_summaries in summaries.items():
probabilities[class_value] = summaries[class_value][0][2] / total_rows
for i in range(len(class_summaries)):
mean, stdev, _ = class_summaries[i]
probabilities[class_value] *= calculate_probability(row[i], mean, stdev)
return probabilities
我们可以使用任何值来测试我们的代码。为简单起见,我们使用数据集中的值。
test = torch.tensor([3.393533211, 2.331273381]).fix_precision().share(bob, alice, crypto_provider=bill)
最后,我们可以通过将测试张量传递给calculate_class_probabilities()函数以及为数据集计算出的摘要字典,来计算类值的概率。
# calculate probabilities of every class for a given row
prob = calculate_class_probabilities(summaries, test)
for k, v in prob.items():
print(k.get().float_precision())
print(v.get().float_precision())
本文翻译自OpenMined官方博客,链接:https://blog.openmined.org/encrypted-gaussian-naive-bayes-from-scratch/
- 这篇文章的作者:
-