Вопрос о балансировки обучающих данных для анализа тональности (машинное обучение)

Вопрос или проблема

Мой вопрос касается того, когда балансировать тренировочные данные для анализа настроений. Оценив свой набор данных для обучения, который имеет 3 метки (хорошо, плохо, нейтрально), я заметил, что нейтральных меток в два раза больше, чем остальных 2 в сумме, поэтому я использовал функцию для случайного удаления нейтральных меток. Тем не менее, я не был уверен, должен ли я делать это до или после создания сопоставлений vocab2index. Чтобы объяснить, я преобразую свои текстовые данные в числовые, создавая словарь слов в обучающих данных и связывая их с числами с помощью функции enumerate. Я думаю использовать этот словарь значений vocab: index для преобразования тренировочных данных в числовой формат. Я также использую тот же словарь для числового представления тестовых данных, удаляя любые слова, которые не существуют в словаре. Когда я проходил курс по этой теме, они балансировали обучающие данные ПОСЛЕ создания словаря vocab2index. Однако, когда я подумал об этом в своей реализации, это не имело смысла. А что, если некоторые слова из оригинального словаря полностью исчезли, тогда мы не обучаем классификатор машинного обучения на этих словах, но они также не будут удалены из тестовых данных (поскольку слова убираются из X_test на основе того, существуют ли они в словаре vocab2index). Так что, должен ли я балансировать данные ДО создания словаря vocab2index? Я прикрепил код для создания X_train и X_test ниже на случай, если это поможет. Спасибо!

def create_X_train(training_data="Sentences_75Agree_csv.csv"):
    data_csv = pd.read_csv(filepath_or_buffer=training_data, sep='.@', header=None, names=['sentence','sentiment'], engine="python")
    list_data = []
    for index, row in data_csv.iterrows():
        dictionary_data = {}
        dictionary_data['message_body'] = row['sentence']
        if row['sentiment'] == 'positive':
             dictionary_data['sentiment'] = 2
        elif row['sentiment'] == 'negative':
             dictionary_data['sentiment'] = 0
        else:
             dictionary_data['sentiment'] = 1 # Для нейтрального настроения
        list_data.append(dictionary_data)
    dictionary_data = {}
    dictionary_data['data'] = list_data
    messages = [sentence['message_body'] for sentence in dictionary_data['data']]
    sentiments = [sentence['sentiment'] for sentence in dictionary_data['data']]

    tokenized = [preprocess(sentence) for sentence in messages]
    bow = Counter([word for sentence in tokenized for word in sentence]) 
    freqs = {key: value/len(tokenized) for key, value in bow.items()} # ключи - это слова в словаре, значения - количество этих слов
    # Удаление 5 самых общих слов из данных
    high_cutoff = 5
    K_most_common = [x[0] for x in bow.most_common(high_cutoff)] 
    filtered_words = [word for word in freqs if word not in K_most_common]
    # Создание словаря vocab2index:
    vocab = {word: i for i, word in enumerate(filtered_words, 1)}
    id2vocab = {i: word for word, i in vocab.items()}
    filtered = [[word for word in sentence if word in vocab] for sentence in tokenized] 
    
    # Балансировка тренировочных данных из-за большого количества нейтральных предложений
    balanced = {'messages': [], 'sentiments':[]}
    n_neutral = sum(1 for each in sentiments if each == 1)
    N_examples = len(sentiments)
    # print(n_neutral/N_examples)
    keep_prob = (N_examples - n_neutral)/2/n_neutral
    # print(keep_prob)
    for idx, sentiment in enumerate(sentiments):
        message = filtered[idx]
        if len(message) == 0:
            # пропустить это предложение, потому что его длина 0
            continue
        elif sentiment != 1 or random.random() < keep_prob:
            balanced['messages'].append(message)
            balanced['sentiments'].append(sentiment)

    token_ids = [[vocab[word] for word in message] for message in balanced['messages']]
    sentiments_balanced = balanced['sentiments']
    # Модульный тест:
    unique, counts = np.unique(sentiments_balanced, return_counts=True)
    print(np.asarray((unique, counts)).T)
    print(np.mean(sentiments_balanced))
    ##################
    # Левое дополнение и обрезка до одной длины 
    X_train = token_ids
    for i, sentence in enumerate(X_train):
        if len(sentence) <=30:
            X_train[i] = ((30-len(sentence)) * [0] + sentence)
        elif len(sentence) > 30:
            X_train[i] = sentence[:30]
    return vocab, X_train, sentiments_balanced
def create_X_test(test_sentences, vocab):
    tokenized = [preprocess(sentence) for sentence in test_sentences]
    filtered = [[word for word in sentence if word in vocab] for sentence in tokenized] # X_test отфильтрован до только слов в обучающем словаре
    # Альтернативный метод с использованием функционального программирования:
    # filtered = [list(filter(lambda a: a in vocab, sentence)) for sentence in tokenized]
    token_ids = [[vocab[word] for word in sentence] for sentence in filtered] # Преобразование данных в числовой формат
    # Удаление коротких предложений в X_test
    token_ids_filtered = [sentence for sentence in token_ids if len(sentence)>10]
    X_test = token_ids_filtered
    for i, sentence in enumerate(X_test):
        if len(sentence) <=30:
            X_test[i] = ((30-len(sentence)) * [0] + sentence)
        elif len(sentence) > 30:
            X_test[i] = sentence[:30]
    return X_test

Я постараюсь ответить в меру своих возможностей и знаний, которые приобрел.

1) Не удаляйте хорошие данные просто для того, чтобы сбалансировать их с менее многочисленным классом.

2) Вы можете использовать библиотеки Python imbalanced-learn и Smote для работы с несбалансированными данными, но поскольку это текстовые данные, ваши результаты могут быть не столь благоприятными, как вы ожидаете. Снова же это также зависит от области применения текстового языка.

3) Используйте методы ансамблей/механизм голосования/техники бустинга для улучшения вашей модели.

Надеюсь, эти советы помогут вам.

Ответ или решение

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

1. Подход к балансировке обучающих данных

Когда мы говорим о балансировке обучающих данных, важно учитывать, что пересеты и утраты информации могут значительно повлиять на модель. Если вы будете удалять записи до создания словаря vocab2index, то молчаливая информация о некоторых словах может потеряться при дальнейшем обучении модели. Наоборот, если оставите слова, которых нет в финальном наборе данных, вы можете создать неубедительную модель, так как она будет учиться на не полностью представленных данных.

Рекомендация:

Я рекомендую сначала балансировать данные, а затем создавать словарь vocab2index. Это позволит сохранить слова, которые могут быть важны для определенной метки, даже если их количество недостаточно велико.

2. Создание и использование словаря vocab2index

Словарь vocab2index необходимо создавать на основе всех строк данных, которые впоследствии используете для обучения. Это гарантирует, что все слова, имеющиеся в обучающих данных, будут учтены. Если в процессе балансировки данных вы удалите парные записи (например, много нейтральных), это может привести к тому, что в словаре останутся слова, которые вам больше не нужны.

Таким образом, ваша реализация может выглядеть следующим образом:

  • Сначала выполняйте балансировку данных с учетом как положительных, так и отрицательных меток в вашем наборе данных.
  • После балансировки создайте словарь vocab2index.

3. Использование методов балансировки

Используйте методы, такие как переподбор (undersampling) или дополнение (oversampling), чтобы сбалансировать классы. Вместо простого удаления нейтральных меток, вы можете рассмотреть возможность создания синтетических данных для позитивных и негативных классов, что может позволить модели более эффективно учиться.

Кроме этого, использование библиотеки imbalanced-learn может помочь вам, но следует помнить, что методы для числовых данных не всегда хорошо работают с текстовыми данными без предварительной обработки и правильной настройки.

4. Улучшение производительности модели

Для повышения качества классификации можно применить ансамблевые методы, такие как бэггинг или бустинг, которые помогут вам улучшить результаты обучения путем комбинирования множества слабых классификаторов. Также стоит рассмотреть возможность использования более сложных моделей, таких как случайные леса или глубокие нейронные сети, которые могут быть более устойчивыми к различиям в классовом распределении.

Заключение

Ваша задача по балансировке данных для анализа настроений является важным шагом для достижения высококачественных результатов классификации. Необходимо учитывать порядок операций и методы, применяемые для обеспечения максимального сохранения информации. Применяя предложенные рекомендации, вы сможете создать более эффективную и точную модель для анализа текстовых данных.

Оцените материал
Добавить комментарий

Капча загружается...