We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Incorrect parameter values in K-Elbow Visualizer docstring
Initially in the K-Elbow Visualizer's docstring, the possible values for the parameter `metric` are named as `distortion_score`, `silhouette_score`, and `calinski_harabaz_score`. However, using these values returns the following error:

`YellowbrickValueError: '{}' is not a defined metric use one of distortion, silhouette, or calinski_harabaz`

However, the correct names&mdash;`distortion`, `silhouette`, `calinski_harabaz`&mdash;are listed corrected further down under `Parameters`.

![elbow-documentation](https://user-images.githubusercontent.com/19958803/43358572-0f72b404-9262-11e8-8201-7a9ef6cd3fec.png)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `yellowbrick/cluster/elbow.py`
Content:
```
1 # yellowbrick.cluster.elbow
2 # Implements the elbow method for determining the optimal number of clusters.
3 #
4 # Author:   Benjamin Bengfort <bbengfort@districtdatalabs.com>
5 # Created:  Thu Mar 23 22:36:31 2017 -0400
6 #
7 # Copyright (C) 2016 District Data Labs
8 # For license information, see LICENSE.txt
9 #
10 # ID: elbow.py [5a370c8] benjamin@bengfort.com $
11 
12 """
13 Implements the elbow method for determining the optimal number of clusters.
14 https://bl.ocks.org/rpgove/0060ff3b656618e9136b
15 """
16 
17 ##########################################################################
18 ## Imports
19 ##########################################################################
20 
21 import time
22 import numpy as np
23 import scipy.sparse as sp
24 
25 from .base import ClusteringScoreVisualizer
26 from ..exceptions import YellowbrickValueError
27 
28 from sklearn.metrics import silhouette_score
29 from sklearn.metrics import calinski_harabaz_score
30 from sklearn.metrics.pairwise import pairwise_distances
31 from sklearn.preprocessing import LabelEncoder
32 
33 
34 ## Packages for export
35 __all__ = [
36     "KElbowVisualizer", "distortion_score"
37 ]
38 
39 
40 ##########################################################################
41 ## Metrics
42 ##########################################################################
43 
44 def distortion_score(X, labels, metric='euclidean'):
45     """
46     Compute the mean distortion of all samples.
47 
48     The distortion is computed as the the sum of the squared distances between
49     each observation and its closest centroid. Logically, this is the metric
50     that K-Means attempts to minimize as it is fitting the model.
51 
52     .. seealso:: http://kldavenport.com/the-cost-function-of-k-means/
53 
54     Parameters
55     ----------
56     X : array, shape = [n_samples, n_features] or [n_samples_a, n_samples_a]
57         Array of pairwise distances between samples if metric == "precomputed"
58         or a feature array for computing distances against the labels.
59 
60     labels : array, shape = [n_samples]
61         Predicted labels for each sample
62 
63     metric : string
64         The metric to use when calculating distance between instances in a
65         feature array. If metric is a string, it must be one of the options
66         allowed by `sklearn.metrics.pairwise.pairwise_distances
67         <http://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise.pairwise_distances.html#sklearn.metrics.pairwise.pairwise_distances>`_
68 
69     .. todo:: add sample_size and random_state kwds similar to silhouette_score
70     """
71     # Encode labels to get unique centers and groups
72     le = LabelEncoder()
73     labels = le.fit_transform(labels)
74     unique_labels = le.classes_
75 
76     # Sum of the distortions
77     distortion = 0
78 
79     # Loop through each label (center) to compute the centroid
80     for current_label in unique_labels:
81         # Mask the instances that belong to the current label
82         mask = labels == current_label
83         instances = X[mask]
84 
85         # Compute the center of these instances
86         center = instances.mean(axis=0)
87 
88         # NOTE: csc_matrix and csr_matrix mean returns a 2D array, numpy.mean
89         # returns an array of 1 dimension less than the input. We expect
90         # instances to be a 2D array, therefore to do pairwise computation we
91         # require center to be a 2D array with a single row (the center).
92         # See #370 for more detail.
93         if not sp.issparse(instances):
94             center = np.array([center])
95 
96         # Compute the square distances from the instances to the center
97         distances = pairwise_distances(instances, center, metric=metric)
98         distances = distances ** 2
99 
100         # Add the mean square distance to the distortion
101         distortion += distances.mean()
102 
103     return distortion
104 
105 
106 ##########################################################################
107 ## Elbow Method
108 ##########################################################################
109 
110 KELBOW_SCOREMAP = {
111     "distortion": distortion_score,
112     "silhouette": silhouette_score,
113     "calinski_harabaz": calinski_harabaz_score,
114 }
115 
116 
117 class KElbowVisualizer(ClusteringScoreVisualizer):
118     """
119     The K-Elbow Visualizer implements the "elbow" method of selecting the
120     optimal number of clusters for K-means clustering. K-means is a simple
121     unsupervised machine learning algorithm that groups data into a specified
122     number (k) of clusters. Because the user must specify in advance what k to
123     choose, the algorithm is somewhat naive -- it assigns all members to k
124     clusters even if that is not the right k for the dataset.
125 
126     The elbow method runs k-means clustering on the dataset for a range of
127     values for k (say from 1-10) and then for each value of k computes an
128     average score for all clusters. By default, the ``distortion_score`` is
129     computed, the sum of square distances from each point to its assigned
130     center. Other metrics can also be used such as the ``silhouette_score``,
131     the mean silhouette  coefficient for all samples or the
132     ``calinski_harabaz_score``, which computes the ratio of dispersion between
133     and within clusters.
134 
135     When these overall metrics for each model are plotted, it is possible to
136     visually determine the best value for K. If the line chart looks like an
137     arm, then the "elbow" (the point of inflection on the curve) is the best
138     value of k. The "arm" can be either up or down, but if there is a strong
139     inflection point, it is a good indication that the underlying model fits
140     best at that point.
141 
142     Parameters
143     ----------
144 
145     model : a Scikit-Learn clusterer
146         Should be an instance of a clusterer, specifically ``KMeans`` or
147         ``MiniBatchKMeans``. If it is not a clusterer, an exception is raised.
148 
149     ax : matplotlib Axes, default: None
150         The axes to plot the figure on. If None is passed in the current axes
151         will be used (or generated if required).
152 
153     k : integer or tuple
154         The range of k to compute silhouette scores for. If a single integer
155         is specified, then will compute the range (2,k) otherwise the
156         specified range in the tuple is used.
157 
158     metric : string, default: ``"distortion"``
159         Select the scoring metric to evaluate the clusters. The default is the
160         mean distortion, defined by the sum of squared distances between each
161         observation and its closest centroid. Other metrics include:
162 
163         - **distortion**: mean sum of squared distances to centers
164         - **silhouette**: mean ratio of intra-cluster and nearest-cluster distance
165         - **calinski_harabaz**: ratio of within to between cluster dispersion
166 
167     timings : bool, default: True
168         Display the fitting time per k to evaluate the amount of time required
169         to train the clustering model.
170 
171     kwargs : dict
172         Keyword arguments that are passed to the base class and may influence
173         the visualization as defined in other Visualizers.
174 
175     Examples
176     --------
177 
178     >>> from yellowbrick.cluster import KElbowVisualizer
179     >>> from sklearn.cluster import KMeans
180     >>> model = KElbowVisualizer(KMeans(), k=10)
181     >>> model.fit(X)
182     >>> model.poof()
183 
184     Notes
185     -----
186 
187     If you get a visualizer that doesn't have an elbow or inflection point,
188     then this method may not be working. The elbow method does not work well
189     if the data is not very clustered; in this case you might see a smooth
190     curve and the value of k is unclear. Other scoring methods such as BIC or
191     SSE also can be used to explore if clustering is a correct choice.
192 
193     For a discussion on the Elbow method, read more at
194     `Robert Gove's Block <https://bl.ocks.org/rpgove/0060ff3b656618e9136b>`_.
195 
196     .. todo:: add parallelization option for performance
197     .. todo:: add different metrics for scores and silhoutte
198     .. todo:: add timing information about how long its taking
199     """
200 
201     def __init__(self, model, ax=None, k=10,
202                  metric="distortion", timings=True, **kwargs):
203         super(KElbowVisualizer, self).__init__(model, ax=ax, **kwargs)
204 
205         # Get the scoring method
206         if metric not in KELBOW_SCOREMAP:
207             raise YellowbrickValueError(
208                 "'{}' is not a defined metric "
209                 "use one of distortion, silhouette, or calinski_harabaz"
210             )
211 
212         # Store the arguments
213         self.scoring_metric = KELBOW_SCOREMAP[metric]
214         self.timings = timings
215 
216         # Convert K into a tuple argument if an integer
217         if isinstance(k, int):
218             k = (2, k+1)
219 
220         # Expand k in to the values we will use, capturing exceptions
221         try:
222             k = tuple(k)
223             self.k_values_ = list(range(*k))
224         except:
225             raise YellowbrickValueError((
226                 "Specify a range or maximal K value, the value '{}' "
227                 "is not a valid argument for K.".format(k)
228             ))
229 
230 
231         # Holds the values of the silhoutte scores
232         self.k_scores_ = None
233 
234     def fit(self, X, y=None, **kwargs):
235         """
236         Fits n KMeans models where n is the length of ``self.k_values_``,
237         storing the silhoutte scores in the ``self.k_scores_`` attribute.
238         This method finishes up by calling draw to create the plot.
239         """
240 
241         self.k_scores_ = []
242         self.k_timers_ = []
243 
244         for k in self.k_values_:
245             # Compute the start time for each  model
246             start = time.time()
247 
248             # Set the k value and fit the model
249             self.estimator.set_params(n_clusters=k)
250             self.estimator.fit(X)
251 
252             # Append the time and score to our plottable metrics
253             self.k_timers_.append(time.time() - start)
254             self.k_scores_.append(
255                 self.scoring_metric(X, self.estimator.labels_)
256             )
257 
258         self.draw()
259 
260         return self
261 
262     def draw(self):
263         """
264         Draw the elbow curve for the specified scores and values of K.
265         """
266         # Plot the silhouette score against k
267         self.ax.plot(self.k_values_, self.k_scores_, marker="D", label="score")
268 
269         # If we're going to plot the timings, create a twinx axis
270         if self.timings:
271             self.axes = [self.ax, self.ax.twinx()]
272             self.axes[1].plot(
273                 self.k_values_, self.k_timers_, label="fit time",
274                 c='g', marker="o", linestyle="--", alpha=0.75,
275             )
276 
277         return self.ax
278 
279     def finalize(self):
280         """
281         Prepare the figure for rendering by setting the title as well as the
282         X and Y axis labels and adding the legend.
283         """
284         # Get the metric name
285         metric = self.scoring_metric.__name__.replace("_", " ").title()
286 
287         # Set the title
288         self.set_title(
289             '{} Elbow for {} Clustering'.format(metric, self.name)
290         )
291 
292         # Set the x and y labels
293         self.ax.set_xlabel('k')
294         self.ax.set_ylabel(metric.lower())
295 
296         # Set the second y axis labels
297         if self.timings:
298             self.axes[1].grid(False)
299             self.axes[1].set_ylabel("fit time (seconds)", color='g')
300             self.axes[1].tick_params('y', colors='g')
301
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/yellowbrick/cluster/elbow.py b/yellowbrick/cluster/elbow.py
--- a/yellowbrick/cluster/elbow.py
+++ b/yellowbrick/cluster/elbow.py
@@ -125,11 +125,11 @@
 
     The elbow method runs k-means clustering on the dataset for a range of
     values for k (say from 1-10) and then for each value of k computes an
-    average score for all clusters. By default, the ``distortion_score`` is
+    average score for all clusters. By default, the ``distortion`` score is
     computed, the sum of square distances from each point to its assigned
-    center. Other metrics can also be used such as the ``silhouette_score``,
+    center. Other metrics can also be used such as the ``silhouette`` score,
     the mean silhouette  coefficient for all samples or the
-    ``calinski_harabaz_score``, which computes the ratio of dispersion between
+    ``calinski_harabaz`` score, which computes the ratio of dispersion between
     and within clusters.
 
     When these overall metrics for each model are plotted, it is possible to
@@ -186,16 +186,21 @@
 
     If you get a visualizer that doesn't have an elbow or inflection point,
     then this method may not be working. The elbow method does not work well
-    if the data is not very clustered; in this case you might see a smooth
-    curve and the value of k is unclear. Other scoring methods such as BIC or
-    SSE also can be used to explore if clustering is a correct choice.
+    if the data is not very clustered; in this case, you might see a smooth
+    curve and the value of k is unclear. Other scoring methods, such as BIC or
+    SSE, also can be used to explore if clustering is a correct choice.
 
     For a discussion on the Elbow method, read more at
     `Robert Gove's Block <https://bl.ocks.org/rpgove/0060ff3b656618e9136b>`_.
+    
+    .. seealso:: The scikit-learn documentation for the `silhouette_score
+        <https://bit.ly/2LYWjYb>`_ and `calinski_harabaz_score
+        <https://bit.ly/2LW3Zu9>`_. The default, `distortion_score`, is
+        implemented in`yellowbrick.cluster.elbow`.
 
     .. todo:: add parallelization option for performance
-    .. todo:: add different metrics for scores and silhoutte
-    .. todo:: add timing information about how long its taking
+    .. todo:: add different metrics for scores and silhouette
+    .. todo:: add timing information about how long it's taking
     """
 
     def __init__(self, model, ax=None, k=10,

{"golden_diff": "diff --git a/yellowbrick/cluster/elbow.py b/yellowbrick/cluster/elbow.py\n--- a/yellowbrick/cluster/elbow.py\n+++ b/yellowbrick/cluster/elbow.py\n@@ -125,11 +125,11 @@\n \n     The elbow method runs k-means clustering on the dataset for a range of\n     values for k (say from 1-10) and then for each value of k computes an\n-    average score for all clusters. By default, the ``distortion_score`` is\n+    average score for all clusters. By default, the ``distortion`` score is\n     computed, the sum of square distances from each point to its assigned\n-    center. Other metrics can also be used such as the ``silhouette_score``,\n+    center. Other metrics can also be used such as the ``silhouette`` score,\n     the mean silhouette  coefficient for all samples or the\n-    ``calinski_harabaz_score``, which computes the ratio of dispersion between\n+    ``calinski_harabaz`` score, which computes the ratio of dispersion between\n     and within clusters.\n \n     When these overall metrics for each model are plotted, it is possible to\n@@ -186,16 +186,21 @@\n \n     If you get a visualizer that doesn't have an elbow or inflection point,\n     then this method may not be working. The elbow method does not work well\n-    if the data is not very clustered; in this case you might see a smooth\n-    curve and the value of k is unclear. Other scoring methods such as BIC or\n-    SSE also can be used to explore if clustering is a correct choice.\n+    if the data is not very clustered; in this case, you might see a smooth\n+    curve and the value of k is unclear. Other scoring methods, such as BIC or\n+    SSE, also can be used to explore if clustering is a correct choice.\n \n     For a discussion on the Elbow method, read more at\n     `Robert Gove's Block <https://bl.ocks.org/rpgove/0060ff3b656618e9136b>`_.\n+    \n+    .. seealso:: The scikit-learn documentation for the `silhouette_score\n+        <https://bit.ly/2LYWjYb>`_ and `calinski_harabaz_score\n+        <https://bit.ly/2LW3Zu9>`_. The default, `distortion_score`, is\n+        implemented in`yellowbrick.cluster.elbow`.\n \n     .. todo:: add parallelization option for performance\n-    .. todo:: add different metrics for scores and silhoutte\n-    .. todo:: add timing information about how long its taking\n+    .. todo:: add different metrics for scores and silhouette\n+    .. todo:: add timing information about how long it's taking\n     \"\"\"\n \n     def __init__(self, model, ax=None, k=10,\n", "issue": "Incorrect parameter values in K-Elbow Visualizer docstring\nInitially in the K-Elbow Visualizer's docstring, the possible values for the parameter `metric` are named as `distortion_score`, `silhouette_score`, and `calinski_harabaz_score`. However, using these values returns the following error:\r\n\r\n`YellowbrickValueError: '{}' is not a defined metric use one of distortion, silhouette, or calinski_harabaz`\r\n\r\nHowever, the correct names&mdash;`distortion`, `silhouette`, `calinski_harabaz`&mdash;are listed corrected further down under `Parameters`.\r\n\r\n![elbow-documentation](https://user-images.githubusercontent.com/19958803/43358572-0f72b404-9262-11e8-8201-7a9ef6cd3fec.png)\r\n\n", "before_files": [{"content": "# yellowbrick.cluster.elbow\n# Implements the elbow method for determining the optimal number of clusters.\n#\n# Author:   Benjamin Bengfort <bbengfort@districtdatalabs.com>\n# Created:  Thu Mar 23 22:36:31 2017 -0400\n#\n# Copyright (C) 2016 District Data Labs\n# For license information, see LICENSE.txt\n#\n# ID: elbow.py [5a370c8] benjamin@bengfort.com $\n\n\"\"\"\nImplements the elbow method for determining the optimal number of clusters.\nhttps://bl.ocks.org/rpgove/0060ff3b656618e9136b\n\"\"\"\n\n##########################################################################\n## Imports\n##########################################################################\n\nimport time\nimport numpy as np\nimport scipy.sparse as sp\n\nfrom .base import ClusteringScoreVisualizer\nfrom ..exceptions import YellowbrickValueError\n\nfrom sklearn.metrics import silhouette_score\nfrom sklearn.metrics import calinski_harabaz_score\nfrom sklearn.metrics.pairwise import pairwise_distances\nfrom sklearn.preprocessing import LabelEncoder\n\n\n## Packages for export\n__all__ = [\n    \"KElbowVisualizer\", \"distortion_score\"\n]\n\n\n##########################################################################\n## Metrics\n##########################################################################\n\ndef distortion_score(X, labels, metric='euclidean'):\n    \"\"\"\n    Compute the mean distortion of all samples.\n\n    The distortion is computed as the the sum of the squared distances between\n    each observation and its closest centroid. Logically, this is the metric\n    that K-Means attempts to minimize as it is fitting the model.\n\n    .. seealso:: http://kldavenport.com/the-cost-function-of-k-means/\n\n    Parameters\n    ----------\n    X : array, shape = [n_samples, n_features] or [n_samples_a, n_samples_a]\n        Array of pairwise distances between samples if metric == \"precomputed\"\n        or a feature array for computing distances against the labels.\n\n    labels : array, shape = [n_samples]\n        Predicted labels for each sample\n\n    metric : string\n        The metric to use when calculating distance between instances in a\n        feature array. If metric is a string, it must be one of the options\n        allowed by `sklearn.metrics.pairwise.pairwise_distances\n        <http://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise.pairwise_distances.html#sklearn.metrics.pairwise.pairwise_distances>`_\n\n    .. todo:: add sample_size and random_state kwds similar to silhouette_score\n    \"\"\"\n    # Encode labels to get unique centers and groups\n    le = LabelEncoder()\n    labels = le.fit_transform(labels)\n    unique_labels = le.classes_\n\n    # Sum of the distortions\n    distortion = 0\n\n    # Loop through each label (center) to compute the centroid\n    for current_label in unique_labels:\n        # Mask the instances that belong to the current label\n        mask = labels == current_label\n        instances = X[mask]\n\n        # Compute the center of these instances\n        center = instances.mean(axis=0)\n\n        # NOTE: csc_matrix and csr_matrix mean returns a 2D array, numpy.mean\n        # returns an array of 1 dimension less than the input. We expect\n        # instances to be a 2D array, therefore to do pairwise computation we\n        # require center to be a 2D array with a single row (the center).\n        # See #370 for more detail.\n        if not sp.issparse(instances):\n            center = np.array([center])\n\n        # Compute the square distances from the instances to the center\n        distances = pairwise_distances(instances, center, metric=metric)\n        distances = distances ** 2\n\n        # Add the mean square distance to the distortion\n        distortion += distances.mean()\n\n    return distortion\n\n\n##########################################################################\n## Elbow Method\n##########################################################################\n\nKELBOW_SCOREMAP = {\n    \"distortion\": distortion_score,\n    \"silhouette\": silhouette_score,\n    \"calinski_harabaz\": calinski_harabaz_score,\n}\n\n\nclass KElbowVisualizer(ClusteringScoreVisualizer):\n    \"\"\"\n    The K-Elbow Visualizer implements the \"elbow\" method of selecting the\n    optimal number of clusters for K-means clustering. K-means is a simple\n    unsupervised machine learning algorithm that groups data into a specified\n    number (k) of clusters. Because the user must specify in advance what k to\n    choose, the algorithm is somewhat naive -- it assigns all members to k\n    clusters even if that is not the right k for the dataset.\n\n    The elbow method runs k-means clustering on the dataset for a range of\n    values for k (say from 1-10) and then for each value of k computes an\n    average score for all clusters. By default, the ``distortion_score`` is\n    computed, the sum of square distances from each point to its assigned\n    center. Other metrics can also be used such as the ``silhouette_score``,\n    the mean silhouette  coefficient for all samples or the\n    ``calinski_harabaz_score``, which computes the ratio of dispersion between\n    and within clusters.\n\n    When these overall metrics for each model are plotted, it is possible to\n    visually determine the best value for K. If the line chart looks like an\n    arm, then the \"elbow\" (the point of inflection on the curve) is the best\n    value of k. The \"arm\" can be either up or down, but if there is a strong\n    inflection point, it is a good indication that the underlying model fits\n    best at that point.\n\n    Parameters\n    ----------\n\n    model : a Scikit-Learn clusterer\n        Should be an instance of a clusterer, specifically ``KMeans`` or\n        ``MiniBatchKMeans``. If it is not a clusterer, an exception is raised.\n\n    ax : matplotlib Axes, default: None\n        The axes to plot the figure on. If None is passed in the current axes\n        will be used (or generated if required).\n\n    k : integer or tuple\n        The range of k to compute silhouette scores for. If a single integer\n        is specified, then will compute the range (2,k) otherwise the\n        specified range in the tuple is used.\n\n    metric : string, default: ``\"distortion\"``\n        Select the scoring metric to evaluate the clusters. The default is the\n        mean distortion, defined by the sum of squared distances between each\n        observation and its closest centroid. Other metrics include:\n\n        - **distortion**: mean sum of squared distances to centers\n        - **silhouette**: mean ratio of intra-cluster and nearest-cluster distance\n        - **calinski_harabaz**: ratio of within to between cluster dispersion\n\n    timings : bool, default: True\n        Display the fitting time per k to evaluate the amount of time required\n        to train the clustering model.\n\n    kwargs : dict\n        Keyword arguments that are passed to the base class and may influence\n        the visualization as defined in other Visualizers.\n\n    Examples\n    --------\n\n    >>> from yellowbrick.cluster import KElbowVisualizer\n    >>> from sklearn.cluster import KMeans\n    >>> model = KElbowVisualizer(KMeans(), k=10)\n    >>> model.fit(X)\n    >>> model.poof()\n\n    Notes\n    -----\n\n    If you get a visualizer that doesn't have an elbow or inflection point,\n    then this method may not be working. The elbow method does not work well\n    if the data is not very clustered; in this case you might see a smooth\n    curve and the value of k is unclear. Other scoring methods such as BIC or\n    SSE also can be used to explore if clustering is a correct choice.\n\n    For a discussion on the Elbow method, read more at\n    `Robert Gove's Block <https://bl.ocks.org/rpgove/0060ff3b656618e9136b>`_.\n\n    .. todo:: add parallelization option for performance\n    .. todo:: add different metrics for scores and silhoutte\n    .. todo:: add timing information about how long its taking\n    \"\"\"\n\n    def __init__(self, model, ax=None, k=10,\n                 metric=\"distortion\", timings=True, **kwargs):\n        super(KElbowVisualizer, self).__init__(model, ax=ax, **kwargs)\n\n        # Get the scoring method\n        if metric not in KELBOW_SCOREMAP:\n            raise YellowbrickValueError(\n                \"'{}' is not a defined metric \"\n                \"use one of distortion, silhouette, or calinski_harabaz\"\n            )\n\n        # Store the arguments\n        self.scoring_metric = KELBOW_SCOREMAP[metric]\n        self.timings = timings\n\n        # Convert K into a tuple argument if an integer\n        if isinstance(k, int):\n            k = (2, k+1)\n\n        # Expand k in to the values we will use, capturing exceptions\n        try:\n            k = tuple(k)\n            self.k_values_ = list(range(*k))\n        except:\n            raise YellowbrickValueError((\n                \"Specify a range or maximal K value, the value '{}' \"\n                \"is not a valid argument for K.\".format(k)\n            ))\n\n\n        # Holds the values of the silhoutte scores\n        self.k_scores_ = None\n\n    def fit(self, X, y=None, **kwargs):\n        \"\"\"\n        Fits n KMeans models where n is the length of ``self.k_values_``,\n        storing the silhoutte scores in the ``self.k_scores_`` attribute.\n        This method finishes up by calling draw to create the plot.\n        \"\"\"\n\n        self.k_scores_ = []\n        self.k_timers_ = []\n\n        for k in self.k_values_:\n            # Compute the start time for each  model\n            start = time.time()\n\n            # Set the k value and fit the model\n            self.estimator.set_params(n_clusters=k)\n            self.estimator.fit(X)\n\n            # Append the time and score to our plottable metrics\n            self.k_timers_.append(time.time() - start)\n            self.k_scores_.append(\n                self.scoring_metric(X, self.estimator.labels_)\n            )\n\n        self.draw()\n\n        return self\n\n    def draw(self):\n        \"\"\"\n        Draw the elbow curve for the specified scores and values of K.\n        \"\"\"\n        # Plot the silhouette score against k\n        self.ax.plot(self.k_values_, self.k_scores_, marker=\"D\", label=\"score\")\n\n        # If we're going to plot the timings, create a twinx axis\n        if self.timings:\n            self.axes = [self.ax, self.ax.twinx()]\n            self.axes[1].plot(\n                self.k_values_, self.k_timers_, label=\"fit time\",\n                c='g', marker=\"o\", linestyle=\"--\", alpha=0.75,\n            )\n\n        return self.ax\n\n    def finalize(self):\n        \"\"\"\n        Prepare the figure for rendering by setting the title as well as the\n        X and Y axis labels and adding the legend.\n        \"\"\"\n        # Get the metric name\n        metric = self.scoring_metric.__name__.replace(\"_\", \" \").title()\n\n        # Set the title\n        self.set_title(\n            '{} Elbow for {} Clustering'.format(metric, self.name)\n        )\n\n        # Set the x and y labels\n        self.ax.set_xlabel('k')\n        self.ax.set_ylabel(metric.lower())\n\n        # Set the second y axis labels\n        if self.timings:\n            self.axes[1].grid(False)\n            self.axes[1].set_ylabel(\"fit time (seconds)\", color='g')\n            self.axes[1].tick_params('y', colors='g')\n", "path": "yellowbrick/cluster/elbow.py"}], "after_files": [{"content": "# yellowbrick.cluster.elbow\n# Implements the elbow method for determining the optimal number of clusters.\n#\n# Author:   Benjamin Bengfort <bbengfort@districtdatalabs.com>\n# Created:  Thu Mar 23 22:36:31 2017 -0400\n#\n# Copyright (C) 2016 District Data Labs\n# For license information, see LICENSE.txt\n#\n# ID: elbow.py [5a370c8] benjamin@bengfort.com $\n\n\"\"\"\nImplements the elbow method for determining the optimal number of clusters.\nhttps://bl.ocks.org/rpgove/0060ff3b656618e9136b\n\"\"\"\n\n##########################################################################\n## Imports\n##########################################################################\n\nimport time\nimport numpy as np\nimport scipy.sparse as sp\n\nfrom .base import ClusteringScoreVisualizer\nfrom ..exceptions import YellowbrickValueError\n\nfrom sklearn.metrics import silhouette_score\nfrom sklearn.metrics import calinski_harabaz_score\nfrom sklearn.metrics.pairwise import pairwise_distances\nfrom sklearn.preprocessing import LabelEncoder\n\n\n## Packages for export\n__all__ = [\n    \"KElbowVisualizer\", \"distortion_score\"\n]\n\n\n##########################################################################\n## Metrics\n##########################################################################\n\ndef distortion_score(X, labels, metric='euclidean'):\n    \"\"\"\n    Compute the mean distortion of all samples.\n\n    The distortion is computed as the the sum of the squared distances between\n    each observation and its closest centroid. Logically, this is the metric\n    that K-Means attempts to minimize as it is fitting the model.\n\n    .. seealso:: http://kldavenport.com/the-cost-function-of-k-means/\n\n    Parameters\n    ----------\n    X : array, shape = [n_samples, n_features] or [n_samples_a, n_samples_a]\n        Array of pairwise distances between samples if metric == \"precomputed\"\n        or a feature array for computing distances against the labels.\n\n    labels : array, shape = [n_samples]\n        Predicted labels for each sample\n\n    metric : string\n        The metric to use when calculating distance between instances in a\n        feature array. If metric is a string, it must be one of the options\n        allowed by `sklearn.metrics.pairwise.pairwise_distances\n        <http://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise.pairwise_distances.html#sklearn.metrics.pairwise.pairwise_distances>`_\n\n    .. todo:: add sample_size and random_state kwds similar to silhouette_score\n    \"\"\"\n    # Encode labels to get unique centers and groups\n    le = LabelEncoder()\n    labels = le.fit_transform(labels)\n    unique_labels = le.classes_\n\n    # Sum of the distortions\n    distortion = 0\n\n    # Loop through each label (center) to compute the centroid\n    for current_label in unique_labels:\n        # Mask the instances that belong to the current label\n        mask = labels == current_label\n        instances = X[mask]\n\n        # Compute the center of these instances\n        center = instances.mean(axis=0)\n\n        # NOTE: csc_matrix and csr_matrix mean returns a 2D array, numpy.mean\n        # returns an array of 1 dimension less than the input. We expect\n        # instances to be a 2D array, therefore to do pairwise computation we\n        # require center to be a 2D array with a single row (the center).\n        # See #370 for more detail.\n        if not sp.issparse(instances):\n            center = np.array([center])\n\n        # Compute the square distances from the instances to the center\n        distances = pairwise_distances(instances, center, metric=metric)\n        distances = distances ** 2\n\n        # Add the mean square distance to the distortion\n        distortion += distances.mean()\n\n    return distortion\n\n\n##########################################################################\n## Elbow Method\n##########################################################################\n\nKELBOW_SCOREMAP = {\n    \"distortion\": distortion_score,\n    \"silhouette\": silhouette_score,\n    \"calinski_harabaz\": calinski_harabaz_score,\n}\n\n\nclass KElbowVisualizer(ClusteringScoreVisualizer):\n    \"\"\"\n    The K-Elbow Visualizer implements the \"elbow\" method of selecting the\n    optimal number of clusters for K-means clustering. K-means is a simple\n    unsupervised machine learning algorithm that groups data into a specified\n    number (k) of clusters. Because the user must specify in advance what k to\n    choose, the algorithm is somewhat naive -- it assigns all members to k\n    clusters even if that is not the right k for the dataset.\n\n    The elbow method runs k-means clustering on the dataset for a range of\n    values for k (say from 1-10) and then for each value of k computes an\n    average score for all clusters. By default, the ``distortion`` score is\n    computed, the sum of square distances from each point to its assigned\n    center. Other metrics can also be used such as the ``silhouette`` score,\n    the mean silhouette  coefficient for all samples or the\n    ``calinski_harabaz`` score, which computes the ratio of dispersion between\n    and within clusters.\n\n    When these overall metrics for each model are plotted, it is possible to\n    visually determine the best value for K. If the line chart looks like an\n    arm, then the \"elbow\" (the point of inflection on the curve) is the best\n    value of k. The \"arm\" can be either up or down, but if there is a strong\n    inflection point, it is a good indication that the underlying model fits\n    best at that point.\n\n    Parameters\n    ----------\n\n    model : a Scikit-Learn clusterer\n        Should be an instance of a clusterer, specifically ``KMeans`` or\n        ``MiniBatchKMeans``. If it is not a clusterer, an exception is raised.\n\n    ax : matplotlib Axes, default: None\n        The axes to plot the figure on. If None is passed in the current axes\n        will be used (or generated if required).\n\n    k : integer or tuple\n        The range of k to compute silhouette scores for. If a single integer\n        is specified, then will compute the range (2,k) otherwise the\n        specified range in the tuple is used.\n\n    metric : string, default: ``\"distortion\"``\n        Select the scoring metric to evaluate the clusters. The default is the\n        mean distortion, defined by the sum of squared distances between each\n        observation and its closest centroid. Other metrics include:\n\n        - **distortion**: mean sum of squared distances to centers\n        - **silhouette**: mean ratio of intra-cluster and nearest-cluster distance\n        - **calinski_harabaz**: ratio of within to between cluster dispersion\n\n    timings : bool, default: True\n        Display the fitting time per k to evaluate the amount of time required\n        to train the clustering model.\n\n    kwargs : dict\n        Keyword arguments that are passed to the base class and may influence\n        the visualization as defined in other Visualizers.\n\n    Examples\n    --------\n\n    >>> from yellowbrick.cluster import KElbowVisualizer\n    >>> from sklearn.cluster import KMeans\n    >>> model = KElbowVisualizer(KMeans(), k=10)\n    >>> model.fit(X)\n    >>> model.poof()\n\n    Notes\n    -----\n\n    If you get a visualizer that doesn't have an elbow or inflection point,\n    then this method may not be working. The elbow method does not work well\n    if the data is not very clustered; in this case, you might see a smooth\n    curve and the value of k is unclear. Other scoring methods, such as BIC or\n    SSE, also can be used to explore if clustering is a correct choice.\n\n    For a discussion on the Elbow method, read more at\n    `Robert Gove's Block <https://bl.ocks.org/rpgove/0060ff3b656618e9136b>`_.\n    \n    .. seealso:: The scikit-learn documentation for the `silhouette_score\n        <https://bit.ly/2LYWjYb>`_ and `calinski_harabaz_score\n        <https://bit.ly/2LW3Zu9>`_. The default, `distortion_score`, is\n        implemented in`yellowbrick.cluster.elbow`.\n\n    .. todo:: add parallelization option for performance\n    .. todo:: add different metrics for scores and silhouette\n    .. todo:: add timing information about how long it's taking\n    \"\"\"\n\n    def __init__(self, model, ax=None, k=10,\n                 metric=\"distortion\", timings=True, **kwargs):\n        super(KElbowVisualizer, self).__init__(model, ax=ax, **kwargs)\n\n        # Get the scoring method\n        if metric not in KELBOW_SCOREMAP:\n            raise YellowbrickValueError(\n                \"'{}' is not a defined metric \"\n                \"use one of distortion, silhouette, or calinski_harabaz\"\n            )\n\n        # Store the arguments\n        self.scoring_metric = KELBOW_SCOREMAP[metric]\n        self.timings = timings\n\n        # Convert K into a tuple argument if an integer\n        if isinstance(k, int):\n            k = (2, k+1)\n\n        # Expand k in to the values we will use, capturing exceptions\n        try:\n            k = tuple(k)\n            self.k_values_ = list(range(*k))\n        except:\n            raise YellowbrickValueError((\n                \"Specify a range or maximal K value, the value '{}' \"\n                \"is not a valid argument for K.\".format(k)\n            ))\n\n\n        # Holds the values of the silhoutte scores\n        self.k_scores_ = None\n\n    def fit(self, X, y=None, **kwargs):\n        \"\"\"\n        Fits n KMeans models where n is the length of ``self.k_values_``,\n        storing the silhoutte scores in the ``self.k_scores_`` attribute.\n        This method finishes up by calling draw to create the plot.\n        \"\"\"\n\n        self.k_scores_ = []\n        self.k_timers_ = []\n\n        for k in self.k_values_:\n            # Compute the start time for each  model\n            start = time.time()\n\n            # Set the k value and fit the model\n            self.estimator.set_params(n_clusters=k)\n            self.estimator.fit(X)\n\n            # Append the time and score to our plottable metrics\n            self.k_timers_.append(time.time() - start)\n            self.k_scores_.append(\n                self.scoring_metric(X, self.estimator.labels_)\n            )\n\n        self.draw()\n\n        return self\n\n    def draw(self):\n        \"\"\"\n        Draw the elbow curve for the specified scores and values of K.\n        \"\"\"\n        # Plot the silhouette score against k\n        self.ax.plot(self.k_values_, self.k_scores_, marker=\"D\", label=\"score\")\n\n        # If we're going to plot the timings, create a twinx axis\n        if self.timings:\n            self.axes = [self.ax, self.ax.twinx()]\n            self.axes[1].plot(\n                self.k_values_, self.k_timers_, label=\"fit time\",\n                c='g', marker=\"o\", linestyle=\"--\", alpha=0.75,\n            )\n\n        return self.ax\n\n    def finalize(self):\n        \"\"\"\n        Prepare the figure for rendering by setting the title as well as the\n        X and Y axis labels and adding the legend.\n        \"\"\"\n        # Get the metric name\n        metric = self.scoring_metric.__name__.replace(\"_\", \" \").title()\n\n        # Set the title\n        self.set_title(\n            '{} Elbow for {} Clustering'.format(metric, self.name)\n        )\n\n        # Set the x and y labels\n        self.ax.set_xlabel('k')\n        self.ax.set_ylabel(metric.lower())\n\n        # Set the second y axis labels\n        if self.timings:\n            self.axes[1].grid(False)\n            self.axes[1].set_ylabel(\"fit time (seconds)\", color='g')\n            self.axes[1].tick_params('y', colors='g')\n", "path": "yellowbrick/cluster/elbow.py"}]}