CoderCastrov logo
CoderCastrov
Питон

Оптимизация ATS-часть 2 — Извлечение ключевых слов на основе NLP — Руководство для начинающих

Оптимизация ATS-часть 2 — Извлечение ключевых слов на основе NLP — Руководство для начинающих
просмотров
21 мин чтение
#Питон
Table Of Content

В предыдущей части 1 этой статьи мы получили файл в формате Excel с предложениями о работе с LinkedIn, соответствующими результатам поиска работы, отфильтрованным по:

  • набору тематических ключевых слов
  • geoID и
  • дополнительным критериям фильтрации, предлагаемым текущим интерфейсом поиска вакансий LinkedIn.

Ключевые слова являются наиболее важным фильтром, так как они определяют объем результатов. Если вы ищете работу, требующую знания Python, здесь следует указать ключевое слово "Python" в коде части 1. Если вас интересуют более общие описания работы, например, data scientist или data engineer, вы указываете эти более общие ключевые слова. GeoID дает вам возможность ограничить географическую область результатов поиска, определяемую через GeoID. В настоящее время лучший способ получить GeoID - это выполнить ручной поиск, записать желаемый город/регион/страну в соответствующее поле фильтра в LinkedIn и скопировать и вставить полученный GeoID из URL результата поиска в качестве значения переменной в коде части 1. То же самое работает и для дополнительных фильтров (например, уровня иерархии или юридического статуса искомых вакансий), как описано в части 1.

В любом случае, код из части 1 создает файл, читаемый Excel, с всеми должностями, которые отображаются в результатах вашего поиска. Это уже интересно само по себе. Но так как код может легко возвращать сотни результатов, может быть интересно использовать возможности NLP (обработки естественного языка) для получения краткого обзора. Вот мотивация для этой части 2.

В теории NLP, совокупность результатов называется "корпусом", отдельные результаты - "документами". Отдельный документ, в нашем случае, представляет собой описание работы, которое мы извлекли для конкретного предложения о работе из списка результатов поиска. И сумма описаний работы составляет корпус. Если вы читали часть 1, вы помните, что мы извлекли более структурированные данные из результатов (например, прямую ссылку, местоположение, размер компании, отрасль и т. д.) - но для следующей аналитической части только (очень длинное) текстовое описание работы для каждого отдельного предложения о работе, возвращенного в результате поиска, является релевантным. Реальная цель наших усилий - получить представление о том, что эти предложения о работе имеют общего. Это может иметь разные мотивации. Это может помочь оптимизировать резюме, такие как "отметить все правильные пункты" и пройти отбор резюме целевой компании или агентства по подбору персонала через ATS (вид автоматизированного процесса отбора резюме). Или это может служить для получения обзора тенденций и тенденций в интересующей вас области. Или вы можете изучить, чем занимаются компании, сопоставимые с вашей (так называемые конкуренты), идентифицируя навыки, которые они набирают.

После некоторого исследования я выбрал 3 способа извлечения этой желаемой информации из корпуса. Эта методология обычно называется "извлечение темы". Можно представить извлечение темы как процесс извлечения ключевых слов, которые наилучшим образом описывают суть конкретных документов в корпусе. Если алгоритм извлечения темы выводит список ключевых слов, таких как [NASA, booster, space, astronaut], легко можно сделать вывод из этого списка, что документ, скорее всего, будет касаться космических путешествий. Или если вы думаете о коллекции рецептов, как для вегетарианцев, так и для любителей барбекю, список с результатами [lettuce, peppers, onions, olive oil] скорее всего относится к вегетарианскому рецепту, список результатов [T-Bone, medium, smoker] скорее относится к рецепту барбекю.

Или, другими словами, алгоритмы извлечения темы НЕ производят готовые темы в качестве результата. Они представляют пользователю список слов, и "человек в процессе" все равно должен сделать вывод о истинном значении этих "значимых терминов", то есть слов, которые выделяются как особенно информативные о значении документа, из которого они взяты.

3 разных подхода, которые я выбрал для дальнейшего изучения результатов парсинга, были:

  • Облако слов
  • Анализ латентного размещения Дирихле (LDA)
  • Извлечение темы BERTopic

Облако слов

