特征提取

从类别变量中提取特征

类别型特征( Categorical Feature ) 主要是指性别 (男、女)、血型( A 、 B、 AB 、 0 ) 等只在高限选I页内取值的特征。 类别型特征原始输入通常是字符串形式,除了决策树等少数模型能直接处理字符串形式的输入 3,对于逻辑回归、支持向量机等模型来说,类别型特征必须经过处理转换成数值型特征才能正确工作。

one-hot编码

独热编码通常用于处理类别间不具有大小关系的特征。例如血型,
一共有4个取值(A型血、B型血、AB型血、O型血),独热编码会
把血型变成- -个4维稀疏向量,A型血表示为(1,0,0,0),B型血.
表示为(0, 1,0,0), AB型表示为(0,0, 1,0), O型血表示为(0, 0, .
0,1) 。对于类别取值较多的情况下使用独热编码需要注意以下问题。

(1)使用稀疏向量来节省空间。在独热编码下,特征向量只有某维取值为1,其他位置取值均为0。因此可以利用向量的稀疏表示有
效地节省空间,并且目前大部分的算法均接受稀疏向量形式的输入。

(2 )配合特征选择来降低维度。高维度特征会带来几方面的问题。
-是在K近邻算法中,高维空间下两点之间的距离很难得到有效的衡量;
二是在逻辑回归模型中,参数的数量会随着维度的增高而增加,容易引
起过拟合问题;三是通常只有部分维度是对分类、预测有帮助,因此可
以考虑配合特征选择来降低维度。

假设我们的模型中有一个 city 变量, 该变量可以从下面 3 个值中取值:NewYork、 San Francisco 或者 Chapel Hill , One-hot 编码算法使用每个可能城市的二元特征来表示变量。 scikit-leam 类库中的 Dictvectorizer 类是一个可以对类别特征进行 one-hot 编码的转换器

## 法一
from sklearn.feature_extraction import DictVectorizer
onehot_encoder = DictVectorizer()
X = [
    {'city': 'New York'},
    {'city': 'San Francisco'},
    {'city': 'Chapel Hill'}
]
print(onehot_encoder.fit_transform(X).toarray())

[[0. 1. 0.]
 [0. 0. 1.]
 [1. 0. 0.]]
## 法二
import pandas as pd 
X=pd.DataFrame(X)
pd.get_dummies(X)
city_Chapel Hillcity_New Yorkcity_San Francisco
0010
1001
2100

自然数编码

该方法主要用于自然数编码,并且缺失值会被记做-1,其中sort参数表示是否排序后赋值

序号编码通常用于处理类别间具有大小关系的数据。例如成绩,可以分为低、中、高三档,并且存在“高>中>低"的排序关系。序号编码会按照大小关系对类别型特征赋予 -个数值ID,例如高表示为3、中表示为2、低表示为1,转换后依然保留了大小关系。

X
city
0New York
1San Francisco
2Chapel Hill
#法一
codes, uniques = pd.factorize(X.city, sort=True)
codes
array([1, 2, 0], dtype=int64)
#法二
label_dict = dict(zip(X.city.unique(), range(X.city.nunique())))
X.city.map(label_dict)
0    0
1    1
2    2
Name: city, dtype: int64
#法三
#使用sklearn.preprocessing的LabelEncoder
from sklearn.preprocessing import LabelEncoder
lbl = LabelEncoder()  
lbl.fit_transform(X.city)
array([1, 2, 0])

特征标准化

标准化数据有零平均值和单位方差。零平均值解释变量相对于原点居中 , 其平均值为 0。当特征向量所有特征的方差处于相同量级,则拥有单位方差。如果一个特 征的方差和其他特征的方差相差太大的数量级,该特征会控制学习算法, 阻止算法从其他 变量中学习。当数据没有标准化时, 一些学习算法也会更慢地收敛到最佳参数。

为什么需要对数值型特征做归一化呢?我们不妨借助随机梯度下降的实例来说明归一化的重要性。假设有两种数值型特征,x1的取值范围为[0,10],x2的取值范围为[0,3],于是可以构造一个目标函数符合图l.1(a)中的等值图。

在学习速率相同的情况下,x1的更新速度会大于x2,需要较多的迭代才能找到最优解。如果将x1和x2归一化到相同的数值区间后,优化目标的等值图会变成图1.1(b)中的圆形,x1和x2的更新速度变得更为一致,容易更快地通过梯度下降找到最优解。

在这里插入图片描述

