写专栏文章的时候一个比较头痛的问题就是原始数据的遮盖:毕竟医疗数据是比较敏感的东西,不可能直接往网上放。所以像Faker这样的工具就挺有用的了。
安装和导入
pip install Faker
使用pip安装以后,在代码中通过下面的方法导入
from faker import Faker
fake = Faker()
print(fake.name())
>> Ryan Gallagher
更换语言
既然我们是生成中文的病历数据,那肯定就要用中文。好在faker内置了中文库
from faker import Faker
fake = Faker('zh_CN')
fake.name()
Out[4]: '杨桂兰'
切换中文也很简单对吧。
要说美中不足的话,Faker的文档相对比较的弱,可读性比较强的也就是Welcome to Faker’s documentation!这个文档的第一页。不过另一方面,Faker本身的功能也很是直白,无非就是帮你生成各种符合一定规则的数据。所以,一个自然而然的问题就是,我现在想生成一种数据,怎么找到对应的命令呢?你可以看Providers。Faker里面内置了很多的Provider,我现在用的比较多的是profile,date_time, person这几个,另外还有一个python provider也很合用。
生成一个dataframe的数据
进入正题了,现在我想生成5个病人的基本资料,包括了记账号,住院号,姓名,性别,年龄,入院时间和出院时间。对于这些变量有下面的基本要求:记账号在15000到17000之间
住院号是五位数字,从00001开始向上计数,在当前的病人组住院号应该是200到350之间
姓名是中文姓名
性别只能是男/女两种
年龄是15到50之间的整数数字
入院时间是过去30天以内的某一天
出院时间要在入院时间以后(间隔一天以上)
这些要求是不会有人妄图用Excel去实现的,Python写起来都有点烦,Faker的话就简洁很多:
from faker import Faker
from datetime import date,datetime,timedelta
import pandas as pd
fake = Faker('zh_CN')
class PtDataGen:
def __init__(self):
self.data_dict = {}
def fake_data(self):
pt_profile = fake.profile()
self.data_dict['FPATNO']=f"{fake.pyint(15000,17000):05}"
self.data_dict['ZYH'] = f"{fake.pyint(200,350):05}"
self.data_dict['name']=pt_profile['name']
self.data_dict['gender']=pt_profile['sex']
self.data_dict['age']=fake.pyint(15,50)
self.data_dict['ruyuan']=fake.past_datetime(start_date="-30d",tzinfo=None)
self.data_dict['chuyuan']=fake.past_datetime(start_date=self.data_dict['ruyuan']+timedelta(days=1),tzinfo=None)
def get_data_series(self):
return pd.Series(self.data_dict)
def get_data_dict(self):
return self.data_dict
fake_data这个函数负责做上面提到的7个要求。这里需要特别Note的一个地方:如果把fake_data下面的这些生成测试数据的代码放在__init__里,等下用一个loop生成多个病人数据的时候你会发现,哎?怎么每一行的内容都一样呢?我发现只有先init,然后对init后的PtDataGen实例应用fake_data函数,才能让每一行的数据不一样。好了,接下来是如何用这个类生成一个dataframe的数据:
rst_list = []
for _ in range(10):
pt_data = PtDataGen()
pt_data.fake_data()
rst_list.append(pt_data.get_data_dict())
df_pt_list = pd.DataFrame(rst_list)
这里用到了路人乙小明:[api]必应词典查询api,naive implementation提到的将多行记录合成一个dataframe的方法。也是先生成一个空白list,通过遍历(for _ in range(10))逐次将弄好的字典往这个list里添加(append),最后将这个list转换成DataFrame生成的测试数据(姓名如有雷同纯属巧合)
这个东西在敏感数据遮罩的时候真的是太好用了。