Это самое простое для объяснения - и вы, скорее всего, уже видели несколько облаков слов. Это очень визуальный подход: облако слов представляет собой своего рода пэчворк из слов, которые встречаются в корпусе. У них нет определенного порядка - но обычно их написание может быть ориентировано горизонтально или вертикально (что отличает облако слов от "обычного" текста). Самое главное, размер слов меняется в соответствии с частотой встречаемости слова в корпусе. Иначе говоря, чем чаще слово встречается, тем больше оно будет напечатано.

Облако слов из постов jop scraping:

Облако слов - это мощное средство для первоначальной оценки. Оно легко создается и визуально выразительно (например, после просмотра облака слов вам не нужно дополнительное объяснение того, что означает "выдающийся термин"....). Очевидным недостатком облака слов является то, что он работает на всем корпусе, не показывая различий между документами или группами документов. Возьмем предыдущий пример смешанной коллекции рецептов вегетарианской и барбекю: слова "салат" и "т-бон" появятся рядом в облаке слов - и нельзя сказать, что они принадлежат двум разным классам / темам документов. Еще один недостаток: важное понятие в обработке естественного языка (Natural Language Processing, NLP) - это "список стоп-слов": многие старые подходы в NLP работают с чистой статистикой, применяемой к "мешку слов". Можно представить "мешок слов" как список всех слов в документе с указанием количества вхождений слова рядом с ними. Это число может использоваться, например, для определения размера слова в облаке слов (чем чаще слово встречается, тем больше оно будет напечатано). Есть, конечно, очень частые "стоп-слова", которые встречаются намного чаще других. Они обеспечивают структурную основу человеческого языка.... но мало что передают в истинном смысле. Статьи, такие как "the" и "a", или слова, такие как "и" или "или", являются лучшими и наиболее очевидными примерами. Это слова, которые вы хотите исключить из своего "мешка слов" перед любым анализом - или из визуализации, такой как облако слов. Они только затушевывают истинный смысл своим шумом - поэтому вы хотите устранить этот шум. И вы делаете это, используя списки стоп-слов. И чтобы получить информативное облако слов, вам часто приходится вручную настраивать и расширять предварительно настроенные списки стоп-слов. В нашем случае, в противном случае потенциально информативные слова, такие как "компания" или "позиция", очень вероятно, будут появляться в каждом описании работы - поэтому в этом конкретном случае хорошая идея добавить их в список стоп-слов, даже если они не принадлежат к стандартному списку стоп-слов на любом языке. Или, чтобы сделать длинную историю короткой: настройка списка стоп-слов для получения действительно информативного облака слов может занять много времени.... и значительно увеличить используемый список стоп-слов.

Латентное размещение Дирихле

LDA-анализ - это статистический метод моделирования тем. Чтобы процитировать связанную статью Википедии: "Латентное размещение** Дирихле** (LDA) - это генеративная статистическая модель, которая объясняет набор наблюдений через ненаблюдаемые группы, и каждая группа объясняет, почему некоторые части данных похожи."

Звучит и сложно, и увлекательно! И это не только работает, но и есть пакет Python для применения этого метода к стандартным таблицам данных и визуализации результатов (gensim в сочетании с pyLDAvis).

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

Однако был еще один очень интересный аспект для меня: благодаря чтению о LDA, я случайно обнаружил много интересных исторических деталей о своем регионе. Подробнее об этом в разделе "Результаты и находки" - ведь это была чистая счастливая случайность.


BERTopic

