Pytorch重写《E2GAN》——多源多维度时序数据的读取处理

479 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

老师一直想让我参考E2GAN,但是但是这个代码实在太复杂了,又是我看着就眼晕的Tensorflow写的。但是,生活所迫,还是要重新搞一遍E2GAN的源码,这里计划用pytorch重写一遍E2GAN。

之前的GAIN就是TensorFlow写的,我用重写后,改模型什么的舒服多了。

数据读取

E2GAN用的是含有部分缺失值的时序数据,按理来说这种数据一个CSV就解决了,然而天将降大任于斯人也,这个数据读取必不可能这么简单的。

image.png

一个简简单单的读取数据的文件就这么400多行,当时感觉头都大了,但是万变不离其宗。我们只需要把他最终输出的数据和标签搞到一个csv里面去就行了。然后用pytorch的dataloader来帮我们做batch和shuffle。

其实里面做了很多工作的,比如时间序列时间戳的序列化,还有数据归一化,标签标准,batch输出……但是,我们没必要搞这么多

所以我其实在纠结是搞一个csv还是搞多个csv。最后决定了,搞一个csv,虽然不太美观,但是读取的时候加个split处理就ok了。

其实一开始想到这是个不定步长的时序数据时,我还以为只能用多个csv存储,但是我输出了下他处理后的时序,发现时序一样, 完全可以搞成一个csv嘛。

image.png

因为此数据是一个三维的数据。他是多源多维度时序数据。他的样子大致是这样的。

最后处理的数据样式是这个样子。其中行代表不同数据源,列代表了不同的数据时序,d1,d2,……,dn代表了数 据在这个时刻的不同纬度。

时序1时序2
【d1,d2,d3……,dn】【d1,d2,d3……,dn】
【d1,d2,d3……,dn】【d1,d2,d3……,dn】
…………
【d1,d2,d3……,dn】【d1,d2,d3……,dn】

对这样的数据,数据读取就要比一般的复杂点了。

def data_loader(args):

    '''加载数据
    args:
      - data_name: 可选

    Returns:
      data_x: 有缺失的数据
      data_m: 缺失组件的标志矩阵
    '''

    # Load data
    if args.data_name in ['medical']:
        file_name = 'data/' + args.data_name + '.csv'

        data_x = []
        data_y = []
        with open(file_name) as csvfile:
            csv_reader = csv.reader(csvfile)  # 使用csv.reader读取csvfile中的文件
            header = next(csv_reader)        # 读取第一行每一列的标题
            # print(header)
            for row in csv_reader:  # 将csv 文件中的数据保存到data中
                data_x.append(list(map(lambda x:list(map(float,x.split("\t"))),row))[:-1])  # 选择某一列加入到data数组中
                data_y.append(list(map(lambda x:list(map(float,x.split("\t"))),row))[-1])
            # print(data_x)        # 数据跳过第一行

    else:
        raise ValueError('data_name is not included in this project!')

    # Parameters 3594 * 48 * 41
    data_x=np.array(data_x)
    print(data_x.shape)

    # labels 3594 *2
    data_y=np.array(data_y)
    print(data_y.shape)

    # Introduce missing data
    data_m=data_x.copy()
    for i in range(data_m.shape[0]):
        for j in range(data_m.shape[1]):
            for k in range(data_m.shape[2]):
                if data_m[i][j][k]!=0.0:
                    data_m[i][j][k]=1
                elif data_m[i][j][k]==0.0:
                    data_m[i][j][k]=0

    data_x[data_m == 0] = np.nan

    return data_x,data_m

数据处理

当然还要有必要的数据归一化。这里面因为是三维数据,搞得我很惆怅。因为现有的所有的数据归一化我能找到的参考最多是二维数据。

所以,我在这里做了个处理,用reshape来将将三维数据转换成二维数据,然后归一化,再reshape成三维的。

这个方法封装到utils里面,以后肯定用的到

归一化

def normalization_3d(data, parameters=None):
    '''Normalize data in [0, 1] range.

    Args:
      - data: 原始数据

    Returns:
      - norm_data: 归一化数据
      - norm_parameters: 每一列的最大值数组,最小值数组
    '''

    # Parameters
    temp = np.reshape(data, (data.shape[0]*data.shape[1], data.shape[2]))
    _, dim = temp.shape
    norm_data = temp.copy()

    if parameters is None:

        # MixMax normalization
        min_val = np.zeros(dim)
        max_val = np.zeros(dim)

        # For each dimension
        for i in range(dim):
            min_val[i] = np.nanmin(norm_data[:, i])
            norm_data[:, i] = norm_data[:, i] - np.nanmin(norm_data[:, i])
            max_val[i] = np.nanmax(norm_data[:, i])
            norm_data[:, i] = norm_data[:, i] / (np.nanmax(norm_data[:, i]) + 1e-6)

            # Return norm_parameters for renormalization
        norm_parameters = {'min_val': min_val,
                           'max_val': max_val}

    else:
        min_val = parameters['min_val']
        max_val = parameters['max_val']

        # For each dimension
        for i in range(dim):
            norm_data[:, i] = norm_data[:, i] - min_val[i]
            norm_data[:, i] = norm_data[:, i] / (max_val[i] + 1e-6)

        norm_parameters = parameters
    norm_data = np.reshape(norm_data, (data.shape[0], data.shape[1],data.shape[2]))

    return norm_data, norm_parameters

逆归一化

def renormalization_3d(norm_data, norm_parameters):
    '''Renormalize data from [0, 1] range to the original range.

    Args:
      - norm_data: 归一化后数据
      - norm_parameters: 每一列的最大值数组,最小值数组

    Returns:
      - renorm_data: 逆归一化后的元数据数据
    '''

    min_val = norm_parameters['min_val']
    max_val = norm_parameters['max_val']

    temp = np.reshape(norm_data, (norm_data.shape[0]*norm_data.shape[1], norm_data.shape[2]))

    _, dim = temp.shape
    renorm_data = temp.copy()

    for i in range(dim):
        renorm_data[:, i] = renorm_data[:, i] * (max_val[i] + 1e-6)
        renorm_data[:, i] = renorm_data[:, i] + min_val[i]

    renorm_data = np.reshape(renorm_data, (norm_data.shape[0], norm_data.shape[1],norm_data.shape[2]))

    return renorm_data