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

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

ただいまの
回答率

90.51%

  • Python 3.x

    6835questions

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

  • 機械学習

    709questions

    機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

  • pandas

    626questions

    Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

  • NumPy

    469questions

    NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

  • R

    318questions

    R言語は、「S言語」をオープンソースとして実装なおした、統計解析向けのプログラミング言語です。 計算がとても速くグラフィックも充実しているため、数値計算に向いています。 文法的には、統計解析部分はS言語を参考にしており、データ処理部分はSchemeの影響を受けています。 世界中の専門家が開発に関わり、日々新しい手法やアルゴリズムが追加されています。

,python x-means: 多次元空間に応用したいがLinAlgError: singular matrixとなる

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 894

ak_miyamoto

score 23

初学者です。データフレームの3つ以上のカラムを用いて、多次元空間におけるクラスタリングを行いたいと考えています。

以下は2次元空間におけるxmeans適用の関数です。(出所)
これを3次元以上の多次元空間に応用すべく、修正したいと考えています。

import numpy as np
from scipy import stats
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
from IPython.display import display, HTML # Jupyter notebook用
import pandas as pd
%matplotlib inline

class XMeans:
    """
    x-means法を行うクラス
    """

    def __init__(self, k_init = 2, **k_means_args):
        """
        k_init : The initial number of clusters applied to KMeans()
        """
        self.k_init = k_init
        self.k_means_args = k_means_args

    def fit(self, X):
        """
        x-means法を使ってデータXをクラスタリングする
        X : array-like or sparse matrix, shape=(n_samples, n_features)
        """
        self.__clusters = [] 

        clusters = self.Cluster.build(X, KMeans(self.k_init, **self.k_means_args).fit(X))
        self.__recursively_split(clusters)

        self.labels_ = np.empty(X.shape[0], dtype = np.intp)
        for i, c in enumerate(self.__clusters):
            self.labels_[c.index] = i

        self.cluster_centers_ = np.array([c.center for c in self.__clusters])
        self.cluster_log_likelihoods_ = np.array([c.log_likelihood() for c in self.__clusters])
        self.cluster_sizes_ = np.array([c.size for c in self.__clusters])

        return self

    def __recursively_split(self, clusters):
        """
        引数のclustersを再帰的に分割する
        clusters : list-like object, which contains instances of 'XMeans.Cluster'
        'XMeans.Cluster'のインスタンスを含むリスト型オブジェクト
        """
        for cluster in clusters:
            if cluster.size <= 3:
                self.__clusters.append(cluster)
                continue

            k_means = KMeans(2, **self.k_means_args).fit(cluster.data)
            c1, c2 = self.Cluster.build(cluster.data, k_means, cluster.index)

            beta = np.linalg.norm(c1.center - c2.center) / np.sqrt(np.linalg.det(c1.cov) + np.linalg.det(c2.cov))
            alpha = 0.5 / stats.norm.cdf(beta)
            bic = -2 * (cluster.size * np.log(alpha) + c1.log_likelihood() + c2.log_likelihood()) + 2 * cluster.df * np.log(cluster.size)

            if bic < cluster.bic():
                self.__recursively_split([c1, c2])
            else:
                self.__clusters.append(cluster)

    class Cluster:
        """
        k-means法によって生成されたクラスタに関する情報を持ち、尤度やBICの計算を行うクラス
        """

        @classmethod
        def build(cls, X, k_means, index = None): 
            if index is None:
                index = np.array(range(0, X.shape[0]))
            labels = range(0, k_means.get_params()["n_clusters"])  

            return tuple(cls(X, index, k_means, label) for label in labels) 

        # index: Xの各行におけるサンプルが元データの何行目のものかを示すベクトル
        def __init__(self, X, index, k_means, label):
            self.data = X[k_means.labels_ == label]
            self.index = index[k_means.labels_ == label]
            self.size = self.data.shape[0]
            self.df = self.data.shape[1] * (self.data.shape[1] + 3) / 2
            self.center = k_means.cluster_centers_[label]
            self.cov = np.cov(self.data.T)

        def log_likelihood(self):
            return sum(stats.multivariate_normal.logpdf(x, self.center, self.cov) for x in self.data)

        def bic(self):
            return -2 * self.log_likelihood() + self.df * np.log(self.size)

この関数に対して、あるデータフレームから取ってくる3×Nの行列を渡します。

data = pd.read_csv(r"file/to/path/data.csv")
data = data.replace(np.inf,np.nan).dropna()

if __name__ == "__main__":
    import matplotlib.pyplot as plt



    test_array = np.array([data["A"].tolist(),data["B"].tolist(),data["C"].tolist()], np.int32).T

    # クラスタリングの実行
    x_means = XMeans(random_state = 1).fit(test_array)  


しかし、以下のようなエラーとなります。逆行列を計算できないとあります。

---------------------------------------------------------------------------
LinAlgError                               Traceback (most recent call last)
<ipython-input-21-450bc8bb6146> in <module>()
     11 
     12     # クラスタリングの実行
---> 13     x_means = XMeans(random_state = 1).fit(test_array)
     14     print(x_means.labels_)
     15     print(x_means.cluster_centers_)

<ipython-input-5-4709a667a908> in fit(self, X)
     19 
     20         clusters = self.Cluster.build(X, KMeans(self.k_init, **self.k_means_args).fit(X))
---> 21         self.__recursively_split(clusters)
     22 
     23         self.labels_ = np.empty(X.shape[0], dtype = np.intp)

<ipython-input-5-4709a667a908> in __recursively_split(self, clusters)
     50 
     51             if bic < cluster.bic():
---> 52                 self.__recursively_split([c1, c2])
     53             else:
     54                 self.__clusters.append(cluster)

<ipython-input-5-4709a667a908> in __recursively_split(self, clusters)
     50 
     51             if bic < cluster.bic():
---> 52                 self.__recursively_split([c1, c2])
     53             else:
     54                 self.__clusters.append(cluster)

#中略 このまとまりと同じエラーが何度も繰り返されます

<ipython-input-5-4709a667a908> in __recursively_split(self, clusters)
     47             beta = np.linalg.norm(c1.center - c2.center) / np.sqrt(np.linalg.det(c1.cov) + np.linalg.det(c2.cov))
     48             alpha = 0.5 / stats.norm.cdf(beta)
---> 49             bic = -2 * (cluster.size * np.log(alpha) + c1.log_likelihood() + c2.log_likelihood()) + 2 * cluster.df * np.log(cluster.size)
     50 
     51             if bic < cluster.bic():

<ipython-input-5-4709a667a908> in log_likelihood(self)
     77 
     78         def log_likelihood(self):
---> 79             return sum(stats.multivariate_normal.logpdf(x, self.center, self.cov) for x in self.data)
     80 
     81         def bic(self):

<ipython-input-5-4709a667a908> in <genexpr>(.0)
     77 
     78         def log_likelihood(self):
---> 79             return sum(stats.multivariate_normal.logpdf(x, self.center, self.cov) for x in self.data)
     80 
     81         def bic(self):

/usr/local/lib/python3.6/dist-packages/scipy/stats/_multivariate.py in logpdf(self, x, mean, cov, allow_singular)
    478         dim, mean, cov = self._process_parameters(None, mean, cov)
    479         x = self._process_quantiles(x, dim)
--> 480         psd = _PSD(cov, allow_singular=allow_singular)
    481         out = self._logpdf(x, mean, psd.U, psd.log_pdet, psd.rank)
    482         return _squeeze_output(out)

/usr/local/lib/python3.6/dist-packages/scipy/stats/_multivariate.py in __init__(self, M, cond, rcond, lower, check_finite, allow_singular)
    155         d = s[s > eps]
    156         if len(d) < len(s) and not allow_singular:
--> 157             raise np.linalg.LinAlgError('singular matrix')
    158         s_pinv = _pinv_1d(s, eps)
    159         U = np.multiply(u, np.sqrt(s_pinv))

LinAlgError: singular matrix


クラス修正が必要と存じていますが、直し方がわかりません。教えて下さると幸いです。よろしくお願いいたします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

0

x-meansが入っててそれなりにしっかり開発されてそうなライブラリを見つけたので、貼っておきます。参考にどうぞ。

annoviko/pyclustering: pyclustring is a Python, C++ data mining (clustering, oscillatory networks, neural networks, etc.) library.

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

クラスター数を自動で決定する方法が必要ということなら、sklearnに実装済みのものから試したほうが簡単かもしれません。sklearnのcheat sheetによるとMeanShiftとVBGMMが提唱させています。
また、sklearnにはクラスター数を評価するsilhouette_scoreという関数があるので、これを使ってkmeansの結果を評価して、一番良さそうなものを選ぶという方法もあります

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 90.51%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Python 3.x

    6835questions

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

  • 機械学習

    709questions

    機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

  • pandas

    626questions

    Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

  • NumPy

    469questions

    NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

  • R

    318questions

    R言語は、「S言語」をオープンソースとして実装なおした、統計解析向けのプログラミング言語です。 計算がとても速くグラフィックも充実しているため、数値計算に向いています。 文法的には、統計解析部分はS言語を参考にしており、データ処理部分はSchemeの影響を受けています。 世界中の専門家が開発に関わり、日々新しい手法やアルゴリズムが追加されています。