针对名义/圆形变量的SOM聚类


11

只是想知道是否有人熟悉标称输入的聚类。我一直在将SOM作为解决方案,但显然它仅适用于数字功能。分类功能是否有扩展?我特别想知道“星期几”是否可能是功能。当然可以将其转换为数值特征(例如,周一至周日对应于1-7号),但是,周日与周一之间的欧几里得距离(1&7)将与周一至周二(1&2)之间的欧氏距离不同)。任何建议或想法将不胜感激。


(+1)一个非常有趣的问题
steffen 2011年

2
最好将循环变量视为复平面中单位圆的元素。因此,它会自然地一周中的天映射到(比方说)点Ĵ = 0 ... 6 ; COS 0 0 COS 2 π / 7 2 π / 7经验值2Ĵπ一世/7Ĵ=06cos00,...COS 12 π / 7 12 π / 7 cos2π/72π/7cos12π/712π/7
ub

1
我是否必须编写自己的距离矩阵,然后再指定循环变量?只是想知道是否已经有用于此类聚类的算法。thx
Michael

@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()的方式来捕获适合您的应用程序的“相似性”概念。
亚瑟·

Answers:


7

背景:

转换小时数的最合乎逻辑的方法是将两个变量来回摆动,使其不同步。想象一下24小时制时针的末尾位置。该x位置来回摆动不同步的y位置。对于24小时制,您可以使用x=sin(2pi*hour/24),完成y=cos(2pi*hour/24)

您需要两个变量,否则会丢失正确的移动时间。这是由于正弦或余弦的导数随时间而变化,而(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

对于名义变量,在神经网络或电气工程环境中的典型编码称为“单热”one-hot),即全0的矢量,其中1对应于变量值。例如,在一周中的某天,有7天,因此您的一热点向量长度为​​7。然后,星期一将表示为[1 0 0 0 0 0 0 0],星期二将表示为[0 1 0 0 0 0 0],依此类推。

正如Tim所暗示的,这种方法可以很容易地推广为包含任意布尔特征向量,其中向量中的每个位置都对应于数据中感兴趣的特征,并且该位置设置为1或0表示存在或不存在该特征特征。

一旦有了二元向量,尽管也使用了欧几里得距离,汉明距离便成为自然度量。对于单热二进制矢量,对于每个矢量位置,SOM(或其他函数逼近器)自然会在0和1之间进行插值。在这种情况下,这些向量通常被视为标称变量空间上的Boltzmann或softmax分布的参数;这种处理方式也提供了在某些KL散布情况下使用向量的方法。

循环变量要复杂得多。正如亚瑟(Arthur)在评论中所说,您需要自己定义一个距离量度,并结合变量的循环特性。


1

假设星期几(dow)从[0,6]开始,而不是将数据投影到圆上,另一个选择是使用:

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

要了解原因,请将道琼斯视为时钟

  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。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.