Ланцюжок логіки: Витягування цінності з даних за допомогою семантичної обробки, методів неспостережуваної кластеризації (та обробки RGB)

Ціль цієї статті — продемонструвати, як комбінація технік може бути використана для отримання цінності з помірних наборів даних. Я представлю вигаданий набір даних і випадок використання та розгляну деякі методи машинного навчання, які можна застосувати для швидкого збагачення даних в осмислений спосіб, що може бути потужним у комерційному світі.

Уявіть, що ви — великий виробник одягу, який шукає способи реалізувати нову стратегію цифрового маркетингу. Ви хочете створити окремі кампанії для різних груп серед ваших клієнтів на основі спільних атрибутів. Простий спосіб досягти цього — це використання детерміністичних методів, таких як визначення правил, які б казали: «показати цю синю спідницю всім клієнтам, які люблять синій», однак ми хочемо піти далі та вирішити, що саме буде найкращим способом на основі більш складних методів. Ось як ми можемо досягти кращих результатів, використовуючи аналіз даних, семантичну обробку, несупервайзерне кластерування та деяку вигадливість із групуванням кольорів.

Оскільки це вигаданий приклад, мій перший крок — використати faker для створення уявних даних з іменами клієнтів та кількома супутніми атрибутами, такими як професія, місто, улюблений колір і титул.

# Імпортуємо всі необхідні бібліотеки
from faker import Faker #для генерації уявних даних

import pandas as pd #для маніпуляції з даними
import numpy as np #для числових операцій

from sentence_transformers import SentenceTransformer #для семантичної обробки тексту BERT
from sklearn.cluster import KMeans #для кластеризації
from sklearn.decomposition import PCA #для зменшення розмірності

import matplotlib.pyplot as plt #для побудови графіків
import webcolors #для перетворення назв кольорів у RGB
# створюємо уявний набір даних за допомогою faker

fake = Faker()

dataset_size = 10000
fake_names_lst = [fake.name() for _ in range(dataset_size)]
fake_color_lst = [fake.color_name() for _ in range(dataset_size)]
fake_job_lst = [fake.job() for _ in range(dataset_size)]
fake_city_lst = [fake.city() for _ in range(dataset_size)]
fake_suffix_lst = [fake.suffix() for _ in range(dataset_size)]

data_struct = {
 'Name' : fake_names_lst,
 'Color': fake_color_lst,
 'Job' : fake_job_lst,
 'City' : fake_city_lst,
 'Suffix' : fake_suffix_lst
}

main_df = pd.DataFrame(data_struct)

pic

Знімок екрана для демонстрації уявних даних, створених бібліотекою Faker

У реальному світі ми часто працюємо з даними високої розмірності. Простими словами, атрибут може мати багато окремих значень. В нашому уявному прикладі ми можемо побачити це в атрибуті «Job» або «Color», де є понад 100 різних значень. Оскільки ми не можемо створити понад 100 різних маркетингових кампаній для відповідних атрибутів, перший крок — розробити метод класифікації для створення кластерів із наявних даних.

pic

Семантична обробка і K-means кластеризація

Один із способів зменшення розмірності нашого набору даних — це аналізувати значення наших атрибутів і групувати їх на основі семантичних концептів. Ми робимо це природно в мові, наприклад, об’єднуючи «CEO» і «CFO» в категорію керівників або «Frontend Engineer» і «QA» як інженерів. Те ж саме можна зробити з даними, створивши числове представлення слів у великих багатовимірних векторах, а потім порівнюючи відстані між ними. Чим ближчі вектори один до одного, тим схожіша семантика слів. Середнє або сума через речення також дозволяє робити те ж саме для більших обсягів тексту.
Процес знаходження числового представлення слова називається вбудовуваннями.

Word2Vec — це модель, що є частиною бібліотеки Gensim, яка дозволяє виконувати ці вбудовування, підтримуючи як натреновані, так і ненатреновані версії. Як несупервайзерна модель кластеризації машинного навчання (ML), Word2Vec може бути натренований виключно на ваших даних (це доцільно, якщо у вас є великий репозиторій текстових даних), де він визначатиме правильне представлення ваших слів у векторному просторі. Для випадків використання, коли ви працюєте з короткими або одиночними реченнями, краще використовувати попередньо натреновану версію, оскільки контекст важливий для ефективного створення точних векторів. Стикавшись із труднощами в ефективному використанні для моїх назв посад, я звернувся до використання BERT від hugging face для генерації вбудовувань. BERT натренований на більшому корпусі і, на відміну від Word2Vec, є багатим вбудовуванням, яке враховує контекст і навколишні слова. Також його набагато легше використовувати, оскільки не потрібні попередні кроки, такі як токенізація чи стандартизація — все це обробляється під капотом.

# Завантажуємо попередньо натреновану модель BERT з Sentence-Transformers
model = SentenceTransformer('all-MiniLM-L6-v2')

# Генеруємо вбудовування BERT для назв посад
job_titles = main_df['Job'].tolist()
embeddings = model.encode(job_titles)

BERT генерує великі вектори, як ми можемо побачити, вектори, які він створив для моїх назв посад, мають довжину 384 (це насправді mini-BERT, який має подібну продуктивність, але є меншим порівняно з оригінальним BERT розміром 768). Фактично, те, що відбувається під капотом, це те, що слова, які ви передаєте BERT, потім шукаються і передаються через шар трансформера (це гарне поглиблене керівництво по BERT)

pic

Тут ми можемо побачити, що посада "Коректор" була перетворена на вектор розміром 384

Щоб підготувати і спростити наші дані для кластеризації, я використовую PCA, техніку зменшення розмірності, яка зменшує шум і фокусується на найважливіших ознаках.

# зменшуємо розмірність для кращої кластеризації
pca = PCA(n_components=50) # Зменшуємо до 50 вимірів
reduced_embeddings = pca.fit_transform(embeddings)

Тепер, коли наші назви посад вбудовані та зменшені до зручних 50 вимірів, ми можемо виконати кластеризацію. Для цього я вибрав K-means через його простоту та зрозумілість. Ця модель машинного навчання обчислює евклідову відстань між векторами, щоб визначити їхні кластери. Як вхідний параметр потрібно подати модель кількість кластерів, які ви хочете, щоб модель вивела. Це не є конкретною наукою, але можна визначити кількість, запустивши скрипт з різними розмірами кластерів і візуалізуючи результат, перевіряючи, чи задоволені ви згуртованістю груп. Як альтернатива можна використовувати метод ліктя або метод силуета для допомоги в цьому.
У моєму випадку я вибрав 8, оскільки мене задовольняє групування на цьому рівні, і це відповідає моєму теоретичному випадку використання, де команда цифрового маркетингу не хоче створювати більше 8 окремих кампаній.

# KMeans кластеризація  
kmeans = KMeans(n_clusters=8, random_state=42)   
main_df['Cluster'] = kmeans.fit_predict(reduced_embeddings)  

# PCA для візуалізації  
pca_2d = PCA(n_components=2)  
embeddings_2d = pca_2d.fit_transform(reduced_embeddings)  

# побудова графіку для кластерів  
plt.figure(figsize=(10, 8))  
plt.scatter(embeddings_2d[:, 0], embeddings_2d[:, 1], c=main_df['Cluster'], cmap='viridis')  
plt.title('2D візуалізація кластерів назв посад')  
plt.xlabel('PCA Компонент 1')  
plt.ylabel('PCA Компонент 2')  
plt.colorbar()  
plt.show()  

# перевірка кластерів  
for i in range(8):   
 print(f"Кластер {i}:")  
 print(main_df[main_df['Cluster'] == i]['Job'].tolist())  
 print()

pic

Кластери вбудовувань назв посад, використовуючи BERT від Hugging Face та K-Means

