sunDP-学习笔记2-均值估计、直方图估计

  • 说明1:本文中的算法均来自
    作者:DPer
    链接:https://zhuanlan.zhihu.com/p/67761743
    来源:知乎
    GitHub:https://github.com/forestneo/sunDP
    在此仅为学习记录
  • 说明2:有些函数的说明在sunDP-学习笔记1中

1. 均值估计

梳理均值估计的思路:

  1. 假如有N个数,每个数分布在[0,1]之间(如果分布在0-m,那就除以一个m,使值同样分布在[0,1]之间)。
  2. 将每个数离散化到0或1。
  3. 对离散化的数据做差分隐私处理(Random Response)并发送。
  4. 服务器收集到DP处理后的数据求和。
  5. 服务器对求和的数据校正。

代码:

def mean_estimation_experiment():
    # generated data
    data = np.clip(np.random.normal(loc=0.5, scale=0.2, size=[10000]), 0, 1)
    #numpy中的clip()函数用于将数组中的元素控制在一个给定的范围内
    #numpy.clip(a, a_min, a_max, out=None)
    #numpy.random.normal() 高斯分布随机数
    #np.random.normal(loc=0.5, scale=0.2, size=[10000])对应的是μ=0.5,σ=0.2的高斯分布,其中size返回值的个数:[10000]

    print("this is generated data\n", data)

    mean = np.average(data)		#np.average()计算均值的函数
    print("the mean of original data is: ", mean)

    epsilon = 1

    discretized_data = [dp.discretization(value=value, lower=0, upper=1) for value in data]
    #从for给定的data中选择出满足条件的元素组成新的discretized_data
    dp_data = [dp.random_response(value=value, epsilon=epsilon) for value in discretized_data]

    cnt_one = np.sum(dp_data)    #da_data中的所有元素求和
    est_one = dp.random_response_adjust(sum=cnt_one, N=len(dp_data), epsilon=epsilon)
    est_mean = est_one / len(dp_data)
    #len()函数返回的是dp_data的长度

    print("the estimated mean is: ", est_mean)

numpy.random.normal() 高斯分布随机数

额外说明
正态分布(Normal distribution)又名高斯分布(Gaussian distribution),若随机变量X服从一个数学期望为μ、标准方差为σ2的高斯分布,记为:X~N(μ,σ2),
正态分布的期望值μ决定了其位置,其标准差σ决定了分布的幅度。因其曲线呈钟形,因此人们又常常称之为钟形曲线。通常所说的标准正态分布是μ = 0,σ = 1的正态分布。
numpy random类中,看名称就是产生随机数的模块。

numpy.random.normal() 高斯分布随机数
numpy.random.normal(loc=0,scale=1e-2,size=shape)

参数说明
loc(float)正态分布的均值(中心),loc=0说明这一个以Y轴为对称轴的正态分布
scale(float)分布的标准差(宽度),scale越大,正态分布的曲线越矮胖,scale越小,曲线越高瘦
size(int 或者整数元组)输出值的维度。如果给定的维度为(m, n, k),那么就从分布中抽取m * n * k个样本。如果size为None(默认值)并且loc和scale均为标量,那么就会返回一个值。否则会返回np.broadcast(loc, scale).size个值

np.random.randn(size) 为标准正态分布(μ=0,σ=1),对应于np.random.normal(loc=0, scale=1, size)。

numpy.clip()函数

numpy中的clip()函数用于将数组中的元素控制在一个给定的范围内,给定需要控制的范围的上下边界,clip函数将所有小于下边界的数值全部改为下边界, 将大于上边界的数值全部改为上边界。

numpy中clip()函数的原型为:clip(self, min=None, max=None, out=None)
参数说明:
self为需要控制的数组,
min为下边界,
max为上边界,
out为存储输出结果的数组。

np.average()

mean和average都是计算均值的函数,在不指定权重的时候average和mean是一样的。指定权重后,average可以计算一维的加权平均值。

