名目変数/循環変数のSOMクラスタリング


11

名目上の入力のクラスタリングに精通している人がいるかどうか疑問に思っています。私はソリューションとしてSOMを検討してきましたが、どうやらそれは数値機能でのみ機能します。カテゴリ機能の拡張機能はありますか?具体的には、「Days of the Week」が可能な機能として考えていました。もちろん、数値特徴に変換することも可能です(つまり、月-日が1〜7に対応)。ただし、太陽と月(1&7)の間のユークリッド距離は、月から火(1&2)までの距離と同じではありません。 )。どんな提案やアイデアも大歓迎です。


(1)非常に興味深い質問
ステファン

2
巡回変数は、複素平面の単位円の要素と考えるのが最適です。したがって、(たとえば)ポイント、曜日をマッピングするのは自然なことです。つまり、、、...。J = 0 ... 6exp(2jπi/7)j=0,,6COS 2 π / 7 2 π / 7 COS 12 π / 7 12 π / 7 (cos(0),sin(0))(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()を定義することです。
Arthur Small

回答:


7

バックグラウンド:

時間を変換する最も論理的な方法は、同期を外れて前後に変動する2つの変数に変換することです。24時間時計の時針の位置を想像してみてください。x前後にと同期して位置スイングy位置。24時間制の場合x=sin(2pi*hour/24)、これは、で実現できますy=cos(2pi*hour/24)

両方の変数が必要です。そうしないと、時間の経過に伴う適切な動きが失われます。これは、sinまたはcosのいずれかの導関数が時間とともに変化するのに対し、(x,y)位置が単位円の周りを移動するときに滑らかに変化するためです。

最後に、3番目の機能を追加して線形時間をトレースする価値があるかどうかを検討します。これは、最初のレコードの開始からの時間(または分または秒)またはUnixタイムスタンプなどで構成できます。これらの3つの機能は、時間の循環的および線形的な進行の両方にプロキシを提供します。たとえば、人々の動きの睡眠サイクルなどの循環的な現象や、人口と時間のような線形的な成長を引き出すことができます。

達成された場合の例:

# 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)

ここに画像の説明を入力してください

真夜中前の緑のクラスターには、真夜中以降の時間が含まれていることがわずかにわかります。次に、クラスターの数を減らして、真夜中前後に1つのクラスターで接続できることをさらに詳しく示します。

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

ここに画像の説明を入力してください

青いクラスターに、同じクラスターにクラスター化された真夜中前後の時刻がどのように含まれているかを確認してください...

これは、時間、曜日、月の週、日、季節のいずれかで行うことができます。


参考になった(+1)。これは、グラフが長方形ではなく正方形であることが本当に重要なアプリケーションの1つです。あなたのソフトウェアは知りませんが、アスペクト比をデフォルトから1に設定できると思います。
Nick Cox

それは本当の@NickCoxです。または、頭の中で線形変換を実行することもできます;-)
user1745038

2

一般的に名目変数は、SOMで使用される場合にダミーコード化されます(たとえば、1つの変数が月曜日ではなく0で月曜日でない場合、別の変数が火曜日である場合など)。

隣接する日の複合カテゴリを作成することにより、追加情報を組み込むことができます。例:月曜日と火曜日、火曜日と水曜日など。ただし、データが人間の行動に関連している場合は、カテゴリとして週日と週末を使用する方が便利です。


2

名目変数の場合、ニューラルネットワークまたは電気工学のコンテキストでの一般的なエンコーディングは「ワンホット」と呼ばれます。変数の値に適切な位置に1が1である、すべて0のベクトルです。たとえば、曜日には7日あるため、ワンホットベクトルの長さは7になります。次に、月曜日は[1 0 0 0 0 0 0]、火曜日は[0 1 0 0 0 0 0]のように表されます。

Timが示唆したように、このアプローチは任意のブール特徴ベクトルを含むように簡単に一般化できます。ベクトルの各位置はデータ内の対象の特徴に対応し、位置は1または0に設定され、その存在または不在を示します。特徴。

バイナリベクトルを取得すると、ハミング距離は自然なメトリックになりますが、ユークリッド距離も使用されます。ワンホットバイナリベクトルの場合、SOM(または他の関数近似器)は、各ベクトル位置に対して0と1の間で自然に補間します。この場合、これらのベクトルは、名目変数の空間上のボルツマンまたはソフトマックス分布のパラメーターとして扱われることがよくあります。この処理は、ある種のKL分岐シナリオでもベクトルを使用する方法を提供します。

巡回変数はかなりトリッキーです。アーサーがコメントで述べたように、変数の循環的な性質を組み込んだ距離メトリックを自分で定義する必要があります。


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

彼のコメントで強調されたwhuberとして、曜日(およびその年の月)を(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に等しい。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.