Порівнюючи когорти, результат досить вдалий, наприклад, Когорта 0: [‘Менеджер з виробництва’, ‘Сертифікований керуючий бухгалтер’, ‘Менеджер з обслуговування клієнтів’, ‘Менеджер розважального центру’, ‘Менеджер архіву’, ‘Менеджер конференц-центру’, ‘Менеджер тематичного парку’…], тоді як Когорта 2: [‘Вчитель початкової школи’, ‘Адміністратор освіти’, ‘Офіцер з підготовки та освіти в збройних силах’, ‘Лектор вищої освіти’, ‘Старша медсестра’, ‘Міжнародний працівник з надання допомоги/розвитку’ …]. Не погано! Тепер набір даних був розширений автоматичними когортами, визначеними за допомогою семантичної обробки та методів несупервайзерного навчання. Замість 639 окремих значень у моєму стовпці "Посада", я зібрав їх у 8 груп; набагато зручніше.

Виявилося, що складно працювати з кольорами

Використовуючи Faker, я зміг швидко створити умовні дані про кольори, які в моєму прикладі сьогодні я інтерпретую як улюблений колір умовних осіб у моєму наборі даних. Коли я це робив, я припустив, що зможу застосувати ту ж саму логіку, що й вище, до мого стовпця «Колір». Я помилився. Це призвело до погано згенерованих вбудовувань як з Word2Vec, так і з FastText та BERT, і навіть ще більш шокуючих кластерів. Причина цього в тому, що кольори є більш конкретними, ніж концептуальними, і попередньо натреновані моделі, такі як BERT, не мають контексту щодо кольорів. Тому, незважаючи на те, що створення атрибуту кольору зайняло кілька секунд, я створив проблему, намагаючись з’ясувати, який найкращий спосіб просто кластеризувати кольори без надмірних ручних зусиль. Це чудова демонстрація того, як важливо вибирати, які методи використовувати, і як один розмір не підходить для всіх.

Чудова річ у кольорах полягає в тому, що ми вже маємо певні вбудовування для них у вигляді RGB.
Щоб вирішити нашу проблему з кольорами, я просто взяв стовпець «Color» і використав бібліотеку для відображення рядкових значень кольорів на представлення в RGB.

# Перетворення назв кольорів у значення RGB  
def name_to_rgb(color_name):  
 try:  
 # Перетворення назви кольору в RGB  
 return np.array(webcolors.name_to_rgb(color_name)) / 255.0 # Нормалізація значень RGB в діапазон [0, 1]  
 except ValueError:  
 return np.array([0, 0, 0]) # За замовчуванням чорний, якщо назва кольору некоректна  

# Застосування функції RGB   
main_df['rgb'] = main_df['Color'].apply(name_to_rgb)

pic

Набір даних, збагачений стовпцем Cluster та представленням кольору в RGB

Тепер, коли ми маємо представлення RGB для кожного кольору в нашому наборі даних, ми можемо просто вручну визначити кластери для наших кольорів, використовуючи просту логіку, яким кольором є найдомінуючий, зменшуючи їх з 140 унікальних значень до 3.

# Функція для класифікації домінуючого кольору в RGB  
def classify_dominant_color(rgb):  
 red, green, blue = rgb  
 if red >= green and red >= blue:  
 return 'Red'  
 elif green >= red and green >= blue:  
 return 'Green'  
 elif blue >= red and blue >= green:  
 return 'Blue'  

# Застосування функції до стовпця  
main_df['Color'] = main_df['rgb'].apply(classify_dominant_color)

Об'єднавши інформацію з кластеризації та обробки RGB, можна провести подальший аналіз, щоб зрозуміти сегментацію в кластерах та які атрибути має кожна когорта. Висновок: вищеописана логічна ланцюжок демонструє, як різні методи можна використовувати послідовно для збагачення даних та створення вартості для бізнесу, роблячи їх більш зручними для використання та допомагаючи у формуванні бізнес-стратегії, такій як створення стратегії цифрового маркетингу.

Перекладено з: Chain of Logic: Extracting value from data through the use of semantic processing, unsupervised clustering methods (& RGB processing)

Leave a Reply

Your email address will not be published. Required fields are marked *