Трансформерные модели в настоящее время находятся на пике популярности. После первых потрясающих моделей, основанных исключительно на тексте, трансформеры, преобразующие текст в изображения, такие как Dall-E или StableDiffusion, в настоящее время украдывают шоу. Но чистые языковые модели проложили путь - и BERT (Bidirectional Encoder Representations from Transformers) был одной из первых моделей этого нового поколения языковых моделей. BERT был несколько затменен более новыми моделями, такими как GPT-2 и GPT-3. Но он является открытым исходным кодом и дает очень хорошие результаты при применении к задачам, таким как извлечение тем, при этом оставаясь управляемым в терминах размера модели (более крупные модели трансформеров стали настолько большими, что, кажется, их трудно интегрировать в пакеты с открытым исходным кодом). И один единственный преданный энтузиаст извлечения тем, Мартен Гротендорст, обученный психолог, превратившийся в специалиста по обработке данных, объединил модель BERT в пакет Python, специально разработанный для извлечения тем: BERTopic - и сообщество NLP должно ему многое за это. Мое несовершенное понимание моделей трансформеров: слова документа "преобразуются" в векторы. В каждом отдельном документе слова могут быть связаны или ассоциированы разными способами - и модель трансформера обучается на БОЛЬШОМ количестве документов и включает в себя то, как конкретные слова (также известные как векторы) "нормально" связаны с другими словами (также известными как другие векторы), а также если конкретные слова похожи друг на друга. Часто приводится пример с "королем" и "королевой": оба тенденциозно появляются в одних и тех же текстах и связаны с одними и теми же предметами и, следовательно, словами.... потому что они по сути одно и то же, только одно обозначает мужского, а другое - женского правителя. И модель трансформера может "увидеть" эту схожесть (или близость), сравнивая векторное представление "короля" и "королевы" и находя, что оба необычно "близки" друг к другу. Если вы хотите узнать больше подробностей об этом, термины, которые следует искать, - это "мера расстояния" и "косинусная схожесть" - но эти детали выходят за рамки этой статьи. Что важно для этой статьи:

  • модели трансформеров лучше подходят для семантики, чем подходы "мешка слов". Потому что они включают в себя отношения между словами, а не только их подсчет. И извлечение тем сводится к семантике в конце концов.
  • BERTopic - это пакет с открытым исходным кодом от Мартена Гротендорста, который использует мощь модели BERT для задачи извлечения тем и сочетает ее с простотой Python

The Code

Сначала предупреждение: вы можете получить доступ к коду из этой статьи из двух блокнотов Jupyter, хранящихся на GitHub. Подробности приведены ниже в разделе "Источники". Однако эти блокноты неактивны - и, следовательно, они НЕ показывают визуальный результат. Вам нужно установить и запустить блокнот(ы), чтобы воспроизвести графический вывод как анализ LDA, так и BERTopic. В промежутке времени, скриншоты должны быть достаточными для первого впечатления.

Второе предупреждение: отступы, так важные в Python, каким-то образом НЕ правильно отображаются в Medium. Пробелы должны быть там... но визуальное воздействие в терминах отступа, мягко говоря, ограничено. Пожалуйста, обратите внимание на правильные отступы при копировании кода, включая циклы, условные операторы if/then/else или что-либо еще, требующее правильных отступов для правильной работы.

Облако слов и анализ LDA будут выполнены в одном блокноте. Второй блокнот выполняет извлечение BERTopic. Оба блокнота сначала выполняют типичную обработку данных NLP, то есть "очищают" текст из исходных описаний вакансий с помощью стандартных шагов перед анализом NLP:

  • Токенизация (также известная как "вырезание" слов из текста)
  • Лемматизация (также известная как "сокращение" окончаний слов для "сжатия" слов и уменьшения количества очень похожих вариаций)
  • Очистка "странных" символов
  • Удаление упомянутых стоп-слов

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

Облако слов

1) Импорт пакетов

Стандартные пакеты

import pandas as pd import time import random as rdm import matplotlib.pyplot as plt import numpy as np import string

Пакеты для визуализации

import matplotlib.pyplot as plt %matplotlib inline # для отображения визуализации непосредственно в блокноте import seaborn as sbn

Пакет WordCloud!

import wordcloud from wordcloud import WordCloud

Natural Language Toolkit для обработки текстовых данных

import nltk from nltk.corpus import stopwords from nltk.tokenize import word_tokenize from nltk.stem.wordnet import WordNetLemmatizer from nltk.tokenize import RegexpTokenizer

Необходимые пакеты для анализа LDA

import gensim 
from gensim import corpora 
import pyLDAvis 
import pyLDAvis.gensim_models as gensimvis 
import pyLDAvis 
import pyLDAvis.gensim_models

Загрузка данных, необходимых для работы с NLP-пакетами: нужно выполнить один раз и периодически повторять

# nltk.download('stopwords')
# nltk.download('punkt')
# nltk.download("wordnet")
# nltk.download('omw-1.4')

2) Объявление переменных (глобальных)

s_separator = " " # определение разделителя, который будет использоваться при необходимости для манипуляции с текстом: специальные символы, которые нужно заменить, и их замена
s_2b_replaced = [',', ';', '.', '!', '&', ':', '?', '-', '(', ')']
s_replacement = " "
# Название основного столбца фрейма данных, который будет анализироваться:
c_category = 'JobDescDetails'

3) Определения функций

Функция "cleaner": очищает строку от символов, не относящихся к ASCII

