Причина решения в настроениях социальных сетей на суахили

Эта статья была первоначально опубликована в блоге neurotech Africa.

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

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

«Почему я должен вам доверять?» Объяснение предсказаний любого классификатора ~ Марко Тулио Рибейро, Самир Сингх и Карлос Гуестрин.

Суахили — это лингва-франка, на котором говорят до 150 миллионов человек в Восточной Африке. Он является официальным языком в Танзании, ДРК, Кении и Уганде. В социальных сетях носители суахили обычно выражаются на своем местном диалекте.

Построение классификатора настроений в социальных сетях на суахили

Анализ настроений опирается на множество смыслов слов и культурные знания и может зависеть от возраста, пола и социально-экономического положения. В сегодняшнем задании я буду использовать набор данных из Twitter, изначально размещенный на Google Natural language processing hack series by zindi Africa, с целью классификации того, является ли предложение на суахили позитивным, негативным или нейтральным по настроению.

Набор данных содержит три колонки: id — уникальный идентификатор уникального твита на суахили, tweets — фактический текст твита на суахили, и labels — метка твита на суахили, либо отрицательная(-1), либо нейтральная(0), либо положительная(1), с 2263 наблюдениями.

Как насчет распределения меток?

Большинство собранных твитов нейтральны, что показывает, что наши метки несбалансированы.

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

  1. удаление неалфавитно-цифрового текста.
  2. удаление стоп-слов
  3. преобразование всех твитов в нижний регистр.
  4. удаление знаков препинания, ссылок, эмодзи и пробелов.
  5. токенизация текста на основе каждого слова.
  6. последний шаг — добавление всех чистых твитов в новые колонки с именем clean_tweets.

Следует отметить, что nltk не содержит стоп-слов суахили, но вы должны создать свой собственный список и применить его к твитам. Я только что создал CSV-файл с парой стоп-слов на суахили, таких как na, kwa, kama, lakini, ya, take и т.д., которые я буду применять здесь.

Стоп-слова — это набор часто используемых слов в любом языке. Например, в английском языке «the», «is» и «and» можно легко отнести к стоп-словам. В приложениях НЛП и интеллектуального анализа текста стоп-слова используются для исключения неважных слов, позволяя приложениям сосредоточиться на важных словах.

Для упрощения работы давайте воспользуемся одной функцией для выполнения всех задач.

def clean_tweets(tweet):
    '''
        function to clean tweet column, make it ready for transformation and modeling
    '''
    tweet = tweet.lower() #convert text to lower-case
    tweet = re.sub('[‘’“”…,]', '', tweet) # remove punctuation
    tweet = re.sub('[()]', '', tweet) # remove parenthesis
    tweet = re.sub("[^a-zA-Z]"," ",tweet) #remove numbers and keep text/alphabet only
    tweet_list = nltk.word_tokenize(tweet)
    clean_tweets=[i for i in tweet_list if i not in swstopwords] # remove stop words
    return ' '.join(clean_tweets)

   df['clean_tweets'] = df['Tweets'].apply(clean_tweets)
Вход в полноэкранный режим Выход из полноэкранного режима

функция для очистки колонки твитов, чтобы подготовить ее к преобразованию и моделированию

Теперь твиты очищены и готовы к дальнейшим процессам

наборы данных после применения функции cleanan_tweet

Пора заняться анализом твитов на суахили, обратив внимание на полярность и субъективность. Но подождите! Что означают полярность и субъективность?

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

Полярность настроения для элемента определяет направленность выраженного настроения, т.е. определяет, выражает ли текст положительное, отрицательное или нейтральное настроение пользователя относительно рассматриваемого объекта.

Субъективность — это мера того, насколько фактологичен текст, в диапазоне от 0 (чистый факт) до 1 (чистое мнение).

Для анализа твитов я буду использовать textblob.

def polarity_score(tweet):
  '''
        This function takes in a text data and returns the polarity of the text
        Polarity is float which lies in the range of [-1,0,1] where 1 means positive statement, 0 means positive statement
        and -1 means a negative statement
    '''
  return TextBlob(tweet).sentiment.polarity

  def subjectivity_score(tweet):
  '''
      This function takes in a text data and returns the subectivity of the text.
      Subjectivity sentences generally refer to personal opinion,
      emotion or judgment whereas objective refers to factual information.
      Subjectivity is also a float which lies in the range of [0,1].
  '''
  return TextBlob(tweet).sentiment.subjectivity

  #apply above functions to the data
df['polarity_score']=df['clean_tweets'].apply(polarity_score)
df['subjectivity_score']=df['clean_tweets'].apply(subjectivity_score)
Войдите в полноэкранный режим Выйти из полноэкранного режима

оценка полярности

Теперь попробуем суммировать общую полярность и субъективность всего набора данных

Общая полярность данных твитов составляет 0,01

Общая субъективность данных твитов составляет 0,03

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

Давайте попробуем визуализировать распределения полярности и субъективности каждого класса независимо друг от друга

# visualization
fig = make_subplots(rows=3, cols=2,subplot_titles=("Polarity Score Distribution-Negative", "Subjectivity Score Distribution-Negative",
                                                   "Polarity Score Distribution-Neutral", "Subjectivity Score Distribution-Neutral",
                                                   'Polarity Score Distribution-Positive','Subjectivity Score Distribution-Positive'),
                    x_title="Score",y_title='Frequency')
fig.add_trace(
    go.Histogram(x=df[df['Labels']== -1 ]['polarity_score']),
    row=1, col=1)
fig.add_trace(
    go.Histogram(x=df[df['Labels']== -1 ]['subjectivity_score']),
    row=1, col=2)
fig.add_trace(
    go.Histogram(x=df[df['Labels']== 0 ]['polarity_score']),
    row=2, col=1)
