Сравнение FeatureHasher и DictVectorizer

Machine LearningMachine LearningBeginner
Практиковаться сейчас

This tutorial is from open-source community. Access the source code

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом лабораторном задании мы изучим векторизацию текста, которая представляет собой процесс представления нечисловых входных данных (например, словарей или текстовых документов) в виде векторов вещественных чисел. Мы сравним два метода, FeatureHasher и DictVectorizer, путём векторизации текстовых документов, предварительно обработанных (токенизированных) с помощью настраиваемой функции на Python.

Советы по использованию ВМ

После запуска ВМ перейдите в левый верхний угол и переключитесь на вкладку Ноутбук, чтобы приступить к практике в Jupyter Notebook.

Иногда вам может потребоваться подождать несколько секунд, пока Jupyter Notebook полностью загрузится. Проверка операций не может быть автоматизирована из-за ограничений Jupyter Notebook.

Если вы столкнетесь с проблемами во время обучения, не стесняйтесь обращаться к Labby. Оставьте отзыв после занятия, и мы оперативно решим проблему для вас.

Загрузка данных

Мы загрузим данные из 20newsgroups_dataset, который содержит около 18000 публикаций новостных групп по 20 темам, разделенных на две подмножества: одно для обучения, а другое для тестирования. Для простоты и снижения вычислительных затрат мы выбираем подмножество из 7 тем и используем только обучающий набор.

from sklearn.datasets import fetch_20newsgroups

categories = [
    "alt.atheism",
    "comp.graphics",
    "comp.sys.ibm.pc.hardware",
    "misc.forsale",
    "rec.autos",
    "sci.space",
    "talk.religion.misc",
]

print("Loading 20 newsgroups training data")
raw_data, _ = fetch_20newsgroups(subset="train", categories=categories, return_X_y=True)
data_size_mb = sum(len(s.encode("utf-8")) for s in raw_data) / 1e6
print(f"{len(raw_data)} documents - {data_size_mb:.3f}MB")

Определение функций предварительной обработки

Токеном может быть слово, часть слова или что угодно, находящееся между пробелами или символами в строке. Здесь мы определяем функцию, которая извлекает токены с использованием простого регулярного выражения (regex), которое соответствует Unicode-символам, составляющим слово. Это включает в себя большинство символов, которые могут быть частью слова на любом языке, а также цифры и нижнее подчеркивание:

import re

def tokenize(doc):
    """Extract tokens from doc.

    This uses a simple regex that matches word characters to break strings
    into tokens. For a more principled approach, see CountVectorizer or
    TfidfVectorizer.
    """
    return (tok.lower() for tok in re.findall(r"\w+", doc))

Мы определяем дополнительную функцию, которая подсчитывает (частоту) появления каждого токена в заданном документе. Она возвращает словарь частот, который будет использоваться векторизаторами.

from collections import defaultdict

def token_freqs(doc):
    """Extract a dict mapping tokens from doc to their occurrences."""

    freq = defaultdict(int)
    for tok in tokenize(doc):
        freq[tok] += 1
    return freq

DictVectorizer

Мы проведем бенчмарк DictVectorizer, который является методом, принимающим словари в качестве входных данных.

from sklearn.feature_extraction import DictVectorizer
from time import time

t0 = time()
vectorizer = DictVectorizer()
vectorizer.fit_transform(token_freqs(d) for d in raw_data)
duration = time() - t0
print(f"done in {duration:.3f} s")
print(f"Found {len(vectorizer.get_feature_names_out())} unique terms")

FeatureHasher

Мы проведем бенчмарк FeatureHasher, который является методом, который строит вектор заданной длины, применяя хэш-функцию к признакам (например, токенам), а затем используя хэш-значения непосредственно в качестве индексов признаков и обновляя результирующий вектор по этим индексам.

from sklearn.feature_extraction import FeatureHasher
import numpy as np

t0 = time()
hasher = FeatureHasher(n_features=2**18)
X = hasher.transform(token_freqs(d) for d in raw_data)
duration = time() - t0
print(f"done in {duration:.3f} s")
print(f"Found {len(np.unique(X.nonzero()[1]))} unique tokens")

Сравнение с специализированными текстовыми векторизаторами

Мы сравним предыдущие методы с CountVectorizer и HashingVectorizer.

from sklearn.feature_extraction.text import CountVectorizer, HashingVectorizer, TfidfVectorizer

t0 = time()
vectorizer = CountVectorizer()
vectorizer.fit_transform(raw_data)
duration = time() - t0
print(f"done in {duration:.3f} s")
print(f"Found {len(vectorizer.get_feature_names_out())} unique terms")

t0 = time()
vectorizer = HashingVectorizer(n_features=2**18)
vectorizer.fit_transform(raw_data)
duration = time() - t0
print(f"done in {duration:.3f} s")

t0 = time()
vectorizer = TfidfVectorizer()
vectorizer.fit_transform(raw_data)
duration = time() - t0
print(f"done in {duration:.3f} s")
print(f"Found {len(vectorizer.get_feature_names_out())} unique terms")

Построение графиков результатов

Мы построим графики скорости вышеперечисленных методов векторизации.

import matplotlib.pyplot as plt

dict_count_vectorizers = {
    "vectorizer": [
        "DictVectorizer\nна нечастотных словарях",
        "FeatureHasher\nна нечастотных словарях",
        "FeatureHasher\nна необработанных токенах",
        "CountVectorizer",
        "HashingVectorizer",
        "TfidfVectorizer"
    ],
    "speed": [
        2.4, 4.4, 7.2, 5.1, 11.7, 2.9
    ]
}

fig, ax = plt.subplots(figsize=(12, 6))

y_pos = np.arange(len(dict_count_vectorizers["vectorizer"]))
ax.barh(y_pos, dict_count_vectorizers["speed"], align="center")
ax.set_yticks(y_pos)
ax.set_yticklabels(dict_count_vectorizers["vectorizer"])
ax.invert_yaxis()
_ = ax.set_xlabel("скорость (МБ/с)")

Резюме

В этом лабаратории мы изучили векторизацию текста, сравнив два метода FeatureHasher и DictVectorizer и четыре специализированных текстовых векторизатора CountVectorizer, HashingVectorizer и TfidfVectorizer. Мы провели бенчмарк методов векторизации и построили графики результатов. Мы пришли к выводу, что HashingVectorizer показывает лучшие результаты, чем CountVectorizer, но в代价 этого теряется обратимость преобразования из-за коллизий хэшей. Кроме того, DictVectorizer и FeatureHasher показывают лучшие результаты, чем их аналог в текстовых векторизаторах для документов с ручным токенизацией, так как внутренний этап токенизации у первых векторизаторов компилирует регулярное выражение один раз и затем переиспользует его для всех документов.