def f_clean_txt_characters(d):
    for elem in s_2b_replaced: # см. определение переменной s_2b_replaced в разделе объявления переменных
        if elem in d: # Заменить любой
            d = d.replace(elem, s_replacement)
    return d

Преобразование текста в список отдельных слов БЕЗ стоп-слов

def f_stopword_filter(d):
    t = word_tokenize(d) # токенизация документа - преобразование из строки в список
    t = [w for w in t if not w.lower() in stop_words] # фактическое удаление стоп-слов
    return t

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

def f_filtered_txt_strg(l):
    s = ' '
    for n in l:
        s = s + n.lower() + ' '
    return s # возвращает строку отфильтрованного текста вместо списка

Лемматизировать слова во входном списке

def f_lematize(l):
    lematized = ' '.join(lemma.lemmatize(word) for word in l.split())
    return lematized

4) Фактическая программа

4a) Импорт данных

Чтение файла IMPORT > результат скрапинга LinkedIn с помощью Selenium. Не забудьте изменить код, если файл и лист с результатами названы по-другому.

xlsx_imp = pd.ExcelFile('LinkedIn_Input.xlsx')
df_imp = pd.read_excel(xlsx_imp, 'Sheet1')

4b) Обработка данных

Извлечение только необходимого столбца ИЗ ИМПОРТА для дальнейшей подготовки/обработки данных.

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

for k in range(len(df_w1)):
    if type(df_w1.loc[k, c_category]) != str:
        print(k)

Очистка текста: удаление пунктуации, большинства специальных символов и "экзотического" текста в кодировке utf-8. Дальнейшая очистка текста: удаление всех символов, не являющихся частью стандартного набора ASCII. Это, например, должно устранить китайский текст.

df_w2 = df_w1.copy()
df_w2[c_category] = df_w2[c_category].apply(f_clean_txt_characters)

Удаление стоп-слов и токенизация текста: Поскольку результаты конкретного поиска содержат описания вакансий на английском, нидерландском и немецком языках, все эти языки должны быть учтены в списке стоп-слов.

stop_words = list(set(stopwords.words('english')) | set(stopwords.words('german')) | set(stopwords.words('dutch')))

#######################################################

добавить больше стоп-слов для исключения часто встречающихся общих слов

-> настроить этот список, чтобы исключить неинформативные слова

как из облака слов, так и из анализа LDA.

Эта настройка сильно зависит от области поиска

и языка(ов), присутствующего в корпусе

####################################################### l_thematic_stop_words = [‘финансы’,’финансовый’,’бизнес’,’финансовые’,’ты’,’будешь’,’наш’,’твой’,’опыт’,’внутри’,’мы’,’опыт’,’должность’,’работать’, ‘работа’,’идти’,’просмотреть’,’биржа’,’получить’,’узнать’,’больше’,’объявление’,’получить’,’искать’,’детали_вакансии’,’команда’,’контролер’,’управление’,’организация’,’иметь’,’контроль’,’знания’,’навыки’,’менеджер’,’компания’,’год’,’работающий’,’ты’,’в’,’контакт’,’проблема’,’диплом’,’брутто’,’возможный’,’проекты’,’развивать’,’новый’,’хороший’,’организация’,’вопросы’, ‘минимальный’,’коллега’, ‘кроме’, ‘включая’, ‘а также’, ‘компания’, ‘процесс’, ‘процессы’, ‘предлагать’, ‘предлагать’, ‘предприятие’, ‘хорошо’, ‘хороший’, ‘хороший’, ‘хороший’,’хорошо’,’внутри’, ‘где’, ‘дальше’, ‘разные’, ‘с удовольствием’, ‘вместе’, ‘процессы’,’при которых’, ‘искать’, ‘роль’, ‘роль’, ‘роль’, ‘сильный’, ‘требуемый’] stop_words.extend(l_thematic_stop_words)

Улучшить таблицу с текстом для облака слов БЕЗ каких-либо слов из списка стоп-слов:

df_w2[‘DOC_LIST4WC’] = df_w2[c_category].apply(f_stopword_filter) # выполнить исключение стоп-слов в столбце df

Возвращаясь от токенизированного списка к одной строке….

df_w2[‘DOC_TEXT4WC’] = df_w2[‘DOC_LIST4WC’].apply(f_filtered_txt_strg) # преобразовать из списка в строку

