Example #1
0
def pp_from_raw_generator(raw_file: str, chunk_size: int,
                          **pp_settings) -> pd.DataFrame:
    """
    Генератор предобработанных текстов
    :param raw_file: путь к файлу исходных текстов
    :param chunk_size: размер чанка для предобработки
    :param pp_settings: настройки препроцессора
    """
    pp = Preprocessor()
    for n, chunk in enumerate(
            pd.read_csv(raw_file,
                        encoding="cp1251",
                        quoting=3,
                        sep="\t",
                        chunksize=chunk_size)):
        try:
            pp_chunk = pp.preprocess_dataframe(df=chunk, **pp_settings)
        except Exception as e:
            logger = get_logger("ecs.data_tools.pp_from_raw_generator")
            error_ps(
                logger,
                f"Error occurred during preprocessing chunk {n} of file {raw_file}: {e}"
            )
            exit(1)
        else:
            yield pp_chunk
Example #2
0
 def __init__(self, preproc: str, language: str):
     self.language = language
     self.preproc = preproc
     self.map_config = ConfigParser()
     self.map_config.read_file(open(join(dirname(__file__), "map.ini"),
                                    'r'))
     self.logger = get_logger("ecs.Preprocessor2.Normalizer")
     section = f"Supported{self.language.capitalize()}Models"
     if section not in self.map_config.keys():
         raise ValueError(
             'Preprocessing is not supported for this language')
     if self.preproc != "no":
         if self.preproc not in list(self.map_config[section].keys()):
             raise ValueError(
                 f'The preprocessing technique is not supported for this language'
             )
         components = self.map_config['Supported' +
                                      self.language.capitalize() +
                                      'Models'][self.preproc].split('.')
         module_name = ".".join(components[:-1])
         try:
             module = import_module(module_name)
             self.class_type = getattr(module, components[-1])
         except ImportError:
             self.logger.error(f"Package '{module_name}' is not installed!")
             exit(1)
     else:
         self.class_type = None
Example #3
0
    def preprocess(self,
                   text: str,
                   remove_stopwords: bool,
                   remove_formulas: bool,
                   normalization: str,
                   language="auto",
                   default_lang="error") -> str:
        """
        Предобработка одного текста.
        ----------------------------
        Аргументы:

            text: Строка с текстом для предобработки.

            remove_stopwords: Удалять стоп-слова.
                              Возможные варианты: [True, False].

            remove_formulas: Удалять TeX-формулы, заключенные в $...$
                             Формулы вида $$...$$ удаляются всегда.
                             Возможные варианты: [True, False].

            normalizaion: Метод нормализации слова. Возможные варианты:
                          ["no", "lemmatization", "stemming"].

            language: Язык текста. По умолчанию язык определяется автоматически.
                      Возможные варианты: ["auto", "ru", "en"].
                      Автоопределение занимает время (особенно на больших текстах),
                      поэтому лучше задать определенный язык.

            default_lang: Действия в случае несоответствия текста ни одному из языков.
                          Аргумент используется только при language="auto".
                          Варианты:
                             - "random": Попробовать угадать язык случайным образом
                             - "error" : Вызвать ошибку
                             - "none"  : Вернуть None (default)
        """
        lang = language
        if language == "auto":
            lang = self.recognize_language(text.lower(), default_lang)
        if lang is None:
            raise ValueError("Unable to recognize language!")
        self.last_language = lang
        res = text
        res = self.__remove_email(res)
        if remove_formulas:
            res = self.__remove_single_formulas(res)
        res = self.__remove_md(res)
        if remove_stopwords:
            res = self.__dense(res)
            res = self.__remove_stopwords(res.lower(), lang)
        res = self.__beautify(res)
        if normalization != "no":
            try:
                res = Normalizer(normalization, lang).normalize(res)
                res = re.sub(" ".join(self.delim).strip(), self.delim, res)
            except ValueError:
                logger = get_logger("ecs.Preprocessor2.preprocess")
                logger.info(f"\n{lang_norm_hint(lang, normalization)}")
                exit()
        return res
Example #4
0
 def __trace_time(self, description: str):
     if self.DEBUG:
         if description.lower() == "init":
             self.timer.start()
             # print("Time recording started")
         else:
             logger = get_logger("ecs.Preprocessor2.__trace_time")
             logger.info(description,
                         "has taken {} sec".format(self.timer.check()))
