【问题标题】:Scikit Learn GridSearchCV without cross validation (unsupervised learning)Scikit Learn GridSearchCV without cross validation(无监督学习)
【发布时间】:2019-02-08 05:20:45
【问题描述】:

是否可以在没有交叉验证的情况下使用 GridSearchCV?我正在尝试通过网格搜索优化 KMeans 聚类中的聚类数量,因此我不需要或不需要交叉验证。

documentation 也让我感到困惑,因为在 fit() 方法下,它有一个用于无监督学习的选项(说使用 None 进行无监督学习)。但是如果你想做无监督学习,你需要在没有交叉验证的情况下进行,而且似乎没有摆脱交叉验证的选项。

【问题讨论】:

  • 您如何确定使用 KMeans 的最佳集群数量?
  • 我现在使用的是剪影评分,我打算以后继续使用其他评分方法。
  • 好的,在这种情况下,您应该避免使用 GridSearchCV,因为顾名思义,它将使用 CV。我建议将您的 KMeans 包裹在 for 循环周围,然后通过每次迭代评估轮廓度量。不确定您是否看到此example,但它应该对您有所帮助。 :)
  • 您可以实现一个自定义 cv,它将所有数据放入训练和测试中。
  • @Eddy 您仍然可以与for 循环并行运行参数扫描。你可以阅读我的blog post

标签: python optimization machine-learning scikit-learn cluster-analysis


【解决方案1】:

我将回答您的问题,因为它似乎仍然没有答案。使用for循环的并行方法,您可以使用multiprocessing模块。

from multiprocessing.dummy import Pool
from sklearn.cluster import KMeans
import functools

kmeans = KMeans()

# define your custom function for passing into each thread
def find_cluster(n_clusters, kmeans, X):
    from sklearn.metrics import silhouette_score  # you want to import in the scorer in your function

    kmeans.set_params(n_clusters=n_clusters)  # set n_cluster
    labels = kmeans.fit_predict(X)  # fit & predict
    score = silhouette_score(X, labels)  # get the score

    return score

# Now's the parallel implementation
clusters = [3, 4, 5]
pool = Pool()
results = pool.map(functools.partial(find_cluster, kmeans=kmeans, X=X), clusters)
pool.close()
pool.join()

# print the results
print(results)  # will print a list of scores that corresponds to the clusters list

【讨论】:

  • 感谢您的 DIY 解决方案。我想我可能已经找到了一种无需交叉验证即可使用 GridSearchCV 的方法,我会尽快发布我的答案。
  • 太棒了!请分享!
  • 刚刚分享,有什么意见请告诉我。
【解决方案2】:

经过大量搜索,我找到了this thread。如果您使用以下方法,您似乎可以摆脱 GridSearchCV 中的交叉验证:

cv=[(slice(None), slice(None))]

我已经针对我自己的网格搜索编码版本进行了测试,没有交叉验证,我从两种方法中得到了相同的结果。我将这个答案发布到我自己的问题上,以防其他人有同样的问题。

编辑:回答 jjrr 在 cmets 中的问题,这里是一个示例用例:

from sklearn.metrics import silhouette_score as sc

def cv_silhouette_scorer(estimator, X):
    estimator.fit(X)
    cluster_labels = estimator.labels_
    num_labels = len(set(cluster_labels))
    num_samples = len(X.index)
    if num_labels == 1 or num_labels == num_samples:
        return -1
    else:
        return sc(X, cluster_labels)

cv = [(slice(None), slice(None))]
gs = GridSearchCV(estimator=sklearn.cluster.MeanShift(), param_grid=param_dict, 
                  scoring=cv_silhouette_scorer, cv=cv, n_jobs=-1)
gs.fit(df[cols_of_interest])

【讨论】:

  • 真的很有趣和hackey类型的解决方案!
  • hmm...也许源代码中发生了一些变化?几个月前我还没有尝试过。
  • 谢谢@DataMan,好主意——我有一个更基本的问题:在这种情况下,你如何通过估算器? (剪影)——谢谢
  • 我收到错误:AttributeError: 'slice' object has no attribute 'flags'。 Python 3.6,sklearn 0.20.3
  • AttributeError: 'slice' 对象没有属性 'flags'
【解决方案3】:

我认为使用 cv=ShuffleSplit(test_size=0.20, n_splits=1) 和 n_splits=1 是一个更好的解决方案,例如 post 建议

【讨论】:

    【解决方案4】:

    我最近推出了以下基于this answer 的自定义交叉验证器。我将它传递给GridSearchCV,它为我正确禁用了交叉验证:

    import numpy as np
    
    class DisabledCV:
        def __init__(self):
            self.n_splits = 1
    
        def split(self, X, y, groups=None):
            yield (np.arange(len(X)), np.arange(len(y)))
    
        def get_n_splits(self, X, y, groups=None):
            return self.n_splits
    

    希望对你有帮助。

    【讨论】:

    • 我测试了你的解决方案,我收到了这个错误:“return self.n_splits AttributeError: 'numpy.ndarray' object has no attribute 'n_splits'”。你知道怎么解决吗?
    猜你喜欢
    • 2019-04-16
    • 2017-08-22
    • 2014-04-20
    • 2022-10-25
    • 2017-02-28
    • 2013-03-24
    • 2013-12-01
    • 2018-10-18
    相关资源
    最近更新 更多