# prepocessing 模块中的 scale 函数 也可以用于单独对数据集的任何轴进行标准化。
from sklearn import preprocessing
import numpy as np
X = np.array([
    [0., 0., 5., 13., 9., 1.],
    [0., 0., 13., 15., 10., 15.],
    [0., 3., 15., 2., 0., 11.]
])
print(preprocessing.scale(X))
[[ 0.         -0.70710678 -1.38873015  0.52489066  0.59299945 -1.35873244]
 [ 0.         -0.70710678  0.46291005  0.87481777  0.81537425  1.01904933]
 [ 0.          1.41421356  0.9258201  -1.39970842 -1.4083737   0.33968311]]
# scikit-learn类库中的 StandardScaler 类是一个用于特征缩放的转换器,它能确保 所有的特征都有单位方差
#首先将所有实例特征值减去均值来将其居中。其次将每个实例特征值除以特征的标准差对其进行缩放。均值为0,方差为1的数据称为标准化数据。
from sklearn.preprocessing import StandardScaler
ss=StandardScaler()
print(ss.fit_transform(X))

[[ 0.         -0.70710678 -1.38873015  0.52489066  0.59299945 -1.35873244]
 [ 0.         -0.70710678  0.46291005  0.87481777  0.81537425  1.01904933]
 [ 0.          1.41421356  0.9258201  -1.39970842 -1.4083737   0.33968311]]

从文本中提取特征

词袋模型

词袋模型是最常用的文本表示法, 这种表示法使用一个多重集或袋对文本中出现的单 词进行编码。词袋模型不会编码任何文本句法,同时忽视单词的顺序, 忽略所有的语法。 词袋模型可以被看作是 one-hot 编码的一种扩展,它会对文本中关注的每一个单词创建一个 特征。 词袋模型产生的灵感来源于包含类似单词的文档经常有相似的含义。词袋模型可以 有效地用于文档分类和检索, 同时不会受到编码信息的限制。 一个文档的集合称为一个语料库。

corpus = [
    'UNC played Duke in basketball',
    'Duke lost the basketball game'
]

CountVectorizer 转换器可以从一个字 符串或者文件中生成词包表示。默认情况下, CountVectorizer 把文档中的字符转换为 小写并对文档进行词汇切分。词汇切分是一个将字符串切分为标志或者有意义的字符序列 的过程。标志通常是单词,但是也有可能是更短的序列,包括标点符号和词缀。 CountVectorizer 使用一个正则表达式将字符串用空格分开,并提取长度大于等于两个 字符的字符序列进行切分。如代码 4.4 所示,我们的语料库中的文档可以表示为以下的特 征向量。

from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer()
print(vectorizer.fit_transform(corpus))
print(vectorizer.fit_transform(corpus).todense())
print(vectorizer.vocabulary_)
  (0, 7)	1
  (0, 5)	1
  (0, 1)	1
  (0, 3)	1
  (0, 0)	1
  (1, 1)	1
  (1, 0)	1
  (1, 4)	1
  (1, 6)	1
  (1, 2)	1
[[1 1 0 1 0 1 0 1]
 [1 1 1 0 1 0 1 0]]
{'unc': 7, 'played': 5, 'duke': 1, 'in': 3, 'basketball': 0, 'lost': 4, 'the': 6, 'game': 2}
corpus.append('I ate a sandwich')
print(vectorizer.fit_transform(corpus).todense())
print(vectorizer.vocabulary_)
[[0 1 1 0 1 0 1 0 0 1]
 [0 1 1 1 0 1 0 0 1 0]
 [1 0 0 0 0 0 0 1 0 0]]
{'unc': 9, 'played': 6, 'duke': 2, 'in': 4, 'basketball': 1, 'lost': 5, 'the': 8, 'game': 3, 'ate': 0, 'sandwich': 7}

scikit-leam 类库的 eculidean distances 函数可以用来计算两个或多个向量之间 的距离, 同时确认语意最为类似的文档在向量空间中最为靠近。在下面例子中 ,我们将使用 euclidean_distances 函数对文档进行特征向量比较。

from sklearn.metrics.pairwise import euclidean_distances
X = vectorizer.fit_transform(corpus).todense()
print('Distance between 1st and 2nd documents:', euclidean_distances(X[0], X[1]))
print('Distance between 1st and 3rd documents:', euclidean_distances(X[0], X[2]))
print('Distance between 2nd and 3rd documents:', euclidean_distances(X[1], X[2]))
Distance between 1st and 2nd documents: [[2.44948974]]
Distance between 1st and 3rd documents: [[2.64575131]]
Distance between 2nd and 3rd documents: [[2.64575131]]

停用词过滤降低特征空间维度

vectorizer = CountVectorizer(stop_words='english')
print(vectorizer.fit_transform(corpus).todense())
print(vectorizer.vocabulary_)
[[0 1 1 0 0 1 0 1]
 [0 1 1 1 1 0 0 0]
 [1 0 0 0 0 0 1 0]]
{'unc': 7, 'played': 5, 'duke': 2, 'basketball': 1, 'lost': 4, 'game': 3, 'ate': 0, 'sandwich': 6}

减少特征维度-词干提取和词形还原

corpus = [
    'He ate the sandwiches',
    'Every sandwich was eaten by him'
]
vectorizer = CountVectorizer(binary=True, stop_words='english')
print(vectorizer.fit_transform(corpus).todense())
print(vectorizer.vocabulary_)
[[1 0 0 1]
 [0 1 1 0]]
{'ate': 0, 'sandwiches': 3, 'sandwich': 2, 'eaten': 1}
corpus = [
    'I am gathering ingredients for the sandwich.',
    'There were many wizards at the gathering.'
]
from nltk.stem.wordnet import WordNetLemmatizer

lemmatizer = WordNetLemmatizer()
print(lemmatizer.lemmatize('gathering', 'v'))
print(lemmatizer.lemmatize('gathering', 'n'))
gather
gathering
from nltk.stem import PorterStemmer

stemmer = PorterStemmer()
print(stemmer.stem('gathering'))
gather
对玩具语料库做词形还原
from nltk import word_tokenize
from nltk.stem import PorterStemmer
from nltk.stem.wordnet import WordNetLemmatizer
from nltk import pos_tag

wordnet_tags = ['n', 'v']
corpus = [
    'He ate the sandwiches',
    'Every sandwich was eaten by him'
]
stemmer = PorterStemmer()
print('Stemmed:', [[stemmer.stem(token) for token in word_tokenize(document)] for document in corpus])


def lemmatize(token, tag):
    if tag[0].lower() in ['n', 'v']:
        return lemmatizer.lemmatize(token, tag[0].lower())
    return token

lemmatizer = WordNetLemmatizer()
tagged_corpus = [pos_tag(word_tokenize(document)) for document in corpus]
print('Lemmatized:', [[lemmatize(token, tag) for token, tag in document] for document in tagged_corpus])
Stemmed: [['He', 'ate', 'the', 'sandwich'], ['everi', 'sandwich', 'wa', 'eaten', 'by', 'him']]
Lemmatized: [['He', 'eat', 'the', 'sandwich'], ['Every', 'sandwich', 'be', 'eat', 'by', 'him']]

tf-idf权重扩展词包

创建编码单词频数的特征向量

我们将创建编码单词频数的特征向量,并讨论用 于减轻由编码单 词频数带来的两个问题的策略。 我们将使用一个整数来表示单词在文档中出现的次数, 而 不是使用一个二元值表示特征向量中的每个元素。 通过使用停用词过滤,语料库被表示为 以下的特征向量

import numpy as np
from sklearn.feature_extraction.text import CountVectorizer

corpus = ['The dog ate a sandwich, the wizard transfigured a sandwich, and I ate a sandwich']
vectorizer = CountVectorizer(stop_words='english')
frequencies = np.array(vectorizer.fit_transform(corpus).todense())[0]
print(frequencies)
print('Token indices %s' % vectorizer.vocabulary_)
for token, index in vectorizer.vocabulary_.items():
    print('The token "%s" appears %s times' % (token, frequencies[index]))
[2 1 3 1 1]
Token indices {'dog': 1, 'ate': 0, 'sandwich': 2, 'wizard': 4, 'transfigured': 3}
The token "dog" appears 1 times
The token "ate" appears 2 times
The token "sandwich" appears 3 times
The token "wizard" appears 1 times
The token "transfigured" appears 1 times
tf-idf

在这里插入图片描述

分子是语料库中的文档总数, 分母是语料库中包含该单词的文档总数。 一个单词的 tf-idf值是其单词频数和逆文档指数的乘积。 当 use idf 关键词参数被设置为34 默认值 Ture 的时候, TfidfTransformer 将返回 tιidf 权重。

from sklearn.feature_extraction.text import TfidfVectorizer
corpus = [
    'The dog ate a sandwich and I ate a sandwich',
    'The wizard transfigured a sandwich'
]
vectorizer = TfidfVectorizer(stop_words='english',use_idf=True)
print(vectorizer.fit_transform(corpus).todense())
[[0.75458397 0.37729199 0.53689271 0.         0.        ]
 [0.         0.         0.44943642 0.6316672  0.6316672 ]]
print(vectorizer)
TfidfVectorizer(analyzer='word', binary=False, decode_error='strict',
                dtype=<class 'numpy.float64'>, encoding='utf-8',
                input='content', lowercase=True, max_df=1.0, max_features=None,
                min_df=1, ngram_range=(1, 1), norm='l2', preprocessor=None,
                smooth_idf=True, stop_words='english', strip_accents=None,
                sublinear_tf=False, token_pattern='(?u)\\b\\w\\w+\\b',
                tokenizer=None, use_idf=True, vocabulary=None)

