假设您有一个类似于 CSV 文件的数据集,其中包含轻度敏感信息,例如在 12 年级英语课上谁给谁发了一张便条。虽然如果这些数据泄露出去并不是危机,但最好去掉识别信息,这样数据就可以公开、与合作者共享等。数据看起来像这样:
给予者、接受者:
安娜、
乔安娜、马克·
马克、明迪
·明迪、乔
你将如何处理这个列表,为每个名称分配一个唯一但任意的标识符,然后去掉这些名称并用 Python 中的标识符替换它们,这样你最终会得到类似的结果:
1,2
1,3
3,4
4,2
假设您有一个类似于 CSV 文件的数据集,其中包含轻度敏感信息,例如在 12 年级英语课上谁给谁发了一张便条。虽然如果这些数据泄露出去并不是危机,但最好去掉识别信息,这样数据就可以公开、与合作者共享等。数据看起来像这样:
给予者、接受者:
安娜、
乔安娜、马克·
马克、明迪
·明迪、乔
你将如何处理这个列表,为每个名称分配一个唯一但任意的标识符,然后去掉这些名称并用 Python 中的标识符替换它们,这样你最终会得到类似的结果:
1,2
1,3
3,4
4,2
您可以使用hash()
生成唯一的任意标识符,它将始终返回特定字符串的相同整数:
with open("data1.txt") as f:
lis=[x.split(",") for x in f]
items=[map(lambda y:hash(y.strip()),x) for x in lis]
for x in items:
print ",".join(map(str,x))
....:
-1319295970,1155173045
-1319295970,-1963774321
-1963774321,-1499251772
-1499251772,1155173045
或者您也可以使用iterools.count
:
In [80]: c=count(1)
In [81]: with open("data1.txt") as f:
lis=[map(str.strip,x.split(",")) for x in f]
dic={}
for x in set(chain(*lis)):
dic.setdefault(x.strip(),next(c))
for x in lis:
print ",".join(str(dic[y.strip()]) for y in x)
....:
3,2
3,4
4,1
1,2
或使用 itertools 的配方改进我以前的答案unique_everseen
,您可以获得确切的答案:
In [84]: c=count(1)
In [85]: def unique_everseen(iterable, key=None):
seen = set()
seen_add = seen.add
if key is None:
for element in ifilterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element
....:
In [86]: with open("data1.txt") as f:
lis=[map(str.strip,x.split(",")) for x in f]
dic={}
for x in unique_everseen(chain(*lis)):
dic.setdefault(x.strip(),next(c))
for x in lis:
print ",".join(str(dic[y.strip()]) for y in x)
....:
1,2
1,3
3,4
4,2
names = """
Anna,Joe
Anna,Mark
Mark,Mindy
Mindy,Joe
"""
nameset = set((",".join(names.strip().splitlines())).split(","))
for i,name in enumerate(nameset):
names = names.replace(name,str(i))
print names
2,1
2,3
3,0
0,1
要真正匿名化数据,您需要名称的随机别名。哈希对此很有用,但如果您只想将每个名称映射到一个整数,您可以执行以下操作:
from random import shuffle
data = [("Anna", "Joe"), ("Anna", "Mark"), ("Mark", "Mindy"), ("Mindy", "Joe")]
names = list(set(x for pair in data for x in pair))
shuffle(names)
aliases = dict((k, v) for v, k in enumerate(names))
munged = [(aliases[a], aliases[b]) for a, b in data]
这会给你类似的东西:
>>> data
[('Anna', 'Joe'), ('Anna', 'Mark'), ('Mark', 'Mindy'), ('Mindy', 'Joe')]
>>> names
['Mindy', 'Joe', 'Anna', 'Mark']
>>> aliases
{'Mindy': 0, 'Joe': 1, 'Anna': 2, 'Mark': 3}
>>> munged
[(2, 1), (2, 3), (3, 0), (0, 1)]
然后,您可以(如果需要)从别名中获取名称,反之亦然:
>>> aliases["Joe"]
1
>>> names[2]
'Anna'
您可以使用hash
为每个名称获取唯一 ID,可以使用字典将名称映射到它们的值(如果您希望数字与示例中的数字相同):
data = [("Anna", "Joe"), ("Anna", "Mark"), ("Mark", "Mindy"), ("Mindy", "Joe")]
names = {}
def anon(name):
if not name in names:
names[name] = len(names) + 1
return names[name]
result = []
for n1, n2 in data:
result.append((anon(n1), anon(n2)))
print names
print result
运行时会给出:
{'Mindy': 4, 'Joe': 2, 'Anna': 1, 'Mark': 3}
[(1, 2), (1, 3), (3, 4), (4, 2)]
首先,将文件读入行列表:
import csv
with open('myFile.csv') as f:
rows = [row for row in csv.reader(f)]
此时,您可以构建一个 dict 来保存映射:
nameSet = set()
for row in rows:
for name in row:
nameSet.add(name)
map = dict((name, i) for i, name in enumerate(nameSet))
或者,您可以直接构建字典:
nextID = 0
map = {}
for row in rows:
for name in row:
if name not in map:
map[name] = nextID
nextID += 1
无论哪种方式,您都会再次浏览这些行并应用映射:
output = [[map[name] for name in row] for row in rows]