赞
踩
本博文为分析学习github上的美年健康ai大赛的开源代码。
https://tianchi.aliyun.com/competition/introduction.htm?spm=5176.11409106.5678.1.1c9a560c15bKhJ&raceId=231654
https://github.com/yzbdt/tianchi_meinian_rank12_1st_season
本开源的代码共分为2个大的步骤,数据预处理与模型训练。
在数据预处理部分,分为了:
共8个步骤。
https://tianchi.aliyun.com/competition/information.htm?spm=5176.100067.5678.2.227e342dl5bS4j&raceId=231654
首先查看一下拿到手的数据集,其中包含2个特征文件和1个标签文件。如图:
查看特征文件内部数据:
共包含3列数据,分别是vid,table_id,field_result 病人id,检查项目id,检查结果。
对于标签文件,查看内部:
可知共6列,分别为病人id以及对应的5个标签值
参赛选手需要提交对每个个体的收缩压,舒张压,甘油三酯,高密度脂蛋白胆固醇和低密度脂蛋白胆固醇五项指标预测结果,以小数形式表示,保留小数点后三位。该结果将与个体实际检测到的数值进行对比。对于第j项指标,计算公式如下:
其中m为总人数,yi'为选手预测的第i个人的指标j的数值,yi为第i个人的指标j的实际检测值。最后的评价指标是五个预测指标评估结果之和:
def creat_label(): ''' 将标签文件进行分割 最终生成的是5个文件 每个文件都是vid以及对应的5个特征中的一个,且特征结果进行了一定处理 格式如: vid 血清低密度脂蛋白 002d1e4859fafd9ded2a2e1e7c839b62 1.444563269 92dd479df5e30ab6a0a1cf85ac53efc3 1.749199855 6bb59d517c4c70f8f50844d24fbd0355 1.297463147 0ebb42adae512906f7e1135da734ea63 1.004301609 ebe7811e919109c42c092abbd98b4ca6 1.166270937 :return: ''' path = './data/' # 添加数据目录 filename = 'meinian_round1_train_20180408.csv' # 标签数据集 llt = [30, 10, 0.01, 0.01, 0.01] # 每个字段的最小值 ult = [270, 200, 30, 20, 20] # 每个字段的最大值 df_train = pd.read_csv(path + filename, encoding='gbk') # 读取csv文件 # print(df_train.columns) # Index(['vid', '收缩压', '舒张压', '血清甘油三酯', '血清高密度脂蛋白', '血清低密度脂蛋白'], dtype='object') lst = list(df_train.columns)[1:] # 忽略第0个列名 从收缩压开始读取 5个文件描述的列名形成一个List for i in range(5): header = ['vid'] # header包含vid一个元素 header.append(lst[i]) # header包含[vid, xxx] temp_df = df_train[header].copy() # 在df_train中索引header记录的两个字段对应的列,提取出来做临时df l = temp_df.shape[0] # 此[vid, xxx]有多少样本 strs = lst[i] # 名称 data_pattern = path + 'throw_nan_label_' + strs + '.csv' if os.path.exists(data_pattern): # 存在则开启下一循环 continue for j in range(l): try: d = float(df_train[strs][j]) # 将对应字段的对应元素转化为float if d >= ult[i] or d <= llt[i]: # 异常判断 temp_df = temp_df.drop(j) # 超出范围直接扔掉 except: try: c = str(df_train[strs][j]).strip('<>+-=轻度乳糜') # 移除字符串头尾指定字符或字符序列 c = float(c) temp_df[strs][j] = c if c >= ult[i] or c <= llt[i]: temp_df = temp_df.drop(j) # 扔掉 except: try: temp_df = temp_df.drop(j) # 扔掉 except: pass # 不再做任何处理 temp_df = nums_log(temp_df, strs) # 将每一行strs对应的数据处理转化分布 temp_df.to_csv(path + 'throw_nan_label_' + strs + '.csv', index=False) # 生成文件
def nums_log(temp_df, strs): ''' :param temp_df: :param strs: :return: ''' temp = np.log(temp_df[strs].astype('float') + 1) # 每一行计算 temp_df[strs] = temp # 重新赋值 return temp_df
输出日志:
最终生成了5个文件:
每个文件都记录了病人id以及对应的指标,如其中一个文件:
在程序最后进行了正态分布的转换,使用 x=log(x+1) 这个公式,关于高斯转换的学习可以参考这里,写的非常全面:
http://baijiahao.baidu.com/s?id=1599068399235692908&wfr=spider&for=pc
截取部分如下:
对于异常检测算法,我们使用的特征是至关重要的,下面谈谈如何选择特征:
异常检测假设特征符合高斯分布,如果数据的分布不是高斯分布,异常检测算法也能够工作,但是最好还是将数据转换成高斯分布,例如使用对数函数:x=log(x+c),其中c为非负常数;或者x=xc,c为0-1之间的一个分数,等方法。
整理特征数据的主要工作就是将解压缩后得到的2个特征数据
进行合并,并整理成想要的格式。之前观察特征文件已经知道,原始的特征文件每一行是一个样本,其字段分别为:
病人id, 体检项目, 体检结果
因此可以确定的是,病人id必然会出现重复。正常情况下,一个病人对应多个体检项目,每个体检项目对应一个体检结果。因此期望将格式整理为:
体检项目1 | 检项目2 | ... | 检项目n | |
病人1 | ||||
病人2 | ||||
... | ||||
病人m |
def read_raw_data(): """ 整理数据,生成原始特征,最终效果: 项目1 项目2 项目3 ... 人1 xxx xxx xxx 人2 xxx xxx xxx 人3 xxx xxx xxx ... :return: """ path = './data/' data_pattern = path + 'raw_feature.csv' if os.path.exists(data_pattern): return # 存在则返回 counter = 0 # 计数 temp_lst = [[], [], []] # 二维数组 每个元素分别存储'vid', 'table_id', 'field_results' filename = 'meinian_round1_data_part1_20180408.txt' # 特征文件1 with open(path + filename, 'r', encoding='UTF-8-sig') as infile: # 读文件 columns = infile.readline().strip().split('$') # 读第0行 按照$分割 # print(columns) #['vid', 'table_id', 'field_results'] while True: # 开启一个循环 line = infile.readline().strip().split('$') # 分割每一行 if line == ['']: break # 读到最后退出 for i in range(3): temp_lst[i].append(line[i]) # 填充temp_lst 注意line[i]本身也是一个list counter += 1 # 计数 filename = 'meinian_round1_data_part2_20180408.txt' # 特征文件2 temp_lst2 = [[], [], []] with open(path + filename, 'r', encoding='UTF-8-sig') as infile: columns2 = infile.readline().strip().split('$') while True: line = infile.readline().strip().split('$') if line == ['']: break for i in range(3): temp_lst2[i].append(line[i]) counter += 1 dit = {columns[i]: temp_lst[i] for i in range(3)} # 将生成的temp_lst以键值对存储,键为对应的行名称 check_df1 = pd.DataFrame(dit) # 格式转化 dit2 = {columns2[i]: temp_lst2[i] for i in range(3)} check_df2 = pd.DataFrame(dit2) set1 = set(check_df1['table_id']) # 将table_id提取出来转为set set2 = set(check_df2['table_id']) same_table_id = set2 & set1 # 找出两个csv文件共有的table_id print(same_table_id) del check_df1, check_df2, temp_lst, temp_lst2 # 清除临时文件 counter = 0 temp_dit = {} filename = 'meinian_round1_data_part1_20180408.txt' with open(path + filename, 'r', encoding='UTF-8-sig') as infile: columns = infile.readline().strip().split('$') while True: line = infile.readline().strip().split('$') if line == ['']: break if line[0] in temp_dit: # 如果此人在temp_dit中 if line[1] in temp_dit[line[0]]: # 如果此人已经有这对应的检查项 try: # 如果能转化为数值型 c = float(line[2]) # 将检查结果转化为float temp_dit[line[0]][line[1]] = line[2] # 直接将此人的此检查结果更新 except: # 是字符型的 if line[2]: # 如果检查结果存在 # 将此人的此检查项赋值 # 检查结果的值为 原来的检查结果,现在的检查结果 (拼接) temp_dit[line[0]][line[1]] = str(temp_dit[line[0]][line[1]]) + ',' + str(line[2]) else: # 此人还没有对应的检查项 temp_dit[line[0]][line[1]] = line[2] # 将此人的此检查结果赋值 else: # 此人不在 # 键为此人的vid,值为{检查项:检查结果} temp_dit[line[0]] = {line[1]: line[2]} counter += 1 check_df = pd.DataFrame(temp_dit) check_df = check_df.T # 转置 行向量变列向量 print(check_df.columns) # 列名 # temp_dit在原有基础上添加 filename = 'meinian_round1_data_part2_20180408.txt' with open(path + filename, 'r', encoding='UTF-8-sig') as infile: columns = infile.readline().strip().split('$') while True: line = infile.readline().strip().split('$') if line == ['']: break if line[1] in same_table_id: # 如果检查项目在相同表里 line[1] += 'A' # 检查项目后面拼接个A if line[0] in temp_dit: if line[1] in temp_dit[line[0]]: try: c = float(line[2]) temp_dit[line[0]][line[1]] = line[2] except: if line[2]: temp_dit[line[0]][line[1]] = str(temp_dit[line[0]][line[1]]) + ',' + str(line[2]) else: temp_dit[line[0]][line[1]] = line[2] else: temp_dit[line[0]] = {line[1]: line[2]} counter += 1 check_df = pd.DataFrame(temp_dit) # 计算完part2 再转化一次 check_df = check_df.T print(check_df.columns) # ['0101', '0102', '0113',,,,,] # 重新索引,原有基础上增加一列 check_df2 = check_df.reset_index() # print(check_df2.columns) #['index', '0101', '0102', '0113',,,,,] lst = list(check_df2.columns) # 提取列名 lst[0] = 'vid' check_df2.columns = lst # 将index替换成vid print(check_df2.columns) # ['vid', '0101', '0102', '0113',,,,,] check_df2.to_csv(path + 'raw_feature.csv', encoding='gbk', index=False)
这里涉及到一个知识,就是pandas的数据格式化。具体代码例子:
dict11['行1']={'列1':1,'列2':2,'列3':4}
dict11['行2']={'列1':1,'列3':6}
dict11['行3']={'列1':1,'列2':4,'列4':5}
print(dict11)
print('--------------')
aaa = pd.DataFrame(dict11)
print(aaa)
print('--------------')
aaa = aaa.T
print(aaa)
print('--------------')
print(aaa.columns)
bbb = aaa.reset_index()
print('--------------')
print(bbb)
print('--------------')
print(bbb.columns)
print('--------------')
list11 = list(bbb.columns)
list11[0]="vid"
bbb.columns=list11
print(bbb)
输出:
{'行1': {'列1': 1, '列2': 2, '列3': 4}, '行2': {'列1': 1, '列3': 6}, '行3': {'列1': 1, '列2': 4, '列4': 5}} -------------- 行1 行2 行3 列1 1.0 1.0 1.0 列2 2.0 NaN 4.0 列3 4.0 6.0 NaN 列4 NaN NaN 5.0 -------------- 列1 列2 列3 列4 行1 1.0 2.0 4.0 NaN 行2 1.0 NaN 6.0 NaN 行3 1.0 4.0 NaN 5.0 -------------- Index(['列1', '列2', '列3', '列4'], dtype='object') -------------- index 列1 列2 列3 列4 0 行1 1.0 2.0 4.0 NaN 1 行2 1.0 NaN 6.0 NaN 2 行3 1.0 4.0 NaN 5.0 -------------- Index(['index', '列1', '列2', '列3', '列4'], dtype='object') -------------- vid 列1 列2 列3 列4 0 行1 1.0 2.0 4.0 NaN 1 行2 1.0 NaN 6.0 NaN 2 行3 1.0 4.0 NaN 5.0
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。