首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >超参数调优k均值聚类

超参数调优k均值聚类
EN

Stack Overflow用户
提问于 2020-05-23 13:35:30
回答 1查看 3.8K关注 0票数 1

我试图通过在管道中使用决策树分类器来执行时空K-均值聚类的超参数调优。其思想是利用K-均值聚类算法生成聚类距离空间矩阵和聚类标签,然后将其传递给决策树分类器。对于超参数调整,只需使用K-均值算法的参数即可。我正在使用Python3.8和sklearn 0.22。

我感兴趣的数据有3列/属性:timexy (xy是空间坐标)。

守则是:

代码语言:javascript
复制
class ST_KMeans():
    """
    Note that the K-means clustering algorithm is designed for Euclidean distances.
    It may stop converging with other distances when the mean is no longer a
    best estimation for the cluster 'center'.

    The 'mean' minimizes squared differences (or, squared Euclidean distance).
    If you want a different distance function, you need to replace the mean with
    an appropriate center estimation.


    Parameters:

    k:  number of clusters
    
    eps1 : float, default=0.5
        The spatial density threshold (maximum spatial distance) between 
        two points to be considered related.

    eps2 : float, default=10
        The temporal threshold (maximum temporal distance) between two 
        points to be considered related.

    metric : string default='euclidean'
        The used distance metric - more options are
        ‘braycurtis’, ‘canberra’, ‘chebyshev’, ‘cityblock’, ‘correlation’,
        ‘cosine’, ‘dice’, ‘euclidean’, ‘hamming’, ‘jaccard’, ‘jensenshannon’,
        ‘kulsinski’, ‘mahalanobis’, ‘matching’, ‘rogerstanimoto’, ‘sqeuclidean’,
        ‘russellrao’, ‘seuclidean’, ‘sokalmichener’, ‘sokalsneath’, ‘yule’.
    
    n_jobs : int or None, default=-1
        The number of processes to start; -1 means use all processors (BE AWARE)


    Attributes:
    
    labels : array, shape = [n_samples]
        Cluster labels for the data - noise is defined as -1
    """

    def __init__(self, k, eps1 = 0.5, eps2 = 10, metric = 'euclidean', n_jobs = 1):
        self.k = k
        self.eps1 = eps1
        self.eps2 = eps2
        # self.min_samples = min_samples
        self.metric = metric
        self.n_jobs = n_jobs


    def fit(self, X):
        """
        Apply the ST K-Means algorithm 
        
        X : 2D numpy array. The first attribute of the array should be time attribute
            as float. The following positions in the array are treated as spatial
            coordinates.
            The structure should look like this [[time_step1, x, y], [time_step2, x, y]..]
            
            For example 2D dataset:
            array([[0,0.45,0.43],
            [0,0.54,0.34],...])


        Returns:

        self
        """
        
        # check if input is correct
        X = check_array(X)

        # type(X)
        # numpy.ndarray

        # Check arguments for DBSCAN algo-
        if not self.eps1 > 0.0 or not self.eps2 > 0.0:
            raise ValueError('eps1, eps2, minPts must be positive')

        # Get dimensions of 'X'-
        # n - number of rows
        # m - number of attributes/columns-
        n, m = X.shape


        # Compute sqaured form Euclidean Distance Matrix for 'time' and spatial attributes-
        time_dist = squareform(pdist(X[:, 0].reshape(n, 1), metric = self.metric))
        euc_dist = squareform(pdist(X[:, 1:], metric = self.metric))

        '''
        Filter the euclidean distance matrix using time distance matrix. The code snippet gets all the
        indices of the 'time_dist' matrix in which the time distance is smaller than 'eps2'.
        Afterward, for the same indices in the euclidean distance matrix the 'eps1' is doubled which results
        in the fact that the indices are not considered during clustering - as they are bigger than 'eps1'.
        '''
        # filter 'euc_dist' matrix using 'time_dist' matrix-
        dist = np.where(time_dist <= self.eps2, euc_dist, 2 * self.eps1)


        # Initialize K-Means clustering model-
        self.kmeans_clust_model = KMeans(
            n_clusters = self.k, init = 'k-means++',
            n_init = 10, max_iter = 300,
            precompute_distances = 'auto', algorithm = 'auto')

        # Train model-
        self.kmeans_clust_model.fit(dist)


        self.labels = self.kmeans_clust_model.labels_

        self.X_transformed = self.kmeans_clust_model.fit_transform(X)

        return self

    def transform(self, X):
        # print("\nX.shape = {0}\n".format(X.shape))
        # pass
        # return self.kmeans_clust_model.fit_transform(X)
        return self.X_transformed



# Initialize ST-K-Means object-
st_kmeans_algo = ST_KMeans(
    k = 5, eps1=0.6,
    eps2=9, metric='euclidean',
    n_jobs=1
    )

# Train on a chunk of dataset-
st_kmeans_algo.fit(data.loc[:500, ['time', 'x', 'y']])

# Get clustered data points labels-
kmeans_labels = st_kmeans_algo.labels

kmeans_labels.shape
# (501,)


# Get labels for points clustered using trained model-
kmeans_transformed = st_kmeans_algo.X_transformed

kmeans_transformed.shape
# (501, 5)

dtc = DecisionTreeClassifier()

dtc.fit(kmeans_transformed, kmeans_labels)

y_pred = dtc.predict(kmeans_transformed)

# Get model performance metrics-
accuracy = accuracy_score(kmeans_labels, y_pred)
precision = precision_score(kmeans_labels, y_pred, average='macro')
recall = recall_score(kmeans_labels, y_pred, average='macro')

print("\nDT model metrics are:")
print("accuracy = {0:.4f}, precision = {1:.4f} & recall = {2:.4f}\n".format(
    accuracy, precision, recall
    ))

# DT model metrics are:
# accuracy = 1.0000, precision = 1.0000 & recall = 1.0000


# Define steps of pipeline-
pipeline_steps = [
    ('st_kmeans_algo' ,ST_KMeans(k = 5, eps1=0.6, eps2=9, metric='euclidean', n_jobs=1)),
    ('dtc', DecisionTreeClassifier())
    ]

# Instantiate a pipeline-
pipeline = Pipeline(pipeline_steps)

# Train pipeline-
pipeline.fit(kmeans_transformed, kmeans_labels)

然而,pipeline.fit()提供了以下错误:

代码语言:javascript
复制
> --------------------------------------------------------------------------- TypeError                                 Traceback (most recent call
> last) <ipython-input-25-711d6dd8d926> in <module>
> ----> 1 pipeline = Pipeline(pipeline_steps)
> 
> ~/.local/lib/python3.8/site-packages/sklearn/pipeline.py in
> __init__(self, steps, memory, verbose)
>     134         self.memory = memory
>     135         self.verbose = verbose
> --> 136         self._validate_steps()
>     137 
>     138     def get_params(self, deep=True):
> 
> ~/.local/lib/python3.8/site-packages/sklearn/pipeline.py in
> _validate_steps(self)
>     179             if (not (hasattr(t, "fit") or hasattr(t, "fit_transform")) or not
>     180                     hasattr(t, "transform")):
> --> 181                 raise TypeError("All intermediate steps should be "
>     182                                 "transformers and implement fit and transform "
>     183                                 "or be the string 'passthrough' "
> 
> TypeError: All intermediate steps should be transformers and implement
> fit and transform or be the string 'passthrough' '<__main__.ST_KMeans
> object at 0x7f0971db5430>' (type <class '__main__.ST_KMeans'>) doesn't

出什么问题了?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-24 09:21:20

您的错误信息说明了一切:所有中间步骤都应该是转换器,并实现fit 和转换。在您的示例中,类ST_KMeans()还必须实现一个transform函数,以便在管道中使用。此外,最佳实践通常是从BaseEstimator类继承,从模块sklearn.base继承TransformerMixin

代码语言:javascript
复制
from sklearn.base import BaseEstimator, TransformerMixin


class ST_KMeans(BaseEstimator, TransformerMixin):

    def fit(self, X, y=none):
        ...
        return self

    def transform(self, X):
        return self.X_transformed

然后,您可以在管道中使用您的类。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61972858

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档