题目
(1)实际中,很多信息都可以简化为只有两个不同的选项,例如性别、近14天是否出省、有无家族遗传病史、是否绿码等,研究附件中的两组二元数据,保证每个个体的信息都能得到保护,分别给出一个隐藏数据量最少的方案,并建立二元数据表隐私保护的一般数学模型。
(2)考虑多元数据表,研究附件中的两组多元数据,给出一个隐藏数据量最少的方案,并建立多元数据隐私保护的一般数学模型。
(3)如果个体能够隐藏在一个至少包含p个个体的数据组中,则称该个体得到了p-重保护(p>=2),下图是一个分别有2-重保护和4-重保护的数据隐藏示例。建立多重保护数据隐藏的数学模型,对附件数据的p=3,5,8-重保护问题,分别给出情形的最佳隐藏方案。
求解
1模型建立
2模型建立
3模型建立
代码
聚类
import pandas as pd
import numpy as np
from k_means_constrained import KMeansConstrained
X=pd.read_excel('data1.xlsx',sheet_name='ey1')
X=np.array(X)
model1=KMeansConstrained(
n_clusters=40,
size_min=2,
size_max=3,
random_state=0)
#model.fit_predict(X)
model1.fix(X)
读取excel表到数组
import pandas as pd
import xlrd2 as xlrd
import numpy as np
import openpyxl
data = []
excel_file = 'B题附件.xlsx'
#将第一个表 转换成数组
book = xlrd.open_workbook(excel_file)
sheet0= book.sheets()[3] #更改选取的维度 改变 选取的表
nrows = sheet0.nrows
for i in range(0, nrows):
row_data = sheet0.row_values(i)
data.append(row_data)
data = np.array(data).astype(int).tolist()
# print(len(data))
自定义函数
#某个数在list的位置
def localist(temp, list1):
for i in range(len(list1)):
if list1[i] == temp:
loca = i
return loca
#某个数在list的所有位置
def localistall(temp, list1):
id=[]
for i in range(len(list1)):
if list1[i] == temp:
id.append(i)
return id
#计算距离与 位置
def caldis(temp1,temp2):
loc=[]
dis=0
for i in range(len(temp1)):
if temp1[i]!=temp2[i]:
dis=dis+1
loc.append(i)
return loc,dis
#求距离最小值 的 位置
def minindex(list1):
min=list1[0][1]
loc=0
for i in range(len(list1)):
if min>list1[i][1]:
min=list1[i][1]
loc=i
return loc
加*处理
先求出不重复的数据项sdata
将数据项数量最多的项maxdata 与 第二多的项 secdatas 之间求距离
找到 与maxdata 距离最近的secdata,将不同的位置取值为-1,
然后 将处理好后的 数据 添加到 处理后的数组quxinghou中
将经过处理的两个数据 从sdata中删除
重复以上操作 直到 sdata<=1
对于最后一个sdata 求它与处理后的数据最接近的项,即归为该类
#找到独立的不重复的数
l=len(data)
sdata=[] #独立的项
sid=[] #对于id
for i in range(l):
if data[i] not in sdata:
sdata.append(data[i])
# list0=[i]
# sid.append(list0)
sid.append([i])
else:
j=localist(data[i],sdata)
sid[j].append(i)
quxinghou=[] #取*后
xingid=[]
it=0
while(len(sdata) > 1):
# 求 sid 的 每个成员的 长度
lensid = []
for i in range(len(sid)):
lensid.append(len(sid[i]))
it=it+1
print('*******************************'+str(it)+'*******************************')
maxdataid=lensid.index(max(lensid)) #求列表最大值 第一次出现 对应下标
maxdata=sdata[maxdataid]
#找数量第二大的值
maxnum=max(lensid)
maxdataidall = localistall(maxnum,lensid)
if len(maxdataidall)==1 : #当仅有一个数量最大项
a = maxnum - 1
while(a not in lensid):
if a == 0:
break
a = a - 1
if a!=0:
secnum=a
else:
secnum = maxnum
else:
secnum=maxnum
print('maxnum:',maxnum,'maxdataid:',maxdataid)
secid=localistall(secnum,lensid) #数量第二大的值 对应的所有成员的id
print('secnum:', secnum)
print('secid',secid)
# 如果包含maxdataid 去除
if maxdataid in secid:
secid.remove(maxdataid)
#计算数量最多 与数量第二多的成员之间的距离
juli=[]
print('secid:',secid)
print('sdata:',sdata)
print('sdata长度:',len(sdata))
for j in secid:
# print(sdata[j])
juli.append(caldis(maxdata,sdata[j]))
# print(juli)
minloc=minindex(juli) #与数量最大项maxdata 的 距离最小的 数量第二大项 在 secid中的下标
mintemp=juli[minloc]
# maxdata 与 sdata[secid[minloc]] 的距离是 mintemp[1],不同项是 mintemp[0]
# print(maxdata)
secdataid=secid[minloc]
secdata=sdata[secdataid]
# print(secdata)
# print(mintemp)
#将元素取※ 并添加到quxinghou
for i in range(len(mintemp[0])):
maxdata[mintemp[0][i]]=-1
# secdata[mintemp[0][0]]=-1
quxinghou.append(maxdata)
xingid.append(sid[maxdataid]+sid[secdataid]) #合并两个列表
# print(quxinghou)
# print(xingid)
# sdata[maxdataid]=maxdata
# sdata[secdataid]=secdata
# print(maxdataid)
# print(secdataid)
# print(sdata)
#缩减已处理的数据项
sdata.remove(maxdata) #remove 删除指定元素
sdata.remove(secdata)
a=sid[maxdataid]
b=sid[secdataid]
# sid.pop(maxdataid) # 删除下标 的元素
# sid.pop(secdataid) # 有问题 删除一个元素后 下标不对应
sid.remove(a)
sid.remove(b)
# print(quxinghou)
# print(xingid)
#处理最后一个sdata
if len(sdata)==1:
data0=sdata[0]
id=sid[0]
#求该数 与quxinghou的最小距离
juli=[]
for j in range(len(quxinghou)):
juli.append(caldis(data0,quxinghou[j]))
minloc=minindex(juli) #与data 的 距离最小的 项 在 quxinghou中的下标
mintemp=juli[minloc]
print(data0,id)
print(mintemp)
print(quxinghou[minloc])
# 与data 与 quxinghou[minloc] 的距离是 mintemp[1],不同项是 mintemp[0]
if mintemp[1]<=10: #最后一个数一般都会重复 不处理了
# xingid[minloc].append(id) #合并两个列表 有问题
xingid[minloc]=xingid[minloc]+id
# print(quxinghou)
# print(xingid)
sum=0
for i in range(len(xingid)):
sum=sum+len(xingid[i])
# print(sum)
if sum!=l:
print('出错了!!!!!!')
#恢复回 数组
resl=[]
#建立l大小的空list
for i in range(l):
resl.append([])
sumx=0
# print()
for i in range(len(quxinghou)):
for j in xingid[i]:
# print(i,j)
# print(quxinghou[i])
resl[j]=quxinghou[i]
for z in range(len(quxinghou[i])):
if quxinghou[i][z]==-1:
sumx=sumx+1
print(resl)
print(sumx)
将list写入Excel文件
# 把二维列表存入excel中
def writeToExcel(file_path, new_list):
# total_list = [['A', 'B', 'C', 'D', 'E'], [1, 2, 4, 6, 8], [4, 6, 7, 9, 0], [2, 6, 4, 5, 8]]
wb = openpyxl.Workbook()
ws = wb.active
ws.title = 'resl'
for r in range(len(new_list)):
for c in range(len(new_list[0])):
ws.cell(r + 1, c + 1).value = new_list[r][c]
# excel中的行和列是从1开始计数的,所以需要+1
wb.save(file_path) # 注意,写入后一定要保存
print("成功写入文件: " + file_path + " !")
return 1
writeToExcel('resl_dy2.xlsx',resl)
list技巧
某元素是否在列表中
if data[i] not in sdata:
求列表最大值 第一次出现 对应下标
maxdataid=lensid.index(max(lensid)) #求列表最大值 第一次出现 对应下标
列表去除元素
sdata.remove(maxdata) #remove 删除指定元素
sid.pop(maxdataid) # 删除下标 的元素
两个列表的元素拼接成一个列表
sid[maxdataid]+sid[secdataid] #合并两个列表成一个列表
建立指定大小的列表
#建立l大小的空list
for i in range(l):
resl.append([])
k重保护
添加了一个数量第三多的项 仅限k=3有用
import pandas as pd
import xlrd2 as xlrd
import numpy as np
import openpyxl
data = []
excel_file = 'B题附件.xlsx'
kk=5 #k重隐私保护
#将第一个表 转换成数组
book = xlrd.open_workbook(excel_file)
sheet0= book.sheets()[3] #更改选取的维度 改变 选取的表
nrows = sheet0.nrows
for i in range(0, nrows):
row_data = sheet0.row_values(i)
data.append(row_data)
data = np.array(data).astype(int).tolist()
# print(len(data))
#找到独立的不重复的数
l=len(data)
sdata=[] #独立的项
sid=[] #对于id
#某个数在list的位置
def localist(temp, list1):
for i in range(len(list1)):
if list1[i] == temp:
loca = i
return loca
for i in range(l):
if data[i] not in sdata:
sdata.append(data[i])
# list0=[i]
# sid.append(list0)
sid.append([i])
else:
j=localist(data[i],sdata)
sid[j].append(i)
kuan=len(sdata[0])
#求 sid 的 每个成员的 长度
lensid=[]
for i in range(len(sid)):
lensid.append(len(sid[i]))
#某个数在list的所有位置
def localistall(temp, list1):
id=[]
for i in range(len(list1)):
if list1[i] == temp:
id.append(i)
return id
#计算距离与 位置
def caldis(temp1,temp2):
loc=[]
dis=0
for i in range(len(temp1)):
if temp1[i]!=temp2[i]:
dis=dis+1
loc.append(i)
return loc,dis
#求距离最小值 的 位置
def minindex(list1):
min=list1[0][1]
loc=0
for i in range(len(list1)):
if min>list1[i][1]:
min=list1[i][1]
loc=i
return loc
quxinghou=[] #取*后
xingid=[]
it=0
while(len(sdata) > 0):
# 求 sid 的 每个成员的 长度
lensid = []
for i in range(len(sid)):
lensid.append(len(sid[i]))
it=it+1
print('*******************************'+str(it)+'*******************************')
maxdataid=lensid.index(max(lensid)) #求列表最大值 第一次出现 对应下标
maxdata=sdata[maxdataid]
#找数量第二大的值
maxnum=max(lensid)
maxdataidall = localistall(maxnum,lensid)
if len(maxdataidall)==1 : #当仅有一个数量最大项
a = maxnum - 1
while(a not in lensid):
if a == 0:
break
a = a - 1
if a!=0:
secnum=a
else:
secnum = maxnum
else:
secnum=maxnum
print('maxnum:',maxnum,'maxdataid:',maxdataid)
secid=localistall(secnum,lensid) #数量第二大的值 对应的所有成员的id
print('secnum:', secnum)
print('secid',secid)
# 如果包含maxdataid 去除
if maxdataid in secid:
secid.remove(maxdataid)
#计算数量最多 与数量第二多的成员之间的距离
juli=[]
print('secid:',secid)
print('sdata:',sdata)
print('sdata长度:',len(sdata))
for j in secid:
# print(sdata[j])
juli.append(caldis(maxdata,sdata[j]))
# print(juli)
minloc=minindex(juli) #与数量最大项maxdata 的 距离最小的 数量第二大项 在 secid中的下标
mintemp=juli[minloc]
# maxdata 与 sdata[secid[minloc]] 的距离是 mintemp[1],不同项是 mintemp[0]
# print(maxdata)
secdataid=secid[minloc]
secdata=sdata[secdataid]
# print(secdata)
# print(mintemp)
# 满足k重
if secnum + maxnum >= kk:
#将元素取※ 并添加到quxinghou
for i in range(len(mintemp[0])):
maxdata[mintemp[0][i]]=-1
# secdata[mintemp[0][0]]=-1
quxinghou.append(maxdata)
xingid.append(sid[maxdataid]+sid[secdataid]) #合并两个列表
# print(quxinghou)
# print(xingid)
# sdata[maxdataid]=maxdata
# sdata[secdataid]=secdata
# print(maxdataid)
# print(secdataid)
# print(sdata)
#缩减已处理的数据项
sdata.remove(maxdata) #remove 删除指定元素
sdata.remove(secdata)
a=sid[maxdataid]
b=sid[secdataid]
# sid.pop(maxdataid) # 删除下标 的元素
# sid.pop(secdataid) # 有问题 删除一个元素后 下标不对应
sid.remove(a)
sid.remove(b)
elif sum(lensid)>= kk*2:
thnum=kk-secnum-maxnum #第三个项num
print('thnum',thnum)
while(thnum<secnum & thnum not in lensid):
thnum=thnum+1
# if thnum > secnum:
thid = localistall(thnum, lensid) # 第三个数量的值 对应的所有成员的id
# 如果包含maxdataid 去除
if maxdataid in thid:
thid.remove(maxdataid)
if secdataid in thid:
thid.remove(secdataid)
# if len(thid)==0:
# sdataid=[i for i in range(len(sdata))]
# sdataid.remove(maxdataid)
# sdataid.remove(secdataid)
# print('sdataid',sdataid)
if len(sdata)==2: #只有两个数据了
for i in range(kuan):
if maxdata[i] == secdata[i] :
xingdata[i] = maxdata[i]
quxinghou.append(xingdata)
xingid.append(sid[maxdataid] + sid[secdataid] ) # 合并列表
# 缩减已处理的数据项
sdata.remove(maxdata) # remove 删除指定元素
sdata.remove(secdata)
break
# thid = [sdataid[0]]
dis=[]
print('thid:',thid)
for j in range(len(thid)):
# print(j)
dis0=0
thdata=sdata[thid[j]]
for i in range(kuan):
if maxdata[i] != secdata[i] :
dis0=dis0+maxnum+secnum
if maxdata[i] != thdata[i]:
dis0 = dis0 + maxnum + thnum
if secdata[i] != thdata[i]:
dis0 = dis0 + secnum + thnum
dis.append(dis0)
# print('dis',dis)
id0 = dis.index(min(dis))
thdataid=thid[id0]
thdata=sdata[thdataid]
xingdata = [-1 for i in range(kuan)]
for i in range(kuan):
if maxdata[i] == secdata[i] & maxdata[i] == thdata[i] & secdata[i] == thdata[i]:
xingdata[i]=maxdata[i]
quxinghou.append(xingdata)
xingid.append(sid[maxdataid] + sid[secdataid]+sid[thdataid]) # 合并列表
# print('maxdata',maxdata)
# print('secdata',secdata)
# print('thdata', thdata)
# 缩减已处理的数据项
sdata.remove(maxdata) # remove 删除指定元素
sdata.remove(secdata)
sdata.remove(thdata)
a = sid[maxdataid]
b = sid[secdataid]
c = sid[thdataid]
# sid.pop(maxdataid) # 删除下标 的元素
# sid.pop(secdataid) # 有问题 删除一个元素后 下标不对应
sid.remove(a)
sid.remove(b)
sid.remove(c)
else:
# 处理最后几个sdata
for i in range(len(sdata)) :
data0 = sdata[i]
id = sid[i]
# 求该数 与quxinghou的最小距离
juli = []
for j in range(len(quxinghou)):
juli.append(caldis(data0, quxinghou[j]))
minloc = minindex(juli) # 与data 的 距离最小的 项 在 quxinghou中的下标
mintemp = juli[minloc]
# print(data0, id)
# print(mintemp)
# print(quxinghou[minloc])
# 与data 与 quxinghou[minloc] 的距离是 mintemp[1],不同项是 mintemp[0]
if mintemp[1] <= 10: # 最后一个数一般都会重复 不处理了
# xingid[minloc].append(id) #合并两个列表 有问题
xingid[minloc] = xingid[minloc] + id
break
# print(quxinghou)
# print(xingid)
sum=0
for i in range(len(xingid)):
sum=sum+len(xingid[i])
# print(sum)
if sum!=l:
print('出错了!!!!!!')
#恢复回 数组
resl=[]
#建立l大小的空list
for i in range(l):
resl.append([])
sumx=0
# print()
for i in range(len(quxinghou)):
for j in xingid[i]:
# print(i,j)
# print(quxinghou[i])
resl[j]=quxinghou[i]
for z in range(len(quxinghou[i])):
if quxinghou[i][z]==-1:
sumx=sumx+1
print(resl)
print(sumx)
#Python 将list写入Excel文件
# 把二维列表存入excel中
def writeToExcel(file_path, new_list):
# total_list = [['A', 'B', 'C', 'D', 'E'], [1, 2, 4, 6, 8], [4, 6, 7, 9, 0], [2, 6, 4, 5, 8]]
wb = openpyxl.Workbook()
ws = wb.active
ws.title = 'resl'
for r in range(len(new_list)):
for c in range(len(new_list[0])):
ws.cell(r + 1, c + 1).value = new_list[r][c]
# excel中的行和列是从1开始计数的,所以需要+1
wb.save(file_path) # 注意,写入后一定要保存
print("成功写入文件: " + file_path + " !")
return 1
writeToExcel('resl_3k5.xlsx',resl)