Overview

T4这个项目时,训练集采用了1502条正负样本数据,生成了大量的特征,由于各特征数据变化范围差异很大,于是我们按照重新缩放法做了数据的归一化,使得各特征的取值范围均控制在(0,1)内。然而在预测独立测试集3371条正负样本时,遇到一些疑问:独立测试集怎么办?如果独立测试集归一化,该怎么归一化,以谁为基准归一化,即它的最大值和最小值从何而来?
首先,毋庸置疑,独立测试集必须经过归一化。假如不归一化,某些特征值将会远大于1,或者远小于,这样样本会被全部判断为正或者全部为负,这点根据SVM和决策树的原理很容易理解。所以,我们查阅了很多资料,发现提到独立测试集归一化的,几乎没有。最终只在stackoverflow上找到一种思路:保存训练集每种特征原始的极值,应用于独立测试集。这样虽然仍会有部分数据“越界”,但是绝大多数数据将会趋于正常。下面将给出python代码,以记录这次工作。编码部分参考了这篇博客

1.归一化代码


#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#Copyright Chris & Young

def usage():
    print "normalize_test.py usage:"
    print "python normalize_test.py <options> <source files> "
    print "-i,--input: input an independent test dataset feature file."
    print "-t,--train: input training dataset feature file."
    print "-o,--ouput: output a normalized independent test dataset feature file."  
    print "-H,--header: input 'T' if the input_file contains header row, else input 'F'."
    print "-c,--class: input 'T' if the input_file contains class label column, else input 'F'."
    print "-h,--help: show the help information."

import re
import pandas as pd
import numpy as np
import fileinput
import sys, getopt
from os import listdir
from os.path import isfile, join
from sklearn import preprocessing

opts, args = getopt.getopt(sys.argv[1:], 'i:o:t:H:c:h',['input=','output=','train=','header=','class=','help'])
input_file=""
output_file=""
header_input=""
class_input=""
train_file=""

#col_start这个变量,是归一化开始列的index。根据是否有class列而变化。
col_start=0
for opt, arg in opts:
    if opt in ('-i','--input'):
        input_file = arg
    elif opt in ('-o','--output'):
        output_file = arg
    elif opt in ('-t','--train'):
        train_file=arg
    elif opt in('-H','--header'):
        header_input = arg
        if header_input == "T":
            header_input='infer'
        elif header_input == "F":
            header_input=None
    elif opt in ('-c','--class'):
        class_input = arg
        if class_input=="T":
            col_start+=1
    elif opt in ('-h', '--help'):
        usage()
            sys.exit(2)
        else:
            usage()
            sys.exit(2)
#读取数据到dataframe中
df_test = pd.read_csv(input_file,header=None)
df_train = pd.read_csv(train_file,header=header_input)
#将数据框分成两部分:class列单独拿出来,其余部分归一化处理
dataframe_train2 = df_train.ix[:,col_start:]
#数据框需要转化为float类型
dataframe_train2 = np.float64(dataframe_train2)
dataframe_test = np.float64(df_test)
#数据框需要转化为矩阵
matrix_train2=np.array(dataframe_train2)
matrix_test=np.array(dataframe_test)
#如果两个矩阵列数不同,程序终止退出
[row_train,col_train]=np.shape(matrix_train2)
[row_test,col_test]=np.shape(matrix_test)
if col_train!=col_test:
    print "Training or test dataset error!"
    sys.exit(2)
#下面代码是核心归一化代码
min_max_scaler=preprocessing.MinMaxScaler()

minmax_train=min_max_scaler.fit_transform(matrix_train2)
minmax_test=min_max_scaler.transform(matrix_test)
'''
此注释中代码为测试代码,按列观察训练集和测试集的最大最小值,从而确定是否正确将测试集归一化
train_max=minmax_train.max(axis=0)
train_min=minmax_train.min(axis=0)
test_max=minmax_test.max(axis=0)
test_min=minmax_test.min(axis=0)
print train_max,train_min,test_max,test_min
'''
#矩阵重新变为数据框
df_final=pd.DataFrame(minmax_test)
#将数据框存储为csv格式的文件    
df_final.to_csv(output_file,header=None,index=False)

2.解释说明

训练集输入时,程序会按列保存最大值与最小值,只需要sklearn.preprocessing.MinMaxScaler()这个方法,生成一个对象,把它命名为min_max_scaler,这个对象可以提供fit_transform()方法,传入参数为训练集矩阵matrix_train2,这样,这个min_max_scaler对象就可以保存训练集的最大值和最小值,继续使用min_max_scalertransform()方法,传入matrix_test测试集矩阵,这里要求测试集是裸矩阵,不含header的。这样就可以不用自己保存最大值和最小值矩阵,不用自定义归一化方法了。
这步以后,得到的归一化后的测试集矩阵,即使会有大于1或者小于的元素,但是绝大部分都会在(0,1)内,这样就不会再出现全部的正样本或者负样本的预测结果了。