美年AI大赛--开源代码学习笔记(一)

1.概要

1.1 比赛相关

本博文为分析学习github上的美年健康ai大赛的开源代码。

1.1.1大赛地址:

https://tianchi.aliyun.com/competition/introduction.htm?spm=5176.11409106.5678.1.1c9a560c15bKhJ&raceId=231654

1.1.2 github地址:

https://github.com/yzbdt/tianchi_meinian_rank12_1st_season

1.2 代码相关

本开源的代码共分为2个大的步骤,数据预处理与模型训练。

在数据预处理部分,分为了:

  1. 整理标签文件
  2. 整理合并特征文件
  3. 粗略分割特征文件
  4. 清洗混入了少量字符的数值特征文件
  5. 清洗字符特征文件
  6. 切分字符
  7. 特征编码
  8. 生成长字符串特征

共8个步骤。

处理生成文件的顺序:




2.数据集概览

2.1 数据集格式:

https://tianchi.aliyun.com/competition/information.htm?spm=5176.100067.5678.2.227e342dl5bS4j&raceId=231654

2.2 查看数据集

首先查看一下拿到手的数据集,其中包含2个特征文件和1个标签文件。如图:



2.2.1 特征文件

查看特征文件内部数据:


共包含3列数据,分别是vid,table_id,field_result  病人id,检查项目id,检查结果。


2.2.2 标签文件

对于标签文件,查看内部:


可知共6列,分别为病人id以及对应的5个标签值


2.2.3 评估指标

参赛选手需要提交对每个个体的收缩压,舒张压,甘油三酯,高密度脂蛋白胆固醇和低密度脂蛋白胆固醇五项指标预测结果,以小数形式表示,保留小数点后三位。该结果将与个体实际检测到的数值进行对比。对于第j项指标,计算公式如下:

11.png
其中m为总人数,yi'为选手预测的第i个人的指标j的数值,yi为第i个人的指标j的实际检测值。最后的评价指标是五个预测指标评估结果之和:

22.png


3.标签数据集预处理

3.1 代码

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


3.2 运行结果

输出日志:



最终生成了5个文件:


每个文件都记录了病人id以及对应的指标,如其中一个文件:


3.3 高斯转换

在程序最后进行了正态分布的转换,使用 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之间的一个分数,等方法。



4.整理特征数据

4.1 思路

整理特征数据的主要工作就是将解压缩后得到的2个特征数据

进行合并,并整理成想要的格式。之前观察特征文件已经知道,原始的特征文件每一行是一个样本,其字段分别为:

                                                                    病人id, 体检项目, 体检结果

因此可以确定的是,病人id必然会出现重复。正常情况下,一个病人对应多个体检项目,每个体检项目对应一个体检结果。因此期望将格式整理为:

 体检项目1检项目2...检项目n
病人1    
病人2    
...    
病人m    

4.2 代码

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)


4.3 运行结果


可以看到 增加了vid列

4.4 Pandas学习

这里涉及到一个知识,就是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

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值