Кластеризация широты, долготы вместе с числовыми и категориальными данными

Вопрос или проблема

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

Кроме того, у меня есть информация о широте и долготе для каждого клиента, которую я хотел бы включить в кластеризацию. Обычные категориальные и числовые данные можно кластеризовать с помощью, например, 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 или метрики точности, или какой-либо другой супервизированной метрики.

Вы можете найти больше информации здесь.

https://github.com/ASH-WICUS/Notebooks/blob/master/Clustering%20-%20Historical%20Stock%20Prices.ipynb

https://github.com/ASH-WICUS/Notebooks/blob/master/Haversine%20Distance%20-%20Airport%20or%20Not.ipynb

Ответ или решение

При работе с кластеризацией клиентской базы B2B-компании, которая включает в себя числовые и категориальные данные, а также координаты (широту и долготу), важно правильно интегрировать все типы данных в процессе кластеризации. Рассмотрим несколько подходов, которые помогут вам решить эту задачу.

Подходы к обработке данных

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

    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']] как числовые атрибуты для кластеризации.

  2. Использование расстояния Хаверсина:
    Расстояние Хаверсина — это отличный способ измерить расстояние между точками на поверхности Земли. Вы можете создать пользовательскую функцию расстояния, которая будет использовать это расстояние для расчета различий. Чтобы интегрировать это с другими метриками (числовыми и категориальными), вы можете объединить результаты в единую матрицу расстояний:

    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)
  3. Создание регионов:
    Как вы упомянули, можно создавать регионы на основе широты и долготы, что позволит использовать их в качестве категориальных атрибутов. Это может быть особенно полезно в случаях, когда важна географическая классификация клиентов.

    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

Заключение

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

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

Капча загружается...