Этот код служит только для сравнения влияния предыдущего кода на 50-й результат поиска в качестве примера: он печатает текст 50-го описания работы ПЕРЕД обработкой текста (т.е. так, как он был спарсен) с текстом после применения всех манипуляций NLP для облака слов.


4c) Создание облака слов

all_words = ‘ ‘.join([str(text) for text in df_w2[‘DOC_TEXT4WC’]]) wordcloud = WordCloud(width=800, height=500, random_state=21, max_font_size=110).generate(all_words) plt.figure(figsize=(18, 12)) plt.imshow(wordcloud, interpolation=”bilinear”) plt.axis(‘off’) plt.show()

Эта последняя строка создает облако слов, показанное выше в этом тексте. Конечно, вы можете настроить и поиграть с параметрами пакета для создания облака слов.

LDA-анализ

Этот код продолжается просто после создания облака слов.

4d) Подготовка данных для LDA-анализа

Подготовьте данные для анализа: v_num_topics - это важный параметр: как и в методе k-средних, пользователь должен заранее определить количество тем. Пользователю предоставляется возможность повторять и экспериментировать, чтобы найти подходящее количество тем.

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

l_docs = df_w2[‘DOC_TEXT4WC’].tolist() lemma = WordNetLemmatizer() l_doc_lem = [f_lematize(doc).split() for doc in l_docs] corpus = corpora.Dictionary(l_doc_lem) # создание объекта словаря корпуса mat_doc_term = [corpus.doc2bow(doc) for doc in l_doc_lem] # генерация матрицы документ-термин !!

4e) Обучение модели LDA и вывод результатов

Фактическое обучение модели LDA с ранее сгенерированной матрицей документ-термин

Вывод текстового результата модели

print("Модель LDA на основе матрицы документ-термин - Перплексия: -", mod_LDA_DocTermMatr.log_perplexity(mat_doc_term))

Вывод визуального результата модели (интерактивный):

vis_DocTermMatr = gensimvis.prepare(mod_LDA_DocTermMatr, mat_doc_term, corpus)

Результат должен выглядеть примерно так:

BERTopic

Это совершенно новый ноутбук, поэтому он начинается с импорта пакетов снова

1) Импорт пакетов

Импорт необходимых пакетов для работы кода

import re as re import time import pandas as pd import random import nltk from nltk.corpus import stopwords from nltk.tokenize import word_tokenize from nltk.tokenize import RegexpTokenizer from sklearn.feature_extraction.text import CountVectorizer from bertopic import BERTopic

Здесь нет объявлений переменных или определений функций. Поэтому мы сразу переходим к

4) Фактическая программа

4a) Импорт данных

df_imp = pd.read_excel (r’LinkedIn_Input.xlsx’, sheet_name=’Sheet1′) docs = df_imp[‘JobDescDetails’].tolist()

4b) Подготовка данных / обработка

Та же логика, что и для облака слов и анализа LDA, применяется к расширению списка стоп-слов для извлечения тем с помощью BERTopic.

stop_words = list(set(stopwords.words('english')) |set(stopwords.words('german')) |set(stopwords.words('dutch')) ) additional_stop_words = ['finance', 'financial','business','financiële','jij','bent','onze','jouw','experience','binnen','wij','ervaring','functie','werken', 'work','ga','elk','kijken','stellenbörse','stammt','erfahren','mehr','anzeige','stammt','looking','jobdescdetails','team','controller','management','organisatie','hebt','control', 'kennis','skills','manager','company','jaar', 'working', 'jou', 'per', 'contact' ,'probleem', 'diploma', 'bruto', 'mogelijk','projecten','ontwikkelen','nieuwe','goede','organisatie','vragen', 'minimaal','collega', 'daarnaast', 'including', 'sowie', 'bedrijf', 'process', 'processes', 'bieden', 'bieten', 'unternehmen','gut', 'gute', 'guter', 'goede','goed','within', 'waar', 'verder', 'verschillende', 'graag', 'samen', 'processen','waarbij', 'zoek', 'role', 'rolle', 'rol', 'strong', 'required']

EXTEND вместо APPEND, так как добавляется весь список, а не один отдельный элемент !!! Плюс: работает IN_PLACE по умолчанию

stop_words.extend(additional_stop_words)

Удаление всех стоп-слов из списка документов

