Текст-майнинг с пандами, облаками и яблоками

от автора

Привет, Хабр!

Меня зовут Пётр Мананников я Data Scientist и являюсь участником профессионального сообщества NTA. Представьте ситуацию: вас назначили спикером на мероприятии, и вы даже знаете, о чем хотите рассказать аудитории. Но будет ли публикой воспринят ваш доклад так, как вы себе это представляли? Давайте посмотрим, что может пойти не так, и как это исправить.

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

Данное исследование поможет разобраться с нашими вербальными привычками и подсветит зоны роста. К его созданию меня подтолкнул спикер одного из youtube каналов it-направленности. Его речь, наполненная идиомами и вводными словами, мешала восприятию основного полезного контента. Впоследствии родилась идея перевести аудиозаписи роликов в текст и выяснить, какие выражения чаще других перегружают речь. Первой задачей стала транскрибация целевой аудиодорожки, второй – анализ текста, третьей — выводы и работа над ошибками.

Детали исследования с полным кодом я выложил на GitHub.

Транскрибация

Поиск качественного инструмента для анализа аудио свелся к выбору между облачными сервисами. Решения, доступные ‘for free’ в открытых репозиториях, не соответствовали моим ожиданиям по качеству результата. Адекватное решение, способное обрабатывать длинные записи, нашлось только у тындекса. После нетривиальных настроек облака стал доступен API асинхронного распознавания. Настройки сервиса описаны здесь: cloud.yandex.ru/docs/speechkit/. Для теста была записана аудиодорожка с моими впечатлениями за текущий год. Далее в коде используется именно она.

Обработка mp3-файла

import pandas as pd import requests import time import json from collections import Counter

Подключаемся к cloud.yandex.ru , проходим все стартовые настройки сервера и рабочего пространства. Заливаем аудиозапись в выделенное хранилище облака, назначаем права на чтение сервису Speech_Kit, копируем ссылку на файл, вставляем её в POST-запрос:

# параметры запроса key = 'ваш API - key yc’  # путь к файлу в бакете YC filelink = 'https://storage.yandexcloud.net/bucket0011/test_audio.mp3'      body ={     "config": {         "specification": {             "languageCode": "ru-RU"             , "audioEncoding": "MP3"         }     },     "audio": {         "uri": filelink     } }  header = {'Authorization': 'Api-Key {}'.format(key)} POST = "https://transcribe.api.cloud.yandex.net/speech/stt/v2/longRunningRecognize"  # структура POST - запроса согласно инструкции API req = requests.post(POST, headers=header, json=body)  #Получаем ответ от сервера, из которого забирам ID задачи на обработку аудиозаписи. data = req.json() id_ = data['id']   print(id_)

Запрашиваем на сервере статус операции раз в 10 секунд и ожидаем окончания процесса распознавания:

for i in range(1000):     # проверяем распознано ли аудио     GET = "https://operation.api.cloud.yandex.net/operations/{id}"     req = requests.get(GET.format(id=id_), headers=header)     req = req.json()     # если распознано — выходим из цикла     if req['done']: break     # если нет — выводим сообщение     print("файл в обработке")     # ждём 10 секунд     time.sleep(10)  #создаем временные хранилища all_sentenses = [] sentenses_dic = {} all_text ='' for id,chunk in enumerate(req['response']['chunks']): #     if id%2==1:  #актуально только для двухканального аудио      chnk = chunk['alternatives'][0]['text'].lower()     all_text = all_text+chnk+' '          print("Часть распознанного текста: ",all_text[:55])

Переводим весь текст в нижний регистр, чистим от знаков пунктуации:

all_text = all_text.lower() all_text = all_text.replace('.','').replace(',','').replace(' - ','')

Анализ текста

Ищем уникальные идиомы из двух слов, не подпадающие под стандартные речевые обороты:

def get_word_pairs_dic(data):         dic_words_order1 = {}     counter=0     for num, word in enumerate(data.split()):          dic_words_order1[num] = word      all_p =[]     all_p2 =[]     pair=[]     pair2=[]     p=''     p2=''     cnt2=0     for word in dic_words_order1.items():         pair.append(word[1])      #     сочетания двух слов         pair2.append(word[1])         if int(word[0])%2==0:                     try:                 p = pair[0]+' '+pair[1]             except:                 pass             all_p.append(p)             pair=[]      #     сочетания двух слов со смещением на 1 слово         if int(word[0])%2==1:              try:                 p2 = pair2[0]+' '+pair2[1]             except:                 pass             all_p2.append(p2)             pair2=[]      #  ------------ чистим списки от пробелов -----------------     try:         all_p.pop(all_p.index(''))     except:         pass     try:         all_p2.pop(all_p2.index(''))     except:         pass     # -------------- удаляем дубликаты ------------------     all_p = list(set(all_p))     all_p2 = list(set(all_p2))      return all_p ,all_p2 all_pairs1 ,all_pairs2 = get_word_pairs_dic(all_text)

Считаем количество повторений пар из 2 слов в тексте:

def pair_counter(pair_list,text):     phrase_dic = dict(zip(pair_list,[text.count(k) for k in pair_list ]))     df_phrase = pd.DataFrame.from_dict(phrase_dic,  orient='index')     df_phrase = df_phrase.reset_index().rename(columns={'index': 'word_pair', 0: 'count'})     df_phrase.where(df_phrase['word_pair'].str.len()>5).sort_values(by='count', ascending = False)          return df_phrase def combine_pairs_count_results(pair_list, pair_list2, text):     df_pairs = pair_counter(pair_list, text)     df_pairs2 = pair_counter(pair_list2, text)     combine_df = pd.concat([df_pairs,df_pairs2])     combine_df = combine_df.where(combine_df['word_pair'].str.len()>5).drop_duplicates()     .sort_values(by='count', ascending = False)          return combine_df

