Вопрос или проблема
Я работаю над кластеризацией клиентской базы компании, занимающейся бизнесом между организациями. У меня есть данные о клиентах, которые состоят как из числовых (например, количество покупок, средние расходы за покупку), так и из категориальных (например, код отрасли) данных.
Кроме того, у меня есть информация о широте и долготе для каждого клиента, которую я хотел бы включить в кластеризацию. Обычные категориальные и числовые данные можно кластеризовать с помощью, например, PAM / K-Prototypes / Иерархической кластеризации (все методы, где необходимо вычислить матрицу расстояний, так как существуют функции расстояния, которые могут различать оба типа).
Однако я не знаю, как включить значения широты и долготы. Широта и долгота представлены в десятичных градусах, поэтому такие метрики, как евклидово расстояние, не подходят. Некоторые возможные подходы, которые я рассмотрел, включают:
-
вычисление точек x, y, z на поверхности сферы из координат широты / долготы с использованием
$x = \cos(lat) \times cos(lon)$
$y = cos(lat) \times sin(lon)$
$z = sin(lat)$
которые затем можно трактовать как 3 числовых атрибута, используя евклидово расстояние.
-
как-либо реализовать расстояние Хаверсина в вычислении матрицы расстояний. То есть создать функцию расстояния, которая вычисляет числовые разности с использованием евклидового, категориального (после одноразового кодирования) с использованием, например, индекса Жаккара, и диссимилярность по широте и долготе с использованием Хаверсина. Как я могу реализовать что-то подобное? Это возможно или я что-то упускаю?
-
создание регионов, таких как “EMEA” (Европа, Ближний Восток, Африка), “APAC” (Азиатско-Тихоокеанский регион), “NA” (Северная Америка) из значений широты и долготы, что приведет к созданию дополнительных категориальных атрибутов.
Может кто-то прокомментировать, какой подход может быть подходящим?
У меня нет ваших конкретных данных, потому что вы ничего не поделились, но я думаю, что этот общий пример должен быть достаточным.
import statsmodels.api as sm
import numpy as np
import pandas as pd
df = your_df
from numpy import unique
from numpy import where
from sklearn.datasets import make_classification
from sklearn.cluster import KMeans
from matplotlib import pyplot
# определяем датасет
X = df[['lat','lon']]
# определяем модель
model = KMeans(n_clusters=8)
# обучаем модель
model.fit(X)
# присваиваем кластер каждому примеру
yhat = model.predict(X)
X['kmeans']=yhat
pyplot.scatter(X['lat'], X['lon'], c=X['kmeans'], cmap='some_variable', s=50, alpha=0.8)
Ваш конкретный результат, безусловно, будет другим, но в целом вы должны увидеть что-то похожее на это.
Ключевое, на чем стоит сосредоточиться, это:
X = df[['lat','lon']]
Добавляйте больше переменных по мере необходимости и проверяйте результат каждый раз, когда вы вносите изменения. В конечном итоге вам нужно выяснить, что имеет смысл, потому что кластеризация является несупервизированной, поэтому нет метрики R^2 или метрики точности, или какой-либо другой супервизированной метрики.
Вы можете найти больше информации здесь.
Ответ или решение
При работе с кластеризацией клиентской базы B2B-компании, которая включает в себя числовые и категориальные данные, а также координаты (широту и долготу), важно правильно интегрировать все типы данных в процессе кластеризации. Рассмотрим несколько подходов, которые помогут вам решить эту задачу.
Подходы к обработке данных
-
Преобразование широты и долготы в декартовы координаты:
Использование сферических координат — это один из способов, который вы уже упомянули. Применение формул для преобразования широты и долготы в декартовы координаты действительно позволяет использовать евклидово расстояние, изображая точки на сфере как трехмерные координаты. Код для этого может выглядеть следующим образом:import pandas as pd import numpy as np # Функция для преобразования широты и долготы в декартовы координаты def lat_lon_to_cartesian(lat, lon): lat_rad = np.radians(lat) lon_rad = np.radians(lon) x = np.cos(lat_rad) * np.cos(lon_rad) y = np.cos(lat_rad) * np.sin(lon_rad) z = np.sin(lat_rad) return x, y, z # Применение функции к DataFrame df['x'], df['y'], df['z'] = lat_lon_to_cartesian(df['lat'], df['lon'])
После этого вы можете использовать
df[['x', 'y', 'z']]
как числовые атрибуты для кластеризации. -
Использование расстояния Хаверсина:
Расстояние Хаверсина — это отличный способ измерить расстояние между точками на поверхности Земли. Вы можете создать пользовательскую функцию расстояния, которая будет использовать это расстояние для расчета различий. Чтобы интегрировать это с другими метриками (числовыми и категориальными), вы можете объединить результаты в единую матрицу расстояний:from scipy.spatial.distance import pdist, squareform # Функция расстояния Хаверсина def haversine_distance(row1, row2): # Извлечение координат lat1, lon1 = row1['lat'], row1['lon'] lat2, lon2 = row2['lat'], row2['lon'] # Расчет расстояния dlat = np.radians(lat2 - lat1) dlon = np.radians(lon2 - lon1) a = np.sin(dlat/2)**2 + np.cos(np.radians(lat1)) * np.cos(np.radians(lat2)) * np.sin(dlon/2)**2 c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1-a)) r = 6371 # Радиус Земли в км return r * c # Применение функции для вычисления матрицы расстояний distance_matrix = pdist(df[['lat', 'lon']], metric=haversine_distance)
-
Создание регионов:
Как вы упомянули, можно создавать регионы на основе широты и долготы, что позволит использовать их в качестве категориальных атрибутов. Это может быть особенно полезно в случаях, когда важна географическая классификация клиентов.def categorize_region(lat, lon): if (lat >= -36) & (lat <= 72) and (lon >= -25) & (lon <= 180): return "EMEA" elif (lat >= -10) & (lat <= 50) and (lon >= 60) & (lon <= 180): return "APAC" else: return "NA" df['region'] = df.apply(lambda x: categorize_region(x['lat'], x['lon']), axis=1)
Кластеризация с использованием всех данных
После обработки данных, созданием нового числового представления для широты и долготы и добавления категориальных атрибутов вы можете применить метод кластеризации, такой как K-means или другие алгоритмы, поддерживающие смешанные типы данных, например, K-Prototypes.
from kmodes.kprototypes import KPrototypes
# Подготовка данных для кластеризации
X = df[['number_purchases', 'avg_spend', 'region', 'x', 'y', 'z']]
# Применение метода K-Prototypes
kproto = KPrototypes(n_clusters=5, init='Cao', n_init=5, verbose=2)
clusters = kproto.fit_predict(X, categorical=[2]) # 2 - индекс категориальной переменной
df['cluster'] = clusters
Заключение
В конечном итоге, выбор подхода зависит от вашей конкретной ситуации и предположений о данных. Возможно, вам придется поэкспериментировать с различными методами и параметрами. Кластеризация — это интуитивный процесс, и важно внимательно изучать результаты после каждой итерации, чтобы убедиться, что кластеризация имеет смысл для вашей бизнес-задачи.