SOM кластеризация для номинальных / циклических переменных


11

Просто интересно, знаком ли кто-нибудь с кластеризацией номинальных входов. Я рассматривал SOM как решение, но, видимо, оно работает только с числовыми функциями. Есть ли расширения для категориальных функций? В частности, мне было интересно узнать о «Днях недели» как о возможностях. Конечно, его можно преобразовать в числовую характеристику (т. Е. Пн-Вс, что соответствует номерам 1-7), однако тогда евклидово расстояние между Солнцем и Пн (1 и 7) не будет таким же, как расстояние от Пн до Вт (1 и 2). ). Любые предложения или идеи будут высоко ценится.


(+1) очень интересный вопрос
Штеффен

2
Циклические переменные лучше всего рассматривать как элементы единичного круга в комплексной плоскости. Таким образом, было бы естественно сопоставить дни недели с (скажем) точками , j = 0 , , 6 ; т.е. , ( соз ( 0 ) , грех ( 0 ) ) , ( соз ( 2 π / 7 ) , грех ( 2 π / 7exp(2jπi/7)j=0,,6(cos(0),sin(0)) , ... ( cos ( 12 π / 7 ) , sin ( 12 π / 7 ) ) . (cos(2π/7),sin(2π/7))(cos(12π/7),sin(12π/7))
whuber

1
я должен был бы кодировать мою собственную матрицу расстояния тогда определенную для циклических переменных? просто интересно, были ли уже существующие алгоритмы для этого типа кластеризации. THX
Майкл

@Michael: Я полагаю, что вы захотите указать свою собственную метрику расстояния, которая подходит для вашего приложения и которая определяется для всех измерений в ваших данных, а не только для DOW. Формально, позволяя x, y обозначать точки в вашем пространстве данных, вам нужно определить метрическую функцию d (x, y) с обычными свойствами: d (x, x) = 0, d (x, y) = d (y , x) и d (x, z) <= d (x, y) + d (y, z). Как только вы это сделаете, создание SOM будет механическим. Творческая задача состоит в том, чтобы определить d () таким образом, чтобы охватить понятие «сходство», подходящее для вашего приложения.
Артур Смолл

Ответы:


7

Фон:

Самый логичный способ преобразования часа - это две переменные, которые качаются взад и вперед несинхронно. Представьте себе положение конца часовой стрелки на 24-часовых часах. В xколебании позиции вперед и назад из синхронизации с yпозицией. Для 24-часовой вы можете сделать это с x=sin(2pi*hour/24), y=cos(2pi*hour/24).

Вам нужны обе переменные или правильное движение во времени потеряно. Это связано с тем, что производная от sin или cos изменяется во времени, в то время как (x,y)положение изменяется плавно по мере того, как оно перемещается по окружности.

Наконец, подумайте, стоит ли добавлять третью функцию для отслеживания линейного времени, которая может быть построена в виде часов (или минут или секунд) от начала первой записи или метки времени Unix или чего-то подобного. Эти три функции затем обеспечивают прокси как для циклической, так и для линейной прогрессии времени, например, вы можете вытянуть циклические явления, такие как циклы сна в движении людей, а также линейный рост, такой как численность и время.

Пример выполнения:

# Enable inline plotting
%matplotlib inline

#Import everything I need...

import numpy as np
import matplotlib as mp

import matplotlib.pyplot as plt
import pandas as pd

# Grab some random times from here: https://www.random.org/clock-times/
# put them into a csv.
from pandas import DataFrame, read_csv
df = read_csv('/Users/angus/Machine_Learning/ipython_notebooks/times.csv',delimiter=':')
df['hourfloat']=df.hour+df.minute/60.0
df['x']=np.sin(2.*np.pi*df.hourfloat/24.)
df['y']=np.cos(2.*np.pi*df.hourfloat/24.)

df

введите описание изображения здесь

def kmeansshow(k,X):

    from sklearn import cluster
    from matplotlib import pyplot
    import numpy as np

    kmeans = cluster.KMeans(n_clusters=k)
    kmeans.fit(X)

    labels = kmeans.labels_
    centroids = kmeans.cluster_centers_
    #print centroids

    for i in range(k):
        # select only data observations with cluster label == i
        ds = X[np.where(labels==i)]
        # plot the data observations
        pyplot.plot(ds[:,0],ds[:,1],'o')
        # plot the centroids
        lines = pyplot.plot(centroids[i,0],centroids[i,1],'kx')
        # make the centroid x's bigger
        pyplot.setp(lines,ms=15.0)
        pyplot.setp(lines,mew=2.0)
    pyplot.show()
    return centroids

Теперь давайте попробуем это:

kmeansshow(6,df[['x', 'y']].values)

введите описание изображения здесь

Вы едва можете видеть, что есть некоторые после полуночи, включенные в зеленый кластер до полуночи. Теперь давайте уменьшим количество кластеров и покажем, что до и после полуночи можно более подробно подключиться к одному кластеру:

kmeansshow(3,df[['x', 'y']].values)

введите описание изображения здесь

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

Вы можете сделать это для времени, или дня недели, или недели месяца, или дня месяца, или сезона, или чего-либо еще.


Полезно (+1). Это одно из приложений, где графические квадраты, а не продолговатые, действительно важны. Я не знаю вашего программного обеспечения, но я полагаю, вы можете установить соотношение сторон на 1, отличное от значения по умолчанию.
Ник Кокс

Это правда @NickCox. Или вы можете просто выполнить линейное преобразование в своей голове ;-)
user1745038

2

Обычно номинальные переменные фиктивно кодируются при использовании в SOM (например, одна переменная для с 1 для понедельника 0 для не понедельника, другая для вторника и т. Д.).

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


2

Для номинальных переменных типичное кодирование в контексте нейронной сети или электротехники называется «горячим» - вектор со всеми 0, с одним в соответствующем положении для значения для переменной. Например, для дней недели есть семь дней, поэтому ваши горячие векторы будут иметь длину семь. Тогда понедельник будет представлен как [1 0 0 0 0 0 0], вторник как [0 1 0 0 0 0 0] и т. Д.

Как намекнул Тим, этот подход можно легко обобщить, чтобы охватить произвольные векторы логических объектов, где каждая позиция в векторе соответствует интересующему объекту в ваших данных, а позиция установлена ​​в 1 или 0, чтобы указать наличие или отсутствие этого характерная черта.

Если у вас есть бинарные векторы, расстояние Хемминга становится естественной метрикой, хотя евклидово расстояние также используется. Для одноразовых двоичных векторов SOM (или другой аппроксиматор функции) будет естественно интерполироваться между 0 и 1 для каждой позиции вектора. В этом случае эти векторы часто рассматриваются как параметры распределения Больцмана или softmax по пространству номинальной переменной; эта процедура дает возможность использовать векторы в некотором сценарии дивергенции KL.

Циклические переменные намного сложнее. Как сказал Артур в комментариях, вам нужно самостоятельно определить метрику расстояния, которая включает циклический характер переменной.


1

Предполагая, что день недели (dow) исходит из [0, 6], вместо проецирования данных на окружность можно использовать другой вариант:

dist = min(abs(dow_diff), 7 - abs(dow_diff))

Чтобы понять почему, рассмотрим dow как часы

  6  0
5      1
4      2
    3

Разница между 6 и 1 может быть 6 - 1 = 5 (по часовой стрелке от 1 до 6) или 7 - (6 - 1) = 2. Взятие мин обоих вариантов должно помочь.

В общем, вы можете использовать: min(abs(diff), range - abs(diff))


0

Я успешно закодировал Дни недели (и Месяцы года) как кортеж (cos, sin), как указано в его комментарии. Чем использовал евклидово расстояние.

Это пример кода в r:

circularVariable = function(n, r = 4){
 #Transform a circular variable (e.g. Month so the year or day of the week) into two new variables (tuple).
 #n = upper limit of the sequence. E.g. for days of the week this is 7.
 #r =  number of digits to round generated variables.
 #Return
 #
 coord = function(y){
   angle = ((2*pi)/n) *y
   cs = round(cos(angle),r)
   s = round(sin(angle),r)
   c(cs,s)
 }
 do.call("rbind", lapply((0:(n-1)), coord))
}

Евклидово расстояние между 0 и 6 равно 0 и 1.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.