Объединяем результаты и оставляем уникальные:

combine_df = combine_pairs_count_results(all_pairs1, all_pairs2,all_text) combine_df[:5]     word_pair  count 105   это был    6.0 28    в общем    4.0 55    и потом    3.0 81     22 год    3.0 71    был еще    3.0

Промежуточные выводы:

most_popular_phrase = combine_df.iloc[0]['word_pair'] print(f'В тексте часто повторяется фраза "{most_popular_phrase}"') В тексте часто повторяется фраза "это был"

Если мы ищем конкретные речевые обороты, можно упростить процесс перебора, задав их в явном виде:

bad_word_dic = {} bad_words = ['то есть','по моему','по-моему','честно говоря','как бы','так сказать','по сути','собственно говоря','как бы'              ,'таким образом','как говорится','так далее','как его','так вот','как сказать','на самом деле','в общем-то'              ,'в общем','в некотором роде','в принципе','типа того','в самом деле','всё такое','в целом','то есть'              ,'это самое','ну вот','ну это','так сказать','да ладно', 'можно сказать', 'как-то','не вопрос','без проблем'              ,'как-то так','ничего себе','соответственно']

Создаем словарь повторений выбранных фраз в тексте:

def bad_phrase_counter(text):     dic = dict(zip(bad_words,[text.count(k) for k in bad_words ]))     df = pd.DataFrame.from_dict(dic,  orient='index')     df = df.reset_index().rename(columns={'index': 'word', 0: 'count'})     return df

Считаем повторения слов-паразитов в тексте:

df = bad_phrase_counter(all_text) df.sort_values(by='count', ascending = False)[:5]             word  count 16       в общем      4 1       по моему      1 18    в принципе      0 19     типа того      0 20  в самом деле      0

Считаем количество повторений отдельных слов в тексте:

def word_counter(all_sentenses):     all_words = []     for sentance in all_sentenses:         for word in sentance.split(sep=' '):             word = word.lower()             if len(word)>=2:                 all_words.append(word)     unique = dict(zip(all_words,[all_words.count(i) for i in all_words]))     df = pd.DataFrame.from_dict(unique,  orient='index')     df2 =df.reset_index().rename(columns={'index': 'word', 0: 'count'})     return df2 all_sentenses = all_text.split() df_words = word_counter(all_sentenses) df_words.sort_values(by='count', ascending = False)[:5]    word  count 71  это     14 12   на     10 33  что     10 56   не     10 22  так     10

Находим самую «вредную» фразу из всего текста, даем рекомендации:

bad_word = str(combine_df.iloc[0]['word_pair']) bad_word2 = str(combine_df.iloc[1]['word_pair']) print(f'Самые популярные выражения в вашей речи - "{bad_word}" и "{bad_word2}".') word_to_post = bad_word.replace(' ','%20') word_to_post2 = bad_word2.replace(' ','%20') print(f'Ознакомьтесь, пожалуйста, с их синонимами: \nhttps://sinonim.org/s/       {word_to_post} \nhttps://sinonim.org/s/{word_to_post2}') Самые популярные выражения в вашей речи - "это был" и "в общем". Ознакомьтесь, пожалуйста, с их синонимами:  https://sinonim.org/s/это%20был  https://sinonim.org/s/в%20общем

Историческое отступление

Речь Стива Джобса

Давайте немного отвлечемся и для проверки работы скрипта возьмем текст презентации компании Apple 2007 года, где исполнительный директор анонсировал первый мобильный телефон компании с сенсорным дисплеем и функцией геолокации. Анализ текста позволит нам понять, какие фразы Стив Джобс использовал для представления своего нового творения общественности.

Для упрощения процесса загружаем речь спикеров с сайта https://singjupost.com/ по ссылке: https://singjupost.com/wp-content/uploads/2014/07/Steve-Jobs-iPhone-2007-Presentation-Full-Transcript.pdf

Оставляем только речь Стива:

with open ('apple2007_.txt','r') as file:     presentation_text = file.read() presentation_text = presentation_text.replace('.','').replace(',','').replace(' - ','') presentation_text = presentation_text.lower() print(presentation_text[:211]) this is the day i’ve been looking forward to for two and a half years every once in a while a revolutionary product comes along that changes everything and apple has been – well first of all one’s very fortunate Разбиваем текст на пары рядом стоящих слов: all_p ,all_p2 = get_word_pairs_dic(presentation_text) all_p[:5] ['completely automatically',  'hold on',  'wide screen',  'mail this',  'are calling']

Считаем количество повторений пар слов:

combine_df2 = combine_pairs_count_results(all_p, all_p2,presentation_text) combine_df2[:10].sort_values(by='count', ascending = False)      word_pair  count 1456  going to   68.0 1375   want to   57.0 2436    i want   47.0 2139    this i   44.0 2444    here a   42.0 2942   this is   40.0 3069  here and   39.0 930     in the   38.0 2777    here i   35.0 2473   you can   33.0

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

Подводя итог

Можно сказать, что речь — сильный инструмент, способный убеждать, если вы используете верные слова и честны с аудиторией.

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


ссылка на оригинал статьи https://habr.com/ru/post/708100/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *