字典特征提取

将类别中的特征进行one-hot编码处理。

keyvalue
类别one-hot编码

独热编码(one-hot)

  • one-hot编码用于将离散的分类标签转换为二进制向量,这里的关键词有两个:
    • 第一个是离散的分类
    • 另一个是二进制向量

离散的分类

Mnist手写数字识别中,分类是0-9这十个数字。虽然这10个数字是有大小区分的,但对于分类任务来说,数字0和数字1并不存在大小关系。它们仅仅是一种类别,只不过手写数字识别任务中,类别刚好是数字。这就是离散分类。

二进制向量

向量我们都能理解,[1, 2, 3, 4] 这是一个一维数组,也可以称之为一维向量。那么二进制向量,就是里面的数字都是二进制的,像是[0, 1, 0, 0]。

假设需要对黑人、黄种人、白人这三个类别进行分类。最容易想到的,便是以0代表黑人,以1代表黄种人,以2代表白人这种简单粗暴的方式。但这样不行。分类标签一个重要的作用,就是要计算预测标签与真实标签之间的相似性,从而计算loss值。loss值越小,说明预测标签与真实标签之间越接近。

相似性其实就是两个标签之间的距离。如果按照0代表黑人,以1代表黄种人,以2代表白人这种表示方法,那么黑人和黄种人之间距离差为1, 黄种人和黑人之间距离为1, 而黑人和白人之间距离为2。 这样在计算损失的时候是完全不能接受的:互相独立的标签之间,出现了不对等的情况。

因此,需要有一种表示方法,将互相独立的标签表示为互相独立的数字,并且数字之间的距离也相等。

这就是one-hot,也叫独热编码。 它就用二进制向量来表征这种离散的分类标签。

举例

类别one-hot编码
黑人100
黄种人010
白人001

这样得到的编码都是独立的。比如黑人标签,得到一个编码[1, 0, 0]。

在三维坐标系下,[1, 0, 0]、[0, 1, 0]和[0, 0, 1]这三个向量是互相垂直的,也就是互相正交独立。

他们之间距离差相等,这就解决了上面说的独立的标签之间,表示方法不对等的情况。

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
from sklearn.feature_extraction import DictVectorizer

def dict_demo():
    """
    字典特征抽取
    :return:
    """
    data = [{'city': '北京','temperature':100}, {'city': '上海','temperature':60}, {'city': '深圳','temperature':30}]
    # 1、实例化一个转换器类
    transfer = DictVectorizer(sparse=True)

    # 2、调用fit_transform()
    data_new = transfer.fit_transform(data)
    print("data_new:\n", data_new.toarray(), type(data_new))
    print("特征名字:\n", transfer.get_feature_names_out())

    return None


if __name__ == "__main__":
    # 字典特征抽取
    dict_demo()
1
2
3
4
5
6
data_new:
 [[  0.   1.   0. 100.]
 [  1.   0.   0.  60.]
 [  0.   0.   1.  30.]] <class 'scipy.sparse._csr.csr_matrix'>
特征名字:
 ['city=上海' 'city=北京' 'city=深圳' 'temperature']

文本特征提取

从文本中提取出计算机能识别的数字特征

词频统计(CountVectorizer)

统计每个特征值出现的次数(每个词都是一个特征值)

通常使用CountVectorizer类会将文本中的词语转换为词频矩阵。 例如矩阵中包含一个元素a[i][j],它表示j词在i类文本下的词频。它通过fit_transform函数计算各个词语出现的次数,通过get_feature_names()可获取词袋中所有文本的关键字,通过toarray()可看到词频矩阵的结果。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from sklearn.feature_extraction.text import CountVectorizer

def count_demo():
    """
    文本特征抽取:CountVecotrizer
    :return:
    """
    data = [
        "life is short,i like like python",
        "life is too long,i dislike python",
        "talk is cheap, show me my code",
    ]
    # 1、实例化一个转换器类
    transfer = CountVectorizer(stop_words=["is", "too"])

    # 2、调用fit_transform
    data_new = transfer.fit_transform(data)
    print("特征矩阵:\n", data_new.toarray())
    print("特征名字:\n", transfer.get_feature_names_out())

    return None

if __name__ == "__main__":
    # 文本特征抽取:CountVecotrizer
    count_demo()
1
2
3
4
5
6
7
特征矩阵:
 [[0 0 0 1 2 0 0 0 1 1 0 0]
 [0 0 1 1 0 1 0 0 1 0 0 0]
 [1 1 0 0 0 0 1 1 0 0 1 1]]
特征名字:
 ['cheap' 'code' 'dislike' 'life' 'like' 'long' 'me' 'my' 'python' 'short'
 'show' 'talk']

词频-逆文件频率(TfidfVectorvizer)

TF-IDF(Term Frequency-Inverse Document Frequency, 词频-逆文件频率)都带有频率,具体含义是指:一个词语在一篇文章中出现次数越多, 同时在所有文档中出现次数越少, 越能够代表该文章。

词频(Term Frequency)

TF(Term Frequency, 词频)表示词条在文本中出现的频率。

$$ TF_{i, j}=\frac{n_{i, j}}{\sum_{k} n_{k, j}}$$

其中, $n_{i, j}$ 表示词条 $t_{i}$ 在文档 $doc_{j}$ 中出现的次数, $TF_{i, j}$ 就是表示词条 $t_{i}$ 在文档 $doc_{j}$ 中出现的频率。

逆文件频率(Inverse Document Frequency)

IDF(Inverse Document Frequency, 逆文件频率)表示关键词的普遍程度。如果包含此词条的文档越少,IDF越大,则说明此词条具有很好的类别区分能力

$$ IDF_{i}=\log \frac{|D|}{1+\left|j: t_{i} \in doc_{j}\right|} $$

  • 其中:
    • $|D|$ 表示所有文档的数量。
    • $\left|j: t_{i} \in doc_{j}\right|$ 表示包含词条 $t_{i}$ 的文档数量
      • 为什么这里要加 1 呢? 主要是防止包含词条 $t_{i}$ 的数量为 0 从而导致运算出错的现象发生。

某一特定文件内的高词语频率, 以及该词语在整个文件集合中的低文件频率, 可以产生出高权重的 TF-IDF。因此, TF-IDF倾向于过滤掉常见的词语, 保留重要的词语, 表达为 $TF-IDF=TF\cdot IDF$

总结

TF-IDF:采用一种统计方法,根据字词的在文本中出现的次数和在整个语料中包含此字词的文档倒频率来计算一个字词在整个语料中的重要程度。它的优点是能过滤掉一些常见的却无关紧要本的词语,同时保留影响整个文本的重要字词。

TF(Term Frequency)表示某个字词在整篇文章中出现的频率。 IDF(InversDocument Frequency)表示计算倒文本频率。文本频率是指包含某个字词所有文档占在整个语料所有文档之比。倒文档频率又称为逆文档频率,它是文档频率的倒数,主要用于降低所有文档中一些常见却对文档影响不大的词语的作用。

参考

https://zhuanlan.zhihu.com/p/97273457 https://www.zhihu.com/tardis/zm/art/268886634?source_id=1005 https://zhuanlan.zhihu.com/p/634296763