数据预处理

数据预处理流程

  1. 判断数据类型,判断每一列数据的类型,float,category,boolean,text。
  2. 删除只有一个值的特征。
  3. 删除相同的特征,有些特征虽然值不一样,但只是用了不同的代号而已。
  4. 根据特征的类型产生新的特征。例如,对于连续的特征,每个月的销量的累加,对于神经网络,可以自动产生这种特征,但是对于树模型,无法处理这种特征。对于类别的特征,参考下面类别特征。
  5. 可以加入近邻数据的特征的平均值作为新的特征,但是定义近邻距离时,首先要确定不同的特征组(可以根据特征的均值分类),之后给定不同特征组不同的系数,然后求出距离。

Numeric Feature

对于线性模型需要Feature scaling,不同的scale会对梯度下降有很大的影响,scale大的feature的微小变动对结果影响很大。

  • Scaling
    • MinMaxScaler:不改变分布
    • StandardScaler
  • Outliers
    使用可视化的方法,发现outliers。
    • Feature clipping: 使用99%的分位数作为最大的。
    • Rank:使用排序代替原始值,如果无法使用可视化发现outliers
  • 使数据变紧凑
    • np.log(1+x), np.sqrt(1+x)

Categorical and ordinal features

categorical feature没有序,例如:性别。ordinal feature有序,例如:仓位,年级。

对于Tree,使用Label encoding或者Frequency encoding。
对于其他模型,使用One-hot necoding。不同的categorical feature或者ordinal feature之间可以做交互。例如:性别和仓位,变成1male, 2male, 1female, 2female。这样的做法对于线性模型有很大帮助。

Datetime and coordinates features

对于Datetime feature可以转换为,day of week, week of year, season of year;可以转换为距离某一个特定日期的距离,例如距离周末的距离;是否是节假日;

对于Coordinates feature可以转化为距离某一个点,可以是train set中的,也可以是额外的(地标,城市中心)的距离,转换为格子内的统计信息。

缺失值

缺失值的类型有:NA,空字符串,-1,很大的数字,-99999,999,99。通过可视化的方式,可以找出缺失值。

可以使用mean或者median值填充,也可以使用拟合的方式填充。增加一列标记是否缺失的二值变量。

不要在产生新的feature之前对缺失值做填充,否则会影响产生的feature。

文本特征

文本预处理,在提取文本特征之前要对文本做预处理,预处理包括:(1)将文本变为小写,同样的单词大写和小写的意义是相同的。(2)提取词干,将名词,形容词转换为相同的词干。(3)Lemmatization,将名词,形容词都转换为名词形式,过去式转换为现在式。(4)去除停词。这一步可以使用sklearn.feature_extraction.text.CountVectorizer,其中参数max_df指去除出现次数多少次以上的单词。

BOW提取特征,每个单词作为数据中的一个维度,使用sklearn.feature_extraction.text.CountVectorizer来完成这个工作,其中Ngram_range指定使用多少个gram, analyzer指定以单词为单位还是字母为单位。由于不同文本的长度不同,所以单词出现的频率也不同。需要使用tf-idf来衡量每个单词的重要性。

tf-idf原理,在一份给定的文件里,词频(term frequency,tf)指的是某一个给定的词语在该文件中出现的频率。这个数字是对词数(term count)的归一化,以防止它偏向长的文件。tf可以表示为:

逆向文件频率(inverse document frequency,idf)是一个词语普遍重要性的度量。某一特定词语的idf,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取以10为底的对数得到:

其中$|D|$:语料库中的文件总数
$ | {j : t i \in d_j}| $包含词语$t_i$的文件数目(即 $n{i,j} \neq 0$的文件数目)如果词语不在数据中,就导致分母为零,因此一般情况下使用 $1 + \left| \left{ j : t { i } \in d { j } \right} \right|$
然后

例子:假如一篇文件的总词语数是100个,而词语“母牛”出现了3次,那么“母牛”一词在该文件中的词频就是3/100=0.03。而计算文件频率(IDF)的方法是以文件集的文件总数,除以出现“母牛”一词的文件数。所以,如果“母牛”一词在1,000份文件出现过,而文件总数是10,000,000份的话,其逆向文件频率就是lg(10,000,000 / 1,000)=4。最后的tf-idf的分数为0.03 * 4=0.12。

如果只针对单词提取特征,疑问句和陈述句可能得到相同的结果。例如:’This is the first document.’ 和 ‘Is this the first document?’。为了防止词组顺序颠倒,除了提取一元模型 1-grams(个别词)之外,我们还可以提取 2-grams 的单词。

Word2Vec

数据可视化

可视化可以帮助我们发现有用的feature,并且使用他们产生新的feature。通常来说,没有特定的一套方法能够对所有的数据可视化。需要不断的输出数据,绘制数据,发现有用的数据之后进行进一步的探索。

数据可视化有以下方法:

  • Histograms,绘制直方图可以看出数据的分布。但是直方图有时候可能会带来错觉。如下图,左边的直方图看来,所有数据都是0。对数据取log(1+x)之后可以发现,数据有很多不同的值。尖峰的原因可能是很多缺失值被用平均值或者中位数填充了。

标准化

在机器学习算法的目标函数(例如SVM的RBF内核或线性模型的l1和l2正则化),许多学习算法中目标函数的基础都是假设所有的特征都是零均值并且具有同一阶数上的方差。如果某个特征的方差比其他特征大几个数量级,那么它就会在学习算法中占据主导位置,导致学习器并不能像我们说期望的那样,从其他特征中学习。

标准化能够加速梯度下降,如下图:

左边蓝色的图片,由于$x_2$的范围比较大,因此$w_2$的微小变化损失函数就有很大的变化。反之$w_1$要变化很多损失函数才有明显变化。从梯度下降的公式来说,$w_1$的变化取决于$x_1$,因此梯度很小,那么需要很久才能下降到最低点。右边的图片做了标准化,能够很快的下降到最低点。

其他变换

QuantileTransformer把数据变成对应的分为数,例如原本处于0.25分位数的数字是6.8,变化之后就是0.25。这个变换是一个非线性变换。

归一化,是 缩放单个样本以具有单位范数的过程。

数据清洗

清洗常量的数据,常量的数据对于分类没有帮助,需要去除掉。

1
2
3
4
5
6
7
# `dropna = False` makes nunique treat NaNs as a distinct value
feats_counts = train.nunique(dropna = False)
feats_counts.sort_values()[:10]
constant_features = feats_counts.loc[feats_counts==1].index.tolist()
print (constant_features)

traintest.drop(constant_features,axis = 1,inplace=True)

清洗重复的数据,对于不同的列,可能使用符号不同,但是本质是相同的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
train_enc =  pd.DataFrame(index = train.index)
for col in tqdm_notebook(traintest.columns):
train_enc[col] = train[col].factorize()[0]

dup_cols = {}
for i, c1 in enumerate(tqdm_notebook(train_enc.columns)):
for c2 in train_enc.columns[i + 1:]:
if c2 not in dup_cols and np.all(train_enc[c1] == train_enc[c2]):
dup_cols[c2] = c1

import cPickle as pickle
pickle.dump(dup_cols, open('dup_cols.p', 'w'), protocol=pickle.HIGHEST_PROTOCOL)

traintest.drop(dup_cols.keys(), axis = 1,inplace=True)