docs_without_stopwords =[] tokenizer = RegexpTokenizer("[w']+") for d in range(0, len(docs)): doc_token = tokenizer.tokenize(docs[d]) str_no_stopwords = " for w in range(0, len(doc_token)): if doc_token[w].lower() not in stop_words: str_no_stopwords = str_no_stopwords + doc_token[w].lower() + " " else: pass docs_without_stopwords.append(str_no_stopwords)

4c) Игра с запуском фактического извлечения BERTopic

Определение и обучение фактической модели (с важными параметрами для экспериментов, такими как ngram_range или nr_topics)

Получение основной информации о модели

topic_model.get_topic_info() topic_model.get_topic(-1) topic_model.visualize_hierarchy() topic_model.visualize_barchart()

Пример: поиск всех тем, связанных с заданным поисковым термином:

similar_topics, similarity = topic_model.find_topics(“обучение”, top_n=5)

Получение наиболее релевантной темы, содержащей поисковый термин

for topic in range(0, len(similar_topics)): print(“Тема №”+str(topic)) for keyword in topic_model.get_topic(similar_topics[topic]): print(keyword)

Вывод извлеченных тем и связанных ключевых слов и проверка, не включены ли случайно найденные темы в список стоп-слов:

for topic in range(0, len(similar_topics)): print(“Тема №”+str(topic)) for keyword, probability in topic_model.get_topic(similar_topics[topic]): if keyword in stop_words: print(keyword+” -> ОШИБКА: слово темы является стоп-словом!” ) else: print(keyword)

Облако слов

Легко делать! Облако слов - хороший пример применения методологии KISS: просто и глупо! Это отличный инструмент для рассказывания и коммуникации. Особенно его интуитивно понятно для людей, которые являются экспертами в своей области, но не являются специалистами по обработке данных.

Есть два больших замечания при его применении: 1) Качество зависит от списка стоп-слов. И расширение списка стоп-слов вручную также создает возможность умышленного манипулирования. 2) Моделируется только весь корпус. Так что вы не видите "темы", как определено выше, а только термины, которые важны для всего корпуса.


LDA

Этот довольно старый метод работал удивительно хорошо. Например, он отлично разделял по языку: многие из собранных описаний вакансий были на английском, некоторые на немецком (и также на голландском в предыдущей версии, пока LinkedIn не перешел к подходу с использованием гео-ID, объясненному в части 1):

Верхний левый квадрант: только английские термины из англоязычных вакансий:

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

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

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

Вы можете вспомнить из части 1, что мой случай использования заключался в поиске тем и тенденций, определяющих текущее и среднесрочное будущее финансовой сферы. Исходя из этого, одним из основных выводов для меня лично (который вытекал как из облака слов, так и из анализа LDA) стало значение термина "business partnering" для финансовых должностей. Хотя "партнерство" должно быть естественным в повседневной работе, я не был осведомлен о том, что это превратилось в своего рода "модное слово года". Не очень важно для моего случая использования, но интересно знать, если вам нужно отметить галочки, чтобы избежать исключения ATS.

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

Позднее я также провел поиск вакансий в области финансов для начинающих, чтобы проверить этот вывод: там технические навыки формулировались более конкретно..... но на обманчиво низком уровне: большую часть времени достаточно было "продвинутых / отличных навыков работы с Excel", иногда требовалось знание SQL. Некоторые вакансии упоминали также навыки работы с BI-инструментами как плюс.

Исходя из этих результатов, у меня теперь есть сомнения в том, насколько большинство финансовых отделов

  • способны не приводить, а просто следовать цифровой трансформации
  • рассматриваются как равноправные партнеры бизнесом, ИТ и отделами данных / ИИ в обсуждении внедрения новых цифровых технологий и процессов

BERTopic

Это короткий текст: я пока не смог использовать BERTopic! Код запустился и выдал результаты, но не очень значимые. Вот почему мне еще нужно потратить время и изучить настройки. Поэтому я не буду приводить скриншот.

Конечно, это не вина BERTopic, а моя: все статьи, которые я прочитал, хвалили этот пакет за его возможности. Так что это хорошая отправная точка для экспериментов в холодные зимние ночи. И кодовая база должна обеспечить надежную отправную точку для этого.

Случайные открытия: Что такое "Дирихле"

Теперь я отклонюсь и полностью отойду от темы: иногда удивительно, как вещи внезапно связаны в пространстве и времени... и как мы об этом узнаем.