import numpy as np
a = np.array([np.random.randint(0, 20, 5), np.random.randint(0, 20, 5)])
print('原始数据\n', a)
print('mean函数'.center(20, '*'))
print('对所有数据计算\n', a.mean())
print('axis=0,按行方向计算,即每列\n', a.mean(axis=0)) # 按行方向计算,即每列
print('axis=1,按列方向计算,即每行\n', a.mean(axis=1)) # 按列方向计算,即每行
print('average函数'.center(20, '*'))
print('对所有数据计算\n', np.average(a))
print('axis=0,按行方向计算,即每列\n', np.average(a, axis=0)) # 按行方向计算,即每列
print('axis=1,按列方向计算,即每行\n', np.average(a, axis=1)) # 按列方向计算,即每行
b = np.array([1, 2, 3, 4])
wts = np.array([4, 3, 2, 1])
print('不指定权重\n', np.average(b))
print('指定权重\n', np.average(b, weights=wts)

#代码原文链接:https://blog.csdn.net/pyjishu/article/details/105433944

运行结果:

原始数据
 [[ 2  6 11 12 18]
 [12 12  1 11 15]]
*******mean函数*******
对所有数据计算
 10.0
axis=0,按行方向计算,即每列
 [ 7.   9.   6.  11.5 16.5]
axis=1,按列方向计算,即每行
 [ 9.8 10.2]
*****average函数******
对所有数据计算
 10.0
axis=0,按行方向计算,即每列
 [ 7.   9.   6.  11.5 16.5]
axis=1,按列方向计算,即每行
 [ 9.8 10.2]
不指定权重
 2.5
指定权重
 2.0

for 语句

Python for循环可以遍历任何序列的项目,如一个列表或者一个字符串。

for循环的一般格式如下:

for <variable> in <sequence>:
    <statements>
else:
    <statements>

for循环理解

m = [a for b in c]#用于列表的嵌套中,先遍历b(b in c),再将遍历结果存放到a中,赋值给m

用于列表的嵌套中,先遍历b(b in c),再将遍历结果存放到a中,赋值给m。例如:

#要求:列出1~10所有数字的平方
#普通方法
L=[]
for i in range(1,11):
	L.append(i**2)
print(L)

#列表方法
L=[i**2 for i in range(1,11)]
print(L)

#例2
print("\n例2:")
a=[12, 3, 4, 6, 7, 13, 21]
newList = [x for x in a]
print("newList:" , newList)
newList2 = [x for x in a if x%2==0]
print("newList2:" , newList2)

运行结果

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

例2:
newList: [12, 3, 4, 6, 7, 13, 21]
newList2: [12, 4, 6]

np.sum()函数

Numpy中sum函数(Python自带sum函数)的作用是对元素求和。

  1. 无参时,所有全加;
  2. axis=0,按列相加;
  3. axis=1,按行相加;
#举例
from numpy import array
import numpy as np
a = array([[1, 2, 3], [4, 5, 6]])
# numpy中sum函数相加
np_SUM = np.sum(a)  # 所有元素求和
np_SUM_0 = np.sum(a, axis=0)  # 按照列求和
np_SUM_1 = np.sum(a, axis=1)  # 按照行求和

print("np_SUM:"+str(np_SUM))
print("np_SUM_0:"+str(np_SUM_0))
print("np_SUM_1:"+str(np_SUM_1))

运行结果

np_SUM:21
np_SUM_0:[5 7 9]
np_SUM_1:[ 6 15]

python中的len()

  1. 作用:返回字符串、列表、字典、元组等长度
  2. 语法:len(str)
  3. 参数:str:要计算的字符串、列表、字典、元组等
  4. 返回值:字符串、列表、字典、元组等元素的长度

2. 直方图估计

直方图估计思路大概如下,假设我们有m个bucket,即数据是1-m的整数:

  1. 每个用户用onehot编码自己的数据,即建立一个0向量,并且第i位为1,其中i是自己拥有的数据。
  2. 对每一位加上 ε/2 的噪声,并发送数据。
  3. 服务器计算每一位上收到数据的求和,并进行校正,估计出该位上1的个数表示该数据的频数。

为了代码阅读方便,作者写了一个函数用于每个用户给自己的数据编码:’

def random_response_for_hist(user_vector, epsilon):
    """
    每个用户对自己的数据进行random response操作
    :param user_vector: [0,0,0,0,...,0,0,1,0,0,...]
    :param epsilon: 隐私预算
    :return: [1,0,0,1,1,...]
    """
    for i in range(len(user_vector)):
        user_vector[i] = sdp.random_response(user_vector[i], epsilon=epsilon/2)
    return user_vector

总体流程如下:

if __name__ == '__main__':
    # 生成数据
    users = generate_data(user_number=100000)

    # 得到原始数据的直方图
    original_hist = np.sum(users, axis=0)
    print("this is original hist: \n", original_hist)

    # 隐私参数
    epsilon = np.log(3)

    # aggregator收集并处理数据
    rr_user = np.asarray([random_response_for_hist(user, epsilon) for user in users])#np.asarray()将结构数据转换为ndarray类型
    rr_sums = np.sum(rr_user, axis=0)#axis=0,即按照列求和
    print("this is the hist by the aggregator: \n", rr_sums)

    # aggregator校正数据
    estimate_hist = [sdp.random_response_adjust(rr_sum, len(users), epsilon/2) for rr_sum in rr_sums]
    print(np.sum(estimate_hist))

    # 展示原始数据的直方图
    print("this is estimated hist: \n", estimate_hist)

    # 画图
    fig = plt.figure(figsize=[12, 5])
    ax1 = fig.add_subplot(121)  # 2*2的图形 在第一个位置
    ax1.bar(range(len(original_hist)), original_hist)
    ax2 = fig.add_subplot(122)
    ax2.bar(range(len(estimate_hist)), estimate_hist)
    plt.show()

np.asarray()

理解链接:https://blog.csdn.net/sinat_28576553/article/details/89047893

相同点:array和asarray都可以将数组转化为ndarray对象。
区别:当参数为一般数组时,两个函数结果相同;当参数本身就是ndarray类型时,array会新建一个ndarray对象,作为参数的副本,但是asarray不会新建,而是与参数共享同一个内存。重点就是这个共享内存。

参考文章:

https://blog.csdn.net/kobe_academy/article/details/99712062
https://blog.csdn.net/pyjishu/article/details/105433944
https://blog.csdn.net/rifengxxc/article/details/75008427
https://blog.csdn.net/Sophia_11/article/details/84975009
np.sum()更多理解见:
https://blog.csdn.net/rifengxxc/article/details/75008427
https://blog.csdn.net/Sophia_11/article/details/84975009
numpy的数据类型,可以参看: http://www.runoob.com/numpy/numpy-dtype.html

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Max_J999

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值