如何“标准化”具有可变长度的数据集?

时间:2019-09-17 18:49:05

标签: python keras conv-neural-network recurrent-neural-network

我不确定我是否正确表达了我的问题,但这是要点: 我正在使用的数据集SVC 2004具有x个文件,每个文件具有y 7个元组,因此数据集的形状变为(x,y,7)。我已经对数据进行了归一化,并将其插入到一维CNN中进行特征提取,并使用RNN作为分类器。但这是问题所在:每个文件的 y永远都不相同。由于需要恒定的形状,因此在创建顺序模型时会引起问题。这是我的一些代码:

//DataPreprocessing
def load_dataset_normalized(path):
file_names = os.listdir(path)

num_of_persons = len(file_names)

initial_starting_point = np.zeros(np.shape([7]))

highest_num_of_points = find_largest_num_of_points(path)

x_dataset = []
y_dataset = []

current_file = 0

for infile in file_names:
    full_file_name = os.path.join(path, infile)
    file = open(full_file_name, "r")
    file_lines = file.readlines()

    num_of_points = int(file_lines[0])

    x = []
    y = []
    time_stamp = []
    button_status = []
    azimuth_angles = []
    altitude = []
    pressure = []

    for idx, line in enumerate(file_lines[1:]):
        idx+=1
        nums = line.split(' ')

        if idx == 1:
            nums[2] = 0
            initial_starting_point = nums

            x.append(float(nums[0]))
            y.append(float(nums[1]))
            time_stamp.append(0.0)
            button_status.append(float(nums[3]))
            azimuth_angles.append(float(nums[4]))
            altitude.append(float(nums[5]))
            pressure.append(float(nums[6]))

        else:
            x.append(float(nums[0]))
            y.append(float(nums[1]))
            time_stamp.append(10)
            button_status.append(float(nums[3]))
            azimuth_angles.append(float(nums[4]))
            altitude.append(float(nums[5]))
            pressure.append(float(nums[6]))

    max_x = max(x)
    max_y = max(y)
    max_azimuth_angle = max(azimuth_angles)
    max_altitude = max(altitude)
    max_pressure = max(pressure)

    min_x = min(x)
    min_y = min(y)
    min_azimuth_angle = min(azimuth_angles)
    min_altitude = min(altitude)
    min_pressure = min(pressure)

    #Alignment normalization:
    for i in range(num_of_points):
        x[i] -= float(initial_starting_point[0])
        y[i] -= float(initial_starting_point[1])
        azimuth_angles[i] -= float(initial_starting_point[4])
        altitude[i] -= float(initial_starting_point[5])
        pressure[i] -= float(initial_starting_point[6])

    #Size normalization
    for i in range(num_of_points):
        x[i] = ((x[i] - max_x) / (min_x - max_x))
        y[i] = ((y[i] - max_y) / (min_y - max_y))
        azimuth_angles[i] = ((azimuth_angles[i] - max_azimuth_angle) / (min_azimuth_angle - max_azimuth_angle))
        altitude[i] = ((altitude[i] - max_altitude) / (min_altitude - max_altitude))
        pressure[i] = ((pressure[i] - max_pressure) / (min_pressure - max_pressure))

    #data points to dataset
    x_line = []
    for i in range (num_of_points):
        x_line.append(([x[i], y[i], time_stamp[i], button_status[i], azimuth_angles[i], altitude[i], pressure[i]]))
        if (num_of_points < 713) and (i == num_of_points-1):
           for idx in range(713 - num_of_points):
               x_line.append([0, 0, 0, 0, 0, 0, 0])

        if i == num_of_points-1:
            x_dataset.append(x_line)

    current_file += 1

    infile_without_extension = infile.replace('.TXT','')
    index_of_s = infile_without_extension.find("S")
    index_of_num = index_of_s + 1
    sig_ID = int(infile_without_extension[index_of_num:])
    if sig_ID < 21:
        y_dataset.append([1,0])
    else:
        y_dataset.append([0,1])

x_dataset = np.array([np.array(xi) for xi in x_dataset])
y_dataset = np.asarray(y_dataset)
return x_dataset, y_dataset, highest_num_of_points

    //Class that creates my model (creation of model works perfectly)
    class crnn_model:
    def build_model(self, input_shape_num, x_train, y_train, x_test, y_test):
    model = Sequential()
    model.add(Conv1D(filters=50, kernel_size=3, activation='sigmoid', input_shape = (713, 7)))
    model.add(MaxPooling1D(pool_size=3))
    model.add(LSTM(2))
    model.compile(optimizer='adam', loss='mse', metrics = ['accuracy'])
    model.summary()

    print(model.fit(x_train, y_train, epochs=50, verbose=0))

    yhat = model.predict(x_test, verbose=0)
    print(yhat)

我已经考虑过使用具有最多7个元组的文件作为形状,因为到目前为止,我已经使用上述代码(713)对其进行了硬编码。这将是一个很好的选择吗?如果不是,我该如何“标准化”或“标准化” CNN输入形状的点数(y)?

2 个答案:

答案 0 :(得分:1)

在这里,您指的是可变长度序列,可以通过使input_shape=(None, 7)来实现。这表示y的每个批次可以变化,但在一个批次内没有变化。因此,我们通过以下方式解决此问题:

  • 实现一个Sequence,该pad_sequences将数据和印章分批处理。对于每个批次,它使用Masking Layer通过填充返回(batch_size, y_max_within_batch, 7)
  • 设置input_shape=(None, 7),以便在运行时您的模型可以使用不同长度的输入。这说我每批将有7个元组。
  • (可选)使用enter image description here来掩盖填充的序列,因此您的模型不会将填充用作特征,而只会预测正确的样本长度。您还可以对填充进行预测,这将使预测更容易考虑序列的长度。

在Keras中,大多数都是处理各种长度序列所需的工具/层。您如何使用它们以及填充效果等取决于您要解决的任务。

答案 1 :(得分:0)

根据我的经验,人们倾向于手动选择任意长度。任何较短的序列都会被填充(通常为零),而任何较长的序列都会被截断。

您选择的长度取决于数据集;通常,我会对长度进行直方图绘制,然后再用眼球表示一个数字,该数字可以保留大部分数据而不会产生不必要的填充。通常在90%到95%之间。但是,如果最长的长度不比平均长度长太多(例如,小于2的倍数),那么确定这个数字将是不合理的。


另一个可能选项-尽管我对此没有经验,因此不能推荐它-仅标准化每批。任何给定批次的所有样本都需要具有相同的长度,但是独立批次的长度可以不同。从理论上讲,您可以根据序列长度对数据进行分区,然后使用尽可能少的填充/截断进行批处理。但是,这可能会花费很多精力,并且只有在序列长度与其他任何东西都不相关的情况下才可能起作用。我建议不要尝试这种方法。