Перейдите непосредственно к разделу "Источники", если вас интересует только техническая часть этой статьи и соответствующие блокноты 🙂

У меня был очень неожиданный момент синхронности, когда я узнал о теме анализа LDA, которую я просто хотел поделиться:

Когда я впервые прочитал о LDA, полное название "Латентное размещение Дирихле" запало мне в память как особенно странное. "Латентное" и "размещение" были немного странными, но в какой-то мере понятными. Но что такое "Дирихле"? Я помню, что я действительно задумался на мгновение, что может означать "Дирихле": просто имя (как часто в математике, как, например, с Коши-Шварцем или Эйлером и многими другими...) или, может быть, какое-то странное греческое слово для чего-то, о чем я раньше не слышал. Но в конце концов, у меня было дело получше, и я не искал подробного ответа.

Только через неделю у нас были друзья на ужин. Один из приглашенных друзей - англичанин из самого севера (Ньюкасл). У нас обычно бывают дискуссии по самым разным вопросам. Он немного влюбился в немецкий романтизм (...художественный период, известный под этим названием с начала 19-го века) - и только что узнал, что немецкий композитор этого периода написал несколько симфоний, вдохновленных северными пейзажами Британских островов... и хотел знать, знаю ли я об этом.

Конечно, да, я знал, что Феликс Мендельсон Бартольди написал и "Шотландскую симфонию", и "Гебриды". Феликс кто? вы можете спросить. Ну, вы его знаете... даже если не знаете. Это тот парень, который принес вам СВАДЕБНЫЙ МАРШ. Который на самом деле является Свадебным маршем из его оперы "Сон в летнюю ночь".

В общем: англичанин (...хорошо, теперь "натурализованный немец"; Брексит обязывает...) был удивлен узнать, что Мендельсон-Бартольди также имеет прямое отношение к городу, в котором живем он и я, Дюссельдорфу: он был кантором (то есть ответственным за музыку) в местной церкви несколько лет где-то в начале 1830-х годов. Это вызвало интерес нашего друга, и мы быстро просмотрели биографию Мендельсона в немецкой статье Википедии, так как он хотел узнать больше о жизни Мендельсона.

Что это имеет общего с LDA, вы можете спросить - ну, мои глаза сразу зацепились, в середине статьи, за словом "Дирихле". Совпадение? Опечатка? Но в статье говорилось, что сестра Феликса вышла замуж за математика с такой фамилией: Петр Густав Лежен Дирихле.

Поскольку это был всего второй раз в моей жизни, когда я видел это слово, это теперь вызвало мое любопытство. Тем более, что указание на то, что человек с таким именем был математиком, предполагало связь с этим именем в "LDA". И так оно и было. И какая интересная жизнь:

Он родился в Бельгии до того, как Бельгия стала Бельгией (в 1832 году) - поэтому он фактически был французским гражданином, который переехал с отцом на несколько километров восточнее от региона вокруг Льежа на реке Маас (или Люк на голландском, или Люттих на немецком) в Дюрен (рядом с Аахеном), который принадлежал к Пруссии (и нет, еще нет Германии в то время; и регион был даже некоторое время частью Франции, под Наполеоновским правлением) - и оттуда всего несколько километров до Рейна и Дюссельдорфа, где он встретил свою будущую жену, сестру Феликса Мендельсона-Бартольди.

Мы забываем об этом, но удивительно, насколько открытыми были границы (и умы) до того, как народы Европы заболели национализмом в середине 19-го века. Итак, согласно биографии Википедии, он получил свое "немецкое" имя "Лежен Дирихле", буквально напоминая о нем как "молодом человеке из Дерихлетта" - небольшом сообществе недалеко от Льежа - и продолжил свой путь, став знаменитым математиком в Пруссии. В конце концов, он даже стал преемником Гаусса (да, парня с колоколообразной кривой и, помимо Байеса, крестного отца статистики) на знаменитом математическом факультете университета Геттингена... давая нам теоретическую основу для "Латентного размещения Дирихле" в процессе.

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

Интересный факт, чтобы закончить все это: Мартен Гротендорст, упомянутый создатель пакета BERTopic, является голландцем и из Тилбурга... всего в нескольких километрах и от Льежа, и от Дюссельдорфа. Так что это много теории извлечения темы в небольшом, но культурно разнообразном радиусе (смешивая голландскую, валлонскую и немецкую культуру) всего около 50-60 миль - и за примерно 200 лет: