web-dev-qa-db-ja.com

Python:scikit-learnのdbscanを使用した文字列クラスタリング、レーベンシュタイン距離をメトリックとして使用:

私は各URLの元のデータとタイプミスを見つけるために、URLの複数のデータセット(それぞれ約100万個)をクラスター化しようとしています。クラスタリングの数がわからないのでk平均アルゴリズムが機能しないため、クラスタリングアルゴリズムとしてdbscanと同様に、レーベンシュタイン距離を類似性メトリックとして使用することにしました。

Scikit-learnのdbscanの実装を使用して、いくつかの問題に直面しています。

以下のスニペットは、私が使用している形式の小さなデータセットで機能しますが、距離行列全体を事前計算しているため、O(n ^ 2)の空間と時間を必要とし、大きなデータセットには多すぎます。私はこれを何時間も実行しましたが、それは私のPCのすべてのメモリを消費するだけです。

lev_similarity = -1*np.array([[distance.levenshtein(w1[0],w2[0]) for w1 in words] for w2 in words])
dbscan = sklearn.cluster.DBSCAN(eps = 7, min_samples = 1)
dbscan.fit(lev_similarity)

そのため、オンザフライで類似性を計算する方法が必要だと考え、この方法を試しました。

dbscan = sklearn.cluster.DBSCAN(eps = 7, min_samples = 1, metric = distance.levenshtein)
dbscan.fit(words)

しかし、この方法ではエラーが発生します。

ValueError: could not convert string to float: URL

これは、入力を相似関数への変換をフロートに変換しようとしていることを意味します。しかし、私はそれをしたくありません。私が理解している限り、2つの引数を取り、float値を返す関数が必要です。この値をepsと比較できます。これは、レーベンシュタイン距離で行う必要があります。

Sklearnのdbscanの実装の詳細がわからないため、フロートに変換しようとしている理由がわかりません。また、O(n ^ 2)行列を回避する方法については、これ以上の考えはありません。計算。

私が見落としている可能性があるこれらの多くの文字列をクラスタ化するためのより良いまたはより速い方法があるかどうか私に知らせてください。

11
KaziJehangir

Scikit-learnのよくある質問から、これを カスタムメトリックの作成 で行うことができます。

from leven import levenshtein       
import numpy as np
from sklearn.cluster import dbscan
data = ["ACCTCCTAGAAG", "ACCTACTAGAAGTT", "GAATATTAGGCCGA"]
def lev_metric(x, y):
    i, j = int(x[0]), int(y[0])     # extract indices
    return levenshtein(data[i], data[j])

X = np.arange(len(data)).reshape(-1, 1)
dbscan(X, metric=lev_metric, eps=5, min_samples=2)
10
Luke

Sklearnの代わりにELKIを試してください。

anyメトリックを使用してインデックスアクセラレーションDBSCANを許可する唯一のツールです。

レーベンシュタイン距離が含まれます。 -db.indexを使用して、データベースにインデックスを追加する必要があります。私は常にカバーツリーインデックスを使用します(もちろん、インデックスとアルゴリズムに同じ距離を選択する必要があります!)

「pyfunc」距離とボールツリーをsklearnで使用できますが、インタープリターが原因でパフォーマンスは本当に悪かったです。また、sklearnのDBSCANは、より多くのメモリを消費します。