Example #5
0
def vectorize_text(text: str, w2v_model: Word2Vec,
                   conv_type: str) -> np.ndarray:
    tokens = text.split()
    text_matrix = []
    for word in tokens:
        try:
            word_vector = w2v_model[word]
        except KeyError:
            word_vector = np.zeros(w2v_model.vector_size)
        text_matrix.append(word_vector)
    text_matrix = np.vstack(text_matrix)
    if conv_type == "sum":
        return text_matrix.sum(axis=0)
    elif conv_type == "mean":
        return text_matrix.mean(axis=0)
    elif conv_type == "max":
        return text_matrix.max(axis=0)
    else:
        get_logger("ecs.data_tools.vectorize_text").error(
            f"Conv type '{conv_type}' is not supported")
        exit(1)
Example #6
0
def aggregate_full_dataset(vector_gen) -> pd.DataFrame:
    logger = get_logger("ecs.data_tools.aggregate_full_dataset")
    rubricators = ["subj", "ipv", "rgnti"]
    full_df = pd.DataFrame(columns=["vectors", *rubricators])
    try:
        for chunk in vector_gen:
            chunk[rubricators] = chunk[rubricators].astype(str)
            full_df = pd.concat([full_df, chunk], ignore_index=True)
    except Exception as e:
        error_ps(logger,
                 f"Error occurred during loading the dataset in memory: {e}")
        exit(1)
    return full_df
Example #7
0
def create_report(model, x_test: np.ndarray, y_test: list, ignore_rubrics=()):
    # Для обратной совместимости используется старый код
    logger = get_logger("ecs.model_tool.create_report")
    pred = []
    try:
        for p in model.predict_proba(x_test):
            all_prob = pd.Series(p, index=model.classes_)
            for code in ignore_rubrics:
                try:
                    all_prob.drop(code)
                except KeyError:
                    pass
            pred.append(list(all_prob.sort_values(ascending=False).index))
    except Exception as e:
        error_ps(logger, f"Error occurred during model testing: {e}")
        exit(1)
    else:
        return count_stats(predicts=pred,
                           y_test=y_test,
                           amounts=[1, 2, 3, 4, 5, -1])
Example #8
0
def create_w2v(pp_sources: list, vector_dim: int, window_size: int,
               train_alg: str) -> Word2Vec:
    """
    Создать модель Word2Vec для предобработанных текстов.
    :param window_size: размер окна контекста
    :param vector_dim: размерность векторной модели
    :param train_alg: тип алгоритма обучения word2vec (cbow или skip-gram)
    :param pp_sources: список инстансов генератора
                       предобработанных данных (pp_generator или caching_pp_generator)
    :returns обученная модель Word2Vec
    """
    train_algoritm = {
        "cbow": 0,
        "skip-gram": 1
    }  # to transform into word2vec param
    logger = get_logger("ecs.data_tools.create_w2v")
    w2v = Word2Vec(size=vector_dim,
                   min_count=3,
                   workers=3,
                   window=window_size,
                   sg=train_algoritm[train_alg])
    init = False
    for n_source, pp_source in enumerate(pp_sources, start=1):
        info_ps(logger, f"Training W2V on source {n_source}/{len(pp_sources)}")
        for n_chunk, pp_chunk in enumerate(pp_source, start=1):
            try:
                if n_chunk % N_CHUNKS_INTERVAL == 0:
                    info_ps(logger, f"\nChunk {n_chunk}")
                sentence = [text.split() for text in pp_chunk["text"].values]
                w2v.build_vocab(sentence, update=init)
                # TODO: вынести количество эпох в параметры
                w2v.train(sentence, epochs=20, total_examples=len(sentence))
                init = True
            except Exception as e:
                error_ps(
                    logger,
                    f"An error occurred during training W2V: {e}. Source {n_source}, chunk {n_chunk} "
                    f"(~{(n_chunk - 1) * len(pp_chunk) + 1}{n_chunk * len(pp_chunk)} "
                    f"lines in clear file)")
                exit(1)
    return w2v