fig.add_trace(
    go.Histogram(x=df[df['Labels']== 0 ]['subjectivity_score']),
    row=2, col=2)
fig.add_trace(
    go.Histogram(x=df[df['Labels']== 1]['polarity_score']),
    row=3, col=1)
fig.add_trace(
    go.Histogram(x=df[df['Labels']== 1]['subjectivity_score']),
    row=3, col=2)
fig.show(renderer="colab")
Войдите в полноэкранный режим Выйти из полноэкранного режима

Вот так,

распределение каждого класса по полярности и субъективности

С точки зрения субъективности, все три класса имеют тенденцию к сходству, значимых различий не наблюдается, но полярность негативного класса отличается от позитивного и нейтрального классов по перекосу.

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

word_freq=pd.DataFrame(df['clean_tweets'].str.split(expand=True).stack().value_counts()).reset_index()
word_freq=word_freq.rename(columns={'index':'Word', 0:'Count'})
fig = px.bar(df, x=word_freq['Word'][0:20], y=word_freq['Count'][0:20])
fig.update_layout(xaxis_title="Word", yaxis_title="Count", title="Top 20 most Frequent words in across entire tweet data")
fig.show(renderer="colab")
Войти в полноэкранный режим Выход из полноэкранного режима

habari, leo, siku, namba — самые частотные слова в общем содержимом твитов.

# Negative Tweets Word Frequency
word_freq_neg=pd.DataFrame(df[df['Labels']== -1]['clean_tweets'].str.split(expand=True).stack().value_counts()).reset_index()
word_freq_neg=word_freq_neg.rename(columns={'index':'Word',0:'Count'})

# Neutral Tweets Word Frequency
word_freq_neut=pd.DataFrame(df[df['Labels']== 0]['clean_tweets'].str.split(expand=True).stack().value_counts()).reset_index()
word_freq_neut=word_freq_neut.rename(columns={'index':'Word',0:'Count'})

# Positive Tweets Word Frequency
word_freq_pos=pd.DataFrame(df[df['Labels']== 1]['clean_tweets'].str.split(expand=True).stack().value_counts()).reset_index()
word_freq_pos=word_freq_pos.rename(columns={'index':'Word',0:'Count'})

fig = make_subplots(rows=1, cols=3,subplot_titles=("Top 20 most frequent words-Negative", "Top 20 most frequent words-Neutral", "Top 20 most frequent words-Positive"),
                    x_title="Word",y_title='Count')
fig.add_trace(
    go.Bar(x=word_freq_neg['Word'].iloc[0:20], y=word_freq_neg['Count'].iloc[0:20]),
    row=1, col=1
    )
fig.add_trace(
    go.Bar(x=word_freq_neut['Word'].iloc[0:20], y=word_freq_neut['Count'].iloc[0:20]),
    row=1, col=2
    )
fig.add_trace(
    go.Bar(x=word_freq_pos['Word'].iloc[0:20], y=word_freq_pos['Count'].iloc[0:20]),
    row=1, col=3
    )
fig.show(renderer="colab")
Войти в полноэкранный режим Выход из полноэкранного режима

В твитах негативного класса наиболее употребляемыми словами являются watu, leo и siku, в твитах нейтрального класса наиболее употребляемыми словами являются habarikazi и mtu, а в твитах положительного класса наиболее часто используемыми словами являются habari, leo, asante.

Давайте подготовим наш окончательный набор данных для моделирования, разделив его на две группы (train и test)

# data split
X = df["clean_tweets"]
y = df["Labels"]

seed = 42

x_train,x_test,y_train,y_test= train_test_split(X,y,stratify=y, test_size=0.2, random_state=seed)
Вход в полноэкранный режим Выйти из полноэкранного режима

Затем я могу подготовить наш конвейер данных для обучения суахилийских настроений, определив TfidfVectorizer в качестве векторизатора и LogisticRegression в качестве алгоритма для построения нашей модели. Используя инициализированный конвейер, я могу обучить классификатор, используя обучающий набор твитов.

# instantiating model pipeline
model = make_pipeline(
    TfidfVectorizer(),
    LogisticRegression()
)

# training model
model.fit(x_train,y_train)
Вход в полноэкранный режим Выход из полноэкранного режима

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

print("Classification Report")
print("t", "_" * 45, "n" * 2)
print(
    classification_report(
        y_test,
        model.predict(x_test),
        target_names=["Negative", "Neutral","Positive"]
        )
    )
Войти в полноэкранный режим Выйти из полноэкранного режима

Отчет о классификации показывает, что производительность не очень хорошая, точность нашей модели составляет 60%

Интерпретируемость результатов

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

Чем выше интерпретируемость модели машинного обучения, тем легче кому-то понять, почему были приняты определенные решения или предсказания. Модель лучше интерпретируема, чем другая модель, если ее решения человеку легче понять, чем решения другой модели.

Я должен рассмотреть возможность предсказания вероятностей с помощью классификатора LogisticRegression вместо 0 или 1 просто потому, что LIME требует модель, которая выдает оценки вероятности для каждого предсказания, чтобы объяснить причину решения.

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

Приведенное выше наблюдение показывает, что вероятность нейтрального класса выше (0.72) по сравнению с двумя другими классами, и причиной такого решения являются слова walimu, walikuwa и mwanzoni .

Приведенное выше наблюдение показывает, что веса обоих трех классов сопоставимы, но из-за высокого веса слова polisi твиту предсказан негативный класс.

Как компании могут извлечь выгоду из анализа настроений клиентов?

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

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

Заключительные мысли

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

Полный код, использованный в этой статье, можно найти в репозитории GitHub.

Оцените статью
devanswers.ru
Добавить комментарий