杭电2022数模B题隐私保护动态规划

题目

(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)


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值