Example #9
0
def run_grid_search(model_instance, hyperparameters: dict, x_train: list,
                    y_train: list, binary: bool, n_folds: int,
                    n_jobs: int) -> dict:
    """
    Запустить поиск по сетке параметров для модели для поиска лучшей комбинации,
    чтобы затем обучить ее на полной выборке без CV
    :param model_instance: инстанс модели, например MLPClassifier()
    :param hyperparameters: словарь гиперпараметров,
                            где ключи - названия из документации,
                            а значения - списки значений гиперпараметров
    :param x_train: array-like список обучающих векторов
    :param y_train: array-like список меток
    :param binary: использовать ли OneVsAll
    :param n_folds: количество фолдов кросс-валидации
    :param n_jobs: количество параллельных потоков
    :return: словарь лучших параметров в совместимом формате
    """
    # TODO: Возможно, стоит добавить таймер
    scoring = 'f1_weighted'
    skf = StratifiedKFold(shuffle=True, n_splits=n_folds)
    hypers_copy = hyperparameters.copy()
    logger = get_logger("ecs.model_tools.run_grid_search")
    if binary:
        model_instance = OneVsRestClassifier(model_instance)
        for key in hyperparameters:
            hypers_copy["estimator__" + key] = hypers_copy.pop(key)
    grid_searcher = GridSearchCV(estimator=model_instance,
                                 param_grid=hypers_copy,
                                 n_jobs=n_jobs,
                                 scoring=scoring,
                                 cv=skf,
                                 verbose=0)
    info_ps(logger, "Fitting grid-searcher...")
    grid_searcher.fit(x_train, y_train)
    best_params = grid_searcher.best_params_
    # # Убираем "estimator__" из ключей
    # best_params = {}
    # for key, value in grid_searcher.best_params_.items():
    #     best_params[key.split("estimator__")[-1]] = value
    return best_params
Example #10
0
def create_clear_generators(base_dir: str, clear_filter: dict, chunk_size: int,
                            training_fpath: str, test_fpath: str,
                            experiment_title: str, pp_params: dict) -> dict:
    """
    Создает подходящий генератор чистых текстов.
    Если найден кэш, то создает читающий генератор,
    если нет - предобрабатывает сырые данные
    :param base_dir: базовая директория для поиска кэша
    :param clear_filter: словарь с настройками препроцессора
                         для поиска подходящего кэша
    :param chunk_size: размер чанка
    :param training_fpath: путь к сырому обучающему файлу
    :param test_fpath: путь к сырому тест-файлу (может быть равен '')
    :param experiment_title: название эксперимента
    :param pp_params: словарь с полными настройками препроцессора
    :return: словарь вида {'train': генератор, ['test': генератор]}
    """
    try:
        pp_sources = {}
        cached_clear = find_cached_clear(base_dir=base_dir,
                                         metadata_filter=clear_filter)
        clear_file_list = []
        # Если мы нашли кэш, список станет непустым
        # А если нет, то мы не зайдем в условие
        if len(cached_clear) > 0:
            # Если нашли больше, чем одну папку с чистыми текстами,
            # берем случайную
            _, clear_file_list = cached_clear.popitem()
        # Если список был пустым, то find_cache_for source
        # вернет пустую строку и будет создан кэширующий генератор
        train_pp_cache = find_cache_for_source(clear_file_list, training_fpath)
        if train_pp_cache:
            pp_sources[train_pp_cache] = pp_from_csv_generator(
                train_pp_cache, chunk_size)
        else:
            pp_sources[training_fpath] = create_caching_pp_gen(
                raw_path=training_fpath,
                exp_name=experiment_title,
                chunk_size=chunk_size,
                pp_params=pp_params)
        # Тут возможно 2 ситуации:
        # 1. Тестового файла не предусмотрено (ничего не делать)
        # 2. Тестовый кэш не найден (создать кэширующий генератор)
        if test_fpath:
            test_pp_cache = find_cache_for_source(clear_file_list, test_fpath)
            if test_pp_cache:
                pp_sources[test_pp_cache] = pp_from_csv_generator(
                    test_pp_cache, chunk_size)
            else:
                pp_sources[test_fpath] = create_caching_pp_gen(
                    raw_path=test_fpath,
                    exp_name=experiment_title,
                    chunk_size=chunk_size,
                    pp_params=pp_params)
        return train_test_match(pp_sources,
                                train_raw_path=training_fpath,
                                test_raw_path=test_fpath)
    except Exception as e:
        logger = get_logger("ecs.create_clear_generators")
        error_ps(logger,
                 f"Error occurred during creation of clear generators: {e}")
        exit(1)
Example #11
0
def remove_empty_items(lst: list):
    try:
        return list(filter(lambda x: len(x.strip()) > 0, lst))
    except AttributeError:
        logger = get_logger("ecs.Preprocessor2.remove_empty_items")
        logger.error(f"Error occurred during processing the list {lst}")
Example #12
0
import warnings
warnings.filterwarnings("ignore")
import sys

from ECS.interface.logging_tools import get_logger

val_logger = get_logger("ecs.validation")


# Функции для парсинга типов данных настроек
# (См. докстринг ValidConfig)

def is_int(value: str) -> bool:
    try:
        int(value)
        return True
    except ValueError:
        return False


def is_float(value: str) -> bool:
    try:
        float(value)
        return True
    except ValueError:
        return False


def is_bool(value: str) -> bool:
    return value.lower() in ["true", "false"]