参考资料:
处理数值型特征
如何处理类别型特征?
特征工程:时间特征处理方式
特征处理之统计特征
AI基础:特征工程-文本特征处理
特征:作为判断条件的一组输入变量,是做出判断的依据
目标:判断和预测的目标,模型的输出变量,是特征所产生的结果
特征与特征之间应该是平等的,区别应该体现在特征内部
例如房屋价格和住房面积的幅度是不同的,房屋价格可能在30000001500000(万)之间,而住房面积在40300(平方米)之间,那么明明是平等的两个特征,输入到相同的模型中后由于本身的幅值不同导致产生的效果不同,这是不合理的
用sklearn的MinMaxScaler来缩放一个特征数组,将一个数值型特征的值缩放到两个特定的值之间。
import numpy as np
from sklearn import preprocessing
#创建特征
feature = np.array([[-500.5],
[-100.1],
[0],
[100.1],
[900.9]])
#创建缩放器
minmax_scale = preprocessing.MinMaxScaler(feature_range=(0,1))
#缩放特征的值
scaled_feature = minmax_scale.fit_transform(feature)
#查看特征
print(scaled_feature)
array([[0. ],
[0.28571429],
[0.35714286],
[0.42857143],
[1. ]])
对一个特征进行转换,使其平均值为0,标准差为1.
import numpy as np
from sklearn import preprocessing
#创建特征
x = np.array([[-1000.1],
[-200.2],
[500.5],
[600.6],
[9000.9]])
#创建缩放器
scaler = preprocessing.StandardScaler()
#转换特征
standardized = scaler.fit_transform(x)
#查看特征
print(standardized)
array([[-0.76058269],
[-0.54177196],
[-0.35009716],
[-0.32271504],
[ 1.97516685]])
类别型数据本身没有大小关系,需要将它们编码为数字,但它们之间不能有预先设定的大小关系,因此既要做到公平,又要区分开它们,那么直接开辟多个空间
第一种处理方法是标签编码,其实就是直接将类别型特征从字符串转换为数字,有两种处理方法:
转为 category 类型后标签编码
直接替换字符串,算是手动处理,实现如下所示,这里用 body_style 这列特征做例子进行处理,它总共有 5 个取值方式,先通过 value_counts方法可以获取每个数值的分布情况,然后映射为数字,保存为一个字典,最后通过 replace 方法进行转换。
第二种方法比较特别,直接将所有的类别分为两个类别,这里用 engine_type 特征作为例子,假如我们仅关心该特征是否为 ohc ,那么我们就可以将其分为两类,包含 ohc 还是不包含,实现如下所示:
实现 One-hot 编码有以下 3 种方法:
第二种方法–Sklearn 的 DictVectorizer,这首先需要将 dataframe 转化为 dict 类型,这可以通过 to_dict ,并设置参数 orient=records,实现代码如下所示:
第三种方法–Sklearn 的 LabelEncoder+OneHotEncoder
首先是定义 LabelEncoder,实现代码如下,可以发现其实它就是将字符串进行了标签编码,将字符串转换为数值,这个操作很关键,因为 OneHotEncoder 是不能处理字符串类型的,所以需要先做这样的转换操作:
接着自然就是进行 one-hot 编码了,实现代码如下所示:
此外,采用 OneHotEncoder 的一个好处就是可以指定特征的维度,这种情况适用于,如果训练集和测试集的某个特征的取值数量不同的情况,比如训练集的样本包含这个特征的所有可能的取值,但测试集的样本缺少了其中一种可能,那么如果直接用 pandas 的get_dummies方法,会导致训练集和测试集的特征维度不一致了。
实现代码如下所示:
时间型特征既可以做连续值,又可以看做离散值。
如:用户在购买网站上的浏览、购买、收藏的时间;产品在购物网站上的上线时间;顾客在银行的存款和借款时间等。
形式:日期、时间戳等。
方法:将时间变量作为类别变量处理。
如:计算产品上线到现在经过了多长时间;顾客上次借款距离现在的时间隔;两个时可间隔之间是否包含节假日或其他特殊日期等。
方法:根据两个或多个时间变量的含义,进行特征组合。
如:股票价格;天气温度;降雨量;订单量等 目的:基于历史数据预测未来信息。 方法:滞后特征、滑动窗口统计特征。
滞后特征:时间序列预测问题转化为监督学习问题的一种经典方法。 滑动窗口统计特征
例妙如计算前n个值的均值或者前n个值中每个类別的分布。
时间窗口的选取可以有多种方式,滞后特征是滑动窗口统计的一种特例,对应时间窗口宽度是1。
另一种常用的窗口设置包含所有历史数据,成为扩展窗口统计。
更多案例代码参考:AI基础:特征工程-文本特征处理
文本数据预处理后,去掉停用词,剩下的词组成的list,在词库中的映射稀疏向量。Python中用CountVectorizer处理词袋.
在词袋特征中,文本文档被转换成向量。(向量只是 n 个数字的集合。)向量包含词汇表中每个单词可能出现的数目。如果单词"aardvark"在文档中出现三次,则该特征向量在与该单词对应的位置上的计数为 3。如果词汇表中的单词没有出现在文档中,则计数为零。例如,“这是一只小狗,它是非常可爱”的句子具有如图所示的 BOW 表示
from sklearn.feature_extraction.text import CountVectorizer
print (norm_corpus)
cv = CountVectorizer(min_df=0., max_df=1.)
cv.fit(norm_corpus)
print (cv.get_feature_names())
cv_matrix = cv.fit_transform(norm_corpus)
cv_matrix = cv_matrix.toarray()
cv_matrix
['sky blue beautiful' 'love blue beautiful sky'
'quick brown fox jumps lazy dog' 'brown fox quick blue dog lazy'
'sky blue sky beautiful today' 'dog lazy brown fox quick']
['beautiful', 'blue', 'brown', 'dog', 'fox', 'jumps', 'lazy', 'love', 'quick', 'sky', 'today']
array([[1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0],
[0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0],
[0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0],
[1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 1],
[0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0]], dtype=int64)
vocab = cv.get_feature_names()
pd.DataFrame(cv_matrix, columns=vocab)
beautiful blue brown dog fox jumps lazy love quick sky today
0 1 1 0 0 0 0 0 0 0 1 0
1 1 1 0 0 0 0 0 1 0 1 0
2 0 0 1 1 1 1 1 0 1 0 0
3 0 1 1 1 1 0 1 0 1 0 0
4 1 1 0 0 0 0 0 0 0 2 1
5 0 0 1 1 1 0 1 0 1 0 0
n-gram代表n个词的组合。比如“我喜欢你”、“你喜欢我”这两句话如果用词袋表示的话,分词后包含相同的三个词,组成一样的向量:“我 喜欢 你”。显然两句话不是同一个意思,用n-gram可以解决这个问题。如果用2-gram,那么“我喜欢你”的向量中会加上“我喜欢”和“喜欢你”,“你喜欢我”的向量中会加上“你喜欢”和“喜欢我”。这样就区分开来了。
Bag-of-N-gram 或者 bag-of-ngram 是 BOW 的自然延伸。n-gram 是 n 个有序的记号(token)。一个词基本上是一个 1-gram,也被称为一元模型。当它被标记后,计数机制可以将单个词进行计数,或将重叠序列计数为 n-gram。例如,“Emma knocked on the door"这句话会产生 n-gram,如"Emma knocked”,“knocked on”,“on the”,“the door”。N-gram 保留了文本的更多原始序列结构,故 bag-of-ngram可以提供更多信息。但是,这是有代价的。理论上,用 k 个独特的词,可能有 k 个独立的 2-gram(也称为 bigram)。在实践中,并不是那么多,因为不是每个单词后都可以跟一个单词。尽管如此,通常有更多不同的 n-gram(n > 1)比单词更多。这意味着词袋会更大并且有稀疏的特征空间。这也意味着 n-gram 计算,存储和建模的成本会变高。n 越大,信息越丰富,成本越高。
为了说明随着 n 增加 n-gram 的数量如何增加,我们来计算纽约时报文章数据集上的 n-gram。我们使用 Pandas 和 scikit-learn 中的CountVectorizer转换器来计算前 10,000 条评论的 n-gram。
bv = CountVectorizer(ngram_range=(2,2))
bv_matrix = bv.fit_transform(norm_corpus)
bv_matrix = bv_matrix.toarray()
vocab = bv.get_feature_names()
pd.DataFrame(bv_matrix, columns=vocab)
beautiful sky beautiful today blue beautiful blue dog blue sky brown fox dog lazy fox jumps fox quick jumps lazy lazy brown lazy dog love blue quick blue quick brown sky beautiful sky blue
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0
2 0 0 0 0 0 1 0 1 0 1 0 1 0 0 1 0 0
3 0 0 0 1 0 1 1 0 1 0 0 0 0 1 0 0 0
4 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1
5 0 0 0 0 0 1 1 0 1 0 1 0 0 0 0 0 0
TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。TF(t) = (词t在当前文中出现次数) / (t在全部文档中出现次数),IDF(t) = ln(总文档数/ 含t的文档数),TF-IDF权重 = TF(t) * IDF(t)。自然语言处理中经常会用到。
from sklearn.feature_extraction.text import TfidfVectorizer #中国 蜜蜂 养殖 它们的片频数都是20次
tv = TfidfVectorizer(min_df=0., max_df=1., use_idf=True)
tv_matrix = tv.fit_transform(norm_corpus)
tv_matrix = tv_matrix.toarray()
vocab = tv.get_feature_names()
pd.DataFrame(np.round(tv_matrix, 2), columns=vocab)
beautiful blue brown dog fox jumps lazy love quick sky today
0 0.60 0.52 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.60 0.00
1 0.46 0.39 0.00 0.00 0.00 0.00 0.00 0.66 0.00 0.46 0.00
2 0.00 0.00 0.38 0.38 0.38 0.54 0.38 0.00 0.38 0.00 0.00
3 0.00 0.36 0.42 0.42 0.42 0.00 0.42 0.00 0.42 0.00 0.00
4 0.36 0.31 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.72 0.52
5 0.00 0.00 0.45 0.45 0.45 0.00 0.45 0.00 0.45 0.00 0.00