sublinear tf关键词参数设置为True时,TfdfTransformer会计算单词频数的对数缩放值。标准化和对数缩放之后的单词频数可以表示一个文档中单词出现的频数,同时也能缓和不同文档大小的影响。

在这里插入图片描述

from sklearn.feature_extraction.text import TfidfVectorizer
corpus = [
    'The dog ate a sandwich and I ate a sandwich',
    'The wizard transfigured a sandwich'
]
vectorizer = TfidfVectorizer(stop_words='english',sublinear_tf=True,use_idf=True)
print(vectorizer.fit_transform(corpus).todense())
[[0.73420898 0.43363565 0.52239573 0.         0.        ]
 [0.         0.         0.44943642 0.6316672  0.6316672 ]]

通过比较 ti-df 权重和真实单词频数,我们能看到在语料库中许多文档中常见的单词 (例如 sandwich), 都已经被惩罚 。

空间有效特征向量化与哈希技巧

在前面的示例中,都有一个字典包含语料库中所有独特标记被用于将文档中的标记映射到特征向量元素。
然而创建这个字典有两个缺点,首先,需要遍历两次语料库,第 一次遍历用于创建字典,第二次遍历用于为文档创建特征向量: 其次, 字典必须存储在 内存中 , 这对于大语料库来说这是很昂贵的。

我们可以通过对标记使用哈希函数直接决定其 在特征向量中的索引来避免创建这个字典,这个捷径叫作哈希技巧,。

在这里插入图片描述

上述方法有可能使两个原始特征的哈希后位置在一起导致词频累加特征值变大,为了解决这个问题,出现了hash Trick的变种signed hash trick,此时除了哈希函数h,多了一个哈希函数,如下:

在这里插入图片描述

from sklearn.feature_extraction.text import HashingVectorizer

corpus = ['the', 'ate', 'bacon', 'cat']
vectorizer = HashingVectorizer(n_features=6)
print(vectorizer.transform(corpus).todense())
[[-1.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  1.  0.  0.]
 [ 0.  0.  0.  0. -1.  0.]
 [ 0.  1.  0.  0.  0.  0.]]

哈希技巧是无状态的。因为哈希技巧不需要初始遍历语料库,它能被用于在并行在线 应用或者流式应用中创建特征向量。

词向量

词向量是一种减轻了一些词袋模型缺点的文本表示法。词袋模型使用一个标量表示一个标记,而词向量则使用一个向量。向量经常会被压缩,通常包含50~500个维度。这些表示单词的向量处于一个度量空间中。语义相似的单词对应的向量互相也很接近。具体来说,词向量参数化的函数,接受一个来自一些语言的标记作为输入项,并产出一个向量。
这个函数本质上是一个词向量矩阵参数化的查找表。这个矩阵是如何学习的呢?

在这里插入图片描述

在一个大型语料库上训练一个如示例中的序列分类器将耗 费大量的计算能力,但是产出的词向量可以运用到许多领域。正因如此,我们经常会使用 提前训练好的词向量。在本节中我们将使用在谷歌新闻语料库上训练过的 word2vec 词 向 量。该语料库包含超过 1000 亿个单词,同时 word2vec 词向量包含针对超过 300 万个英语 单词的 300 维向量。我们也将使用 Python 库 gensim 来检查模型, 衡量单词的相似度,并 完成类比。

# See https://radimrehurek.com/gensim/install.html for gensim installation instructions
# Download and gunzip the word2vec embeddings from 
# https://drive.google.com/file/d/0B7XkCwpI5KDYNlNUTTlSS21pQmM/edit?usp=sharing
import gensim
#'./GoogleNews-vectors-negative300.bin'
# The model is large
from gensim.models import Word2Vec
model = gensim.models.KeyedVectors.load_word2vec_format("https://s3.amazonaws.com/dl4j-distribution/GoogleNews-vectors-negative300.bin.gz", binary=True)

# Let's inspect the embedding for "cat"
embedding = model.word_vec('cat')
print("Dimensions: %s" % embedding.shape)
print(embedding)

语义相似单词的向量比语义不同单词的向量更相似

# The vectors for semantically similar words are more similar than the vectors for semantically dissimilar words
print(model.similarity('cat', 'dog'))
print(model.similarity('cat', 'sandwich'))
# Puppy is to cat as kitten is to...
print(model.most_similar(positive=['puppy', 'cat'], negative=['kitten'], topn=1))
# Palette is to painter as saddle is to...
for i in model.most_similar(positive=['saddle', 'painter'], negative=['palette'], topn=3):
    print(i)
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值