对数据集进行k匿名(k-Anonymity)处理(python)——以adult数据集为例
k匿名(k-Anonymity)
k匿名技术参考论文:L.Sweeney. Achieving k-anonymity privacy protection using generalization and suppression. International Journal on Uncertainty, Fuzziness and Knowledge-based Systems,10(5), 2002; 571-588.
其中对于k匿名的定义如下:
对于一个数据集的不同属性,或者说,不同列。可以根据其作用粗略划分为三种,标识符,准标识符,与隐私数据。
标识符能够唯一确定一项数据,而不同准标识符的组合也可能可以确定一项数据。而隐私数据顾名思义,是隐私保护的对象。
身份证号 | 性别 | 家庭住址 | 所得疾病 |
123456789 | 男 | xx市xx街道xx小区 | 某传染病 |
例如上表,身份证号即是标识符,而性别和家庭住址可以作为准标识符,他们具备一定的信息,并且组合在一起之后有可能可以确定这一条数据的所有者。而所得疾病即是我们需要保护的隐私信息。
k匿名需要满足的条件就是,对于准标识符的任意组合,搜索出来的结果都需要至少有k条。
例如,上表中以(性别,家庭住址)为准标识符,那么以(男,xx市xx街道xx小区)为条件,去数据集中搜索,最终得到至少k条数据,类似的,用其他任何可能的条件去搜索,最终得到的数据条数都大于等于k,那么就说这个数据集满足k匿名。
精确度的计算
论文中对于精确度的定义如下:
我个人认为这个公式应当翻译成:
prec=1-(各个准标识符的泛化程度(当前高度h/总泛化树高度)之和)/(准标识符个数)
adult数据集
数据集官方网址:UCI Machine Learning Repository: Adult Data Set
对于数据集的介绍引用自
云隐雾匿 的 Adult数据集分析(一)
Adult数据集(即“人口普查收入”数据集),由美国人口普查数据集库 抽取而来,其中共包含48842条记录,年收入大于50k美元的占比23.93%,年收入小于50k美元的占比76.07%,并且已经划分为训练数据32561条和测试数据16281条。 该数据集类变量为年收入是否超过50k美元,属性变量包括年龄、工种、学历、职业等 14类重要信息,其中有8类属于类别离散型变量,另外6类属于数值连续型变量。该数据集是一个分类数据集,用来预测年收入是否超过50k美元。
该数据集总共15列,包括14个属性与一个结论。
结论的取值为字符串,仅有两个:' >50K'和' <=50K'。
注意,该数据集中的每个字符串前面都有一个空格。
全部属性标签如下:
#属性标签
attributeLabels =["age", #0年龄 int64 "workclass", #1工作类型 object "fnlwgt", #2人口特征权重 int64 "education", #3学历 object "education_num", #4受教育时间 int64 "marital_status", #5婚姻状态 object "occupation", #6职业 object "relationship", #7关系 object "race", #8种族 object "sex", #9性别 object "capital_gain", #10资本收益 int64 "capital_loss", #11资本损失 int64 "hours_per_week", #12每周工作小时数 int64 "native_country", #13原籍 object "wage_class"] #14收入类别 object
对于第三个属性‘fnlwgt’,网上众说纷纭,有说是什么信息录入员编号的(然而实际数据长短不一,不太可能),又说代表这条数据真正的人数的(计算之后大概60多亿,也不太可能)。
感觉都不对,不过官方文档adult.names中有给出解释:
根据最后一段可以看出这个所谓“最终权重”应当包含了人口特征信息,具体包含哪些信息则可以参考上文给出的 3 sets of controls。
但是最后一句话有说,这个权重数据尽在州内适用,然而这个数据集中汇聚了全部51个州的数据,所以如果我没有翻译错的话,这个人口特征权重(fnlwgt)实际上不具备参考价值。
代码实现
1.导入包与导入一些字符串配置
import numpy as np
import pandas as pd#配置信息
#数据集文件路径
censusData_FilePath='data/adult.data'
#属性标签
attributeLabels =["age", #0年龄 int64 "workclass", #1工作类型 object "fnlwgt", #2人口特征权重 int64 "education", #3学历 object "education_num", #4受教育时间 int64 "marital_status", #5婚姻状态 object "occupation", #6职业 object "relationship", #7关系 object "race", #8种族 object "sex", #9性别 object "capital_gain", #10资本收益 int64 "capital_loss", #11资本损失 int64 "hours_per_week", #12每周工作小时数 int64 "native_country", #13原籍 object "wage_class"] #14收入类别 object #准标识符
quasi_identifier_list=[]
quasi_identifier_DGH_list=[]
quasi_identifier_VGH_list=[]
quasi_identifier_height_list=[]
2.引入准标识符信息
泛化树通过父母节点表示法存储在数组中,这样就能够快速地找到每个节点的父母节点,同时为了方便计算,增加高度项,代表当前节点在泛化树中的高度。
例如,工作类型的泛化树如下:
由于后续使用了replace这个函数,所以标签的字符串不能一致,加上了hx作为后缀,x为层高。
#marital-status属性标签
marital_attributeLabels=['***', #0抑制标签'Married-h2', #1已婚'Alone', #2独自一人'Married-h1', #3已婚'Single', #4单身 'Widowhood', #5鳏寡'Married-civ-spouse', #已婚-公民-配偶'Married-AF-spouse', #已婚-无房-配偶'Separated', #分居'Divorced', #离婚'Never-married', #未婚'Widowed', #寡居'Married-spouse-absent' #已婚-配偶-不在]
#marital-status的泛化树
vgh_marital=pd.DataFrame({'value': marital_attributeLabels,'parent':[-1,0,0,1,2,2,3,3,3,4,4,5,5],'height':[3,2,2,1,1,1,0,0,0,0,0,0,0]})quasi_identifier_list.append(attributeLabels[5]) #将marital-status设置为准标识符
quasi_identifier_DGH_list.append(3)
quasi_identifier_VGH_list.append(vgh_marital)
quasi_identifier_height_list.append(0)print(vgh_marital)
另外再加两个准标识符,种族与婚姻状况。
#race属性标签
race_attributeLabels =[ '***', #0抑制标签'White-h1', #1白人'Non-White', #2非白人'White', #3白人'Asian-Pac-Islander', #亚洲-太平洋-伊斯兰人'Amer-Indian-Eskimo', #美洲-印第安人-爱斯基摩人'Other', #其他'Black' #黑人]
#workclass的泛化树
vgh_race=pd.DataFrame({'value': race_attributeLabels,'parent':[-1,0,0,1,2,2,2,2],'height':[2,1,1,0,0,0,0,0]})quasi_identifier_list.append(attributeLabels[8]) #将workclass设置为准标识符
quasi_identifier_DGH_list.append(2)
quasi_identifier_VGH_list.append(vgh_race)
quasi_identifier_height_list.append(0)print (vgh_race)
#marital-status属性标签
marital_attributeLabels=['***', #0抑制标签'Married-h2', #1已婚'Alone', #2独自一人'Married-h1', #3已婚'Single', #4单身 'Widowhood', #5鳏寡'Married-civ-spouse', #已婚-公民-配偶'Married-AF-spouse', #已婚-无房-配偶'Separated', #分居'Divorced', #离婚'Never-married', #未婚'Widowed', #寡居'Married-spouse-absent' #已婚-配偶-不在]
#marital-status的泛化树
vgh_marital=pd.DataFrame({'value': marital_attributeLabels,'parent':[-1,0,0,1,2,2,3,3,3,4,4,5,5],'height':[3,2,2,1,1,1,0,0,0,0,0,0,0]})quasi_identifier_list.append(attributeLabels[5]) #将marital-status设置为准标识符
quasi_identifier_DGH_list.append(3)
quasi_identifier_VGH_list.append(vgh_marital)
quasi_identifier_height_list.append(0)print(vgh_marital)
如果还要增加其他准标识符的话,以类似的格式加上就可以了。但是数值型属性需要先分段,不能直接使用。
3.导入数据集与初步处理
这个数据集有2个要处理的地方,首先是缺失值表示为‘ ?’,需要转化为NAN以便处理,然后是字符串的前端会有一个空格,需要去除。
对于有缺失值的数据,由于个数不多,大概2000+条,所以直接删去。
#导入数据集
censusData_Set=pd.read_csv(censusData_FilePath,names=attributeLabels)# 将缺失值部分的“ ?” 置为空,即 np.NaN,便于使用pandas来处理缺失值
censusData_Set = censusData_Set.replace(" ?", np.NaN)#类型为字符串的标签
attributeLabels_str=["workclass","education", "marital_status","occupation","relationship","race","sex","native_country","wage_class"]
#删除数据值前的空格
for label in attributeLabels_str:censusData_Set[label] = censusData_Set[label].str.strip()#删除包含缺失值的行
censusData_Set.dropna(inplace=True)
#重置索引
censusData_Set.reset_index(drop=True, inplace=True)
4.检查数据集是否满足k匿名
将所有出现过的准标识符组合存入字典并计数,最后字典中个数最小的项如果数量大于等于k,显然就满足k匿名。
#检验是否满足k匿名#将所有准标识符的组合存入字典,值为出现次数。
def group_data(testedSet):quasiDict = {}for item in testedSet.itertuples():#--------------------------------------------------------------#将准标识符转化为字符串item_statement=''for label in quasi_identifier_list:item_statement=item_statement+getattr(item,label)+' '#--------------------------------------------------------------#如果该准标识符组合已经出现过了,则计数+1if item_statement in quasiDict.keys():quasiDict[item_statement] += 1#如果该准标识符组合没有出现过,则新建记录else:quasiDict[item_statement]=1#返回字典return quasiDict#判断数据集testedSet是否满足k匿名,是则返回true,否则返回false
def if_k(testedSet,k):#对数据集进行分组,获得组合数量ans_dict=group_data(testedSet)#-----------------------------------------------------------------#展示准标识符组合print('')print (ans_dict)print('')#-----------------------------------------------------------------min_k=None#遍历分组字典,取出最小的重复个数,赋值给min_kfor i in ans_dict:if min_k is None or ans_dict[i]<min_k :min_k=ans_dict[i];#如果字典的最小k值大于等于给定的k值,则满足k匿名if min_k>=k:return Trueelse:return False
5.泛化
父母节点数组存储的泛化树容易得到节点的父母节点,因此泛化的代码比较容易。用节点的父母节点替换本节点即可。
#对数据集tempDataSet(dataframe)的属性列attr(String)进行泛化
#vgh(dataframe)是泛化树
def Generalization_attr(tempDataSet, attr, vgh, h):for index,row in vgh.iterrows():if row.height==h:tempDataSet.replace({attr:row.value},vgh.loc[row.parent].value,inplace=True)
6.运行主函数
输入为:数据集censusData_Set;k匿名需要满足的k值k_Anonymity;
输出为:泛化后满足k匿名的数据集censusData_Set;精确度prec;
#演示取值:16000;2;15;140
k_Anonymity=15#泛化次数计数,初始化为所有准标识符泛化次数之和
gen_count=0
for index in range(len(quasi_identifier_DGH_list)):gen_count+=quasi_identifier_DGH_list[index]while if_k(censusData_Set,k_Anonymity) is False:for index in range(len(quasi_identifier_list)):#如果已经到达了泛化顶点if quasi_identifier_height_list[index]>=quasi_identifier_DGH_list[index]:continue#-----------------------------------------------------------------#泛化Generalization_attr(censusData_Set,quasi_identifier_list[index],quasi_identifier_VGH_list[index],quasi_identifier_height_list[index])#-----------------------------------------------------------------#泛化次数-1gen_count-=1#泛化高度+1quasi_identifier_height_list[index]+=1if if_k(censusData_Set,k_Anonymity):breakprint ('当前泛化高度:')for index in range(len(quasi_identifier_list)):print(quasi_identifier_list[index]+':'+str(quasi_identifier_height_list[index]))#直至无法泛化if gen_count==0:print('泛化失败')breakprint ('当前泛化高度:')
for index in range(len(quasi_identifier_list)):print(quasi_identifier_list[index]+':'+str(quasi_identifier_height_list[index]))print('当前k值为:')
print(k_Anonymity)
print ('精确度为:')
prec=0
for index in range(len(quasi_identifier_list)):prec+=(quasi_identifier_height_list[index])/(quasi_identifier_DGH_list[index])
prec=1-(prec/len(quasi_identifier_list))print (prec)
对数据集进行k匿名(k-Anonymity)处理(python)——以adult数据集为例相关推荐
- k-Anonymity(K匿名)之暴力搜索大法
k-Anonymity(K匿名)之暴力搜索大法 k匿名 k-Anonymity(K匿名)之暴力搜索大法 写在前面 代码 读取文件 分类 距离矩阵 正向搜索 逆向匹配 匿名化处理 写入文件 实验结果 写 ...
- k折交叉验证法python实现_Jason Brownlee专栏| 如何解决不平衡分类的k折交叉验证-不平衡分类系列教程(十)...
作者:Jason Brownlee 编译:Florence Wong – AICUG 本文系AICUG翻译原创,如需转载请联系(微信号:834436689)以获得授权 在对不可见示例进行预测时,模型评 ...
- K均值 - 案例实现(python)
K均值 K均值案例(python) 背景介绍 算法定义 K值的选取 案例实现(python) 数据集 代码实现 运行结果 总结 参考文献 K均值案例(python) k均值聚类算法(k-means c ...
- PRML第九章读书笔记——Mixture Models and EM K均值/K中心点、高斯混合奇异性、EM观点下的高斯混合/K-means/混合伯努利分布/贝叶斯线性回归、推广EM算法
目录 9.1 K-means Clustering P429 K中心点算法K-medoids 9.2 Mixtures of Gaussians P433 高斯混合的奇异性 9.3 An Altern ...
- 机器学习——K近邻分类算法及python代码实现
<机器学习:公式推导与代码实践>鲁伟著读书笔记. K近邻(K-nearest neighbor,K-NN)算法是一种经典的监督学习的分类方法.K近邻算法是依据新样本与k个与其相邻最近的样本 ...
- K近邻算法讲解与python实现(附源码demo下载链接)
k近邻算法概述 对应demo源码及数据:传送门 K近邻(k-Nearest Neighbor,简称kNN)算法,是一种应用很广泛的监督学习算法.它非常有效且易于掌握,其工作机制也很简单:给定测试样本, ...
- C语言学习之求∑k(k=100)+∑K*k(k=50)+∑1/k(k=10)
求∑k(k=100)+∑K*k(k=50)+∑1/k(k=10) #include <stdio.h> #include <math.h> void main(){double ...
- C语言学习之编程实现:输入长方形的两个边长a, b和一个整数k。k=1时,输出长方形的周长 l; k=2时 ,输出长方形的面积s;当k=3时 , 输出长方形的周长1和面积s
C语言学习 编程实现:输入长方形的两个边长a, b和一个整数k.k=1时,输出长方形的周长 l; k=2时 ,输出长方形的面积s;当k=3时 , 输出长方形的周长1和面积s #include < ...
- Macbook pro笔记本键盘失灵了(u,i,o,j,k,l,k,m无效了)解决办法
今天在使用Macbook pro时,突然发现键盘失灵了,(u,i,o,j,k,l,k,m无效了),经过寻找一阵资料发现,原来是开启了鼠标键. 解决方法如下: 在辅助功能-鼠标与触摸板-启用鼠标键,关掉 ...
最新文章
- 将TVM集成到PyTorch
- Android 多语言
- 《Drupal实战》——1.4 常见配置
- 并发编程-02并发基础CPU多级缓存和Java内存模型JMM
- HU 3496 Watch The Movie---二维费用
- html手机网站font-size:16em,px、em、rem
- Dom4j完整教程~Document对象相关
- C++设计模式-职责链模式
- 算法--最大连续子序列和(动态规划,分而治之)
- 【写作技巧】毕业论文写作要素和步骤有哪些呢?
- 《深入浅出深度学习:原理剖析与python实践》第八章前馈神经网络(笔记)
- 无人机群编队分析的定位问题 分析与思考-1(数学建模竞赛2022年B题)
- 自来水公司SCADA调度系统方案
- 基于java的超市积分管理系统设计(含源文件)
- 心理学经典理论与著作
- linux reedme常用单词,【每天打卡记单词】高中英语必背单词3500(Q/R)
- SketchUp + Photoshop:别墅平面图制作教程
- 数据库系统教程(第二版何玉洁)课后数据库上机实验答案
- discuz 模版 php函数,dz function template 函数解析
- python123部分习题2