質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

1986閲覧

3つのクラスタに分けて表示させたいです

mi56

総合スコア14

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2017/05/23 12:08

###前提・実現したいこと
Pythonでクラスタリングについて勉強しています。
コードはhttps://github.com/joelgrus/data-science-from-scratch/blob/master/code/clustering.py
にあります。
現段階でできているのはクラスタの中心を求めること、クラスタリングせずにグラフへの表示です。
したいことは3つのクラスタに分けてクラスタ毎にクラスタの点の種類を変更して表示したいです。

###発生している問題・エラーメッセージ
3つのクラスタに分けることができません。

###該当のソースコード

Python

1from __future__ import division 2#from linear_algebra import squared_distance, vector_mean, distance 3import math, random 4import matplotlib.image as mpimg 5import matplotlib.pyplot as plt 6from functools import reduce 7import re, math, random 8from collections import defaultdict, Counter 9 10# 11# functions for working with vectors 12# 13 14def vector_add(v, w): 15 """adds two vectors componentwise""" 16 return [v_i + w_i for v_i, w_i in zip(v,w)] 17 18def vector_subtract(v, w): 19 """subtracts two vectors componentwise""" 20 return [v_i - w_i for v_i, w_i in zip(v,w)] 21 22def vector_sum(vectors): 23 return reduce(vector_add, vectors) 24 25def scalar_multiply(c, v): 26 return [c * v_i for v_i in v] 27 28# this isn't right if you don't from __future__ import division 29def vector_mean(vectors): 30 """compute the vector whose i-th element is the mean of the 31 i-th elements of the input vectors""" 32 n = len(vectors) 33 return scalar_multiply(1/n, vector_sum(vectors)) 34 35def dot(v, w): 36 """v_1 * w_1 + ... + v_n * w_n""" 37 return sum(v_i * w_i for v_i, w_i in zip(v, w)) 38 39def sum_of_squares(v): 40 """v_1 * v_1 + ... + v_n * v_n""" 41 return dot(v, v) 42 43def magnitude(v): 44 return math.sqrt(sum_of_squares(v)) 45 46def squared_distance(v, w): 47 return sum_of_squares(vector_subtract(v, w)) 48 49def distance(v, w): 50 return math.sqrt(squared_distance(v, w)) 51 52class KMeans: 53 """performs k-means clustering""" 54 55 def __init__(self, k): 56 self.k = k # number of clusters 57 self.means = None # means of clusters 58 59 60 def classify(self, input): 61 """return the index of the cluster closest to the input""" 62 #print(range(self.k)) 63 #print( min(range(self.k), 64 #key=lambda i: squared_distance(input, self.means[i])), squared_distance()) 65 66 return min(range(self.k), 67 key=lambda i: squared_distance(input, self.means[i])) 68 69 def train(self, inputs): 70 71 self.means = random.sample(inputs, self.k) 72 #print(self.means) 73 assignments = None 74 75 while True: 76 # Find new assignments 77 new_assignments = map(self.classify, inputs) 78 79 # If no assignments have changed, we're done. 80 if assignments == new_assignments: 81 return 82 83 # Otherwise keep the new assignments, 84 assignments = new_assignments 85 86 for i in range(self.k): 87 i_points = [p for p, a in zip(inputs, assignments) if a == i] 88 # avoid divide-by-zero if i_points is empty 89 if i_points: 90 self.means[i] = vector_mean(i_points) 91 92 93if __name__ == "__main__": 94 95 inputs = [[-14,-5],[13,13],[20,23],[-19,-11],[-9,-16],[21,27],[-49,15],[26,13],[-46,5],[-34,-1],[11,15],[-49,0],[-22,-16],[19,28],[-12,-8],[-13,-19],[-41,8],[-11,-6],[-25,-9],[-18,-3]] 96 97 98 random.seed(0) # so you get the same results as me 99 clusterer = KMeans(3) 100 try: 101 clusterer.train(inputs) 102 except: 103 val =+ 1 104 print ("3-means:") 105 print (clusterer.means) 106 107#first = [-14,13,20,-19,-9,21,-49,26,-46,-34,11,-49,-22,19,-12,-13,-41,-11,-25,-18] 108#second = [-5,13,23,-11,-16,27,15,13,5,-1,15,0,-16,28,-8,-19,8,-6,-9,-3,] 109 110first,second = zip(*inputs) 111plt.scatter(first,second) 112plt.show()

###補足情報(言語/FW/ツール等のバージョンなど)
Pyhon3.5

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

とりあえずシンプルな方法として、以下のようにクラスター毎に色分けするのが簡単ではないでしょうか。

Python

1if __name__ == "__main__": 2 inputs = [[-14,-5],[13,13],[20,23],[-19,-11],[-9,-16],[21,27],[-49,15],[26,13],[-46,5],[-34,-1],[11,15],[-49,0],[-22,-16],[19,28],[-12,-8],[-13,-19],[-41,8],[-11,-6],[-25,-9],[-18,-3]] 3 4 random.seed(0) 5 clusterer = KMeans(3) 6 clusterer.train(inputs) 7 8 # 各クラスタ毎の色を定義 9 COLORS = ['red','blue','green'] 10 # 中心位置をプロット 11 for cls, vec in enumerate(clusterer.means): 12 plt.scatter(*vec, c=COLORS[cls], marker='x') 13 # 各データをプロット 14 for cls, vec in zip(map(clusterer.classify, inputs), inputs): 15 plt.scatter(*vec, c=COLORS[cls], marker='.') 16 plt.show()

イメージ説明

投稿2017/05/24 08:33

編集2017/05/24 08:53
magichan

総合スコア15898

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

magichan

2017/05/25 06:36 編集

あと質問のコードをそのままPython35で動作させたところ、無限ループにはまった為、修正して使用しました。修正内容は https://teratail.com/questions/74908 の質問の解答に記述しました。
mi56

2017/05/30 09:21

回答ありがとうございます。 inputを入力とした時クラスタリングを行うと横軸20~30,縦軸10~30で1グループ、横軸-25~ -10,縦軸-20~0で1グループ、横軸-40~ -50,縦軸0~20で1グループになると思ったのですがなぜ右上だけて2グループに分けられているのか教えていただきたいです。
magichan

2017/05/30 10:09

k-mean法は「初期値依存性」という問題があり、初期値のとり方によって全く異なる結果が得られます。 ですので、今回は初期値の値により「たまたまこのような結果が得られた」とお考えください。(初期値のとり方によっては、mi56さんの想定している結果になることもあります。) なお、現在のコードは random.seed(0) となっており、毎回同じ乱数表を使っているため、結果も毎回同じとなります。 random.seed() として起動毎に違う乱数を使用するようにすると結果が毎回変わります。何度か実行してみて望ましい(と思われる)結果を採用するとよいのではないでしょうか。 初期値のとり方を改良した 「k-mean++ 」などもありますので、検索してみてください。
mi56

2017/05/30 14:30

丁寧な説明ありがとうございました。 seedの値を変えて試してみたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問