



'''simple docstring'''


import warnings

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from sklearn.metrics import pairwise_distances

warnings.filterwarnings('''ignore''')

lowercase											=      '''K-MEANS-CLUST/ '''






def 			UpperCAmelCase_							(		lowercase__							,						lowercase__							,						lowercase__=None							):


     '''simple docstring'''







     if seed is not None:  # useful for obtaining consistent results
          np.random.seed(lowercase__							)
     a_									=data.shape[0]  # number of data points

     # Pick K indices from range [0, N).
     a_									=np.random.randint(0							,						lowercase__							,						lowercase__							)

     # Keep centroids as dense format, as many entries will be nonzero due to averaging.
     # As long as at least one document in a cluster contains a word,
     # it will carry a nonzero weight in the TF-IDF vector of the centroid.
     a_									=data[rand_indices, :]

     return centroids






def 			UpperCAmelCase_							(		lowercase__							,						lowercase__							):


     '''simple docstring'''







     return pairwise_distances(lowercase__							,						lowercase__							,						metric="euclidean"							)






def 			UpperCAmelCase_							(		lowercase__							,						lowercase__							):


     '''simple docstring'''







     a_									=centroid_pairwise_dist(lowercase__							,						lowercase__							)

     # Compute cluster assignments for each data point:
     # Fill in the blank (RHS only)
     a_									=np.argmin(lowercase__							,						axis=1							)

     return cluster_assignment






def 			UpperCAmelCase_							(		lowercase__							,						lowercase__							,						lowercase__							):


     '''simple docstring'''







     a_									=[]
     for i in range(lowercase__							):
          # Select all data points that belong to cluster i. Fill in the blank (RHS only)
          a_									=data[cluster_assignment == i]
          # Compute the mean of the data points. Fill in the blank (RHS only)
          a_									=member_data_points.mean(axis=0							)
          new_centroids.append(lowercase__							)
     a_									=np.array(lowercase__							)

     return new_centroids






def 			UpperCAmelCase_							(		lowercase__							,						lowercase__							,						lowercase__							,						lowercase__							):


     '''simple docstring'''







     a_									=0.0
     for i in range(lowercase__							):
          # Select all data points that belong to cluster i. Fill in the blank (RHS only)
          a_									=data[cluster_assignment == i, :]

          if member_data_points.shape[0] > 0:  # check if i-th cluster is non-empty
               # Compute distances from centroid to data points (RHS only)
               a_									=pairwise_distances(
                   lowercase__							,						[centroids[i]]							,						metric="euclidean"							)
               a_									=distances**2
               heterogeneity += np.sum(lowercase__							)

     return heterogeneity






def 			UpperCAmelCase_							(		lowercase__							,						lowercase__							):


     '''simple docstring'''







     plt.figure(figsize=(7, 4)							)
     plt.plot(lowercase__							,						linewidth=4							)
     plt.xlabel("# Iterations"							)
     plt.ylabel("Heterogeneity"							)
     plt.title(F"""Heterogeneity of clustering over time, K={k:d}"""							)
     plt.rcParams.update({"font.size": 1_6}							)
     plt.show()






def 			UpperCAmelCase_							(		lowercase__							,						lowercase__							,						lowercase__							,						lowercase__=5_0_0							,						lowercase__=None							,						lowercase__=False							):


     '''simple docstring'''







     a_									=initial_centroids[:]
     a_									=None

     for itr in range(lowercase__							):
          if verbose:
               print(lowercase__							,						end=""							)

          # 1. Make cluster assignments using nearest centroids
          a_									=assign_clusters(lowercase__							,						lowercase__							)

          # 2. Compute a new centroid for each of the k clusters, averaging all data
          #    points assigned to that cluster.
          a_									=revise_centroids(lowercase__							,						lowercase__							,						lowercase__							)

          # Check for convergence: if none of the assignments changed, stop
          if (
              prev_cluster_assignment is not None
              and (prev_cluster_assignment == cluster_assignment).all()
          ):
               break

          # Print number of new assignments
          if prev_cluster_assignment is not None:
               a_									=np.sum(prev_cluster_assignment != cluster_assignment							)
               if verbose:
                    print(
                        F"""    {num_changed:5d} elements changed their cluster assignment."""							)

        # Record heterogeneity convergence metric
          if record_heterogeneity is not None:
               # YOUR CODE HERE
               a_									=compute_heterogeneity(lowercase__							,						lowercase__							,						lowercase__							,						lowercase__							)
               record_heterogeneity.append(lowercase__							)

          a_									=cluster_assignment[:]

     return centroids, cluster_assignment


# Mock test below
if False:  # change to true to run this test case.
  from sklearn import datasets as ds

  lowercase											=      ds.load_iris()
  lowercase											=      3
  lowercase											=      []
  lowercase											=      get_initial_centroids(dataset['''data'''], k, seed=0)
  lowercase							,   lowercase											=      kmeans(
      dataset['''data'''],
      k,
      initial_centroids,
      maxiter=400,
      record_heterogeneity=heterogeneity,
      verbose=True,
  )
  plot_heterogeneity(heterogeneity, k)






def 			UpperCAmelCase_							(		lowercase__							,						lowercase__							,						lowercase__=None							):


     '''simple docstring'''







     if fill_missing_report:
          a_									=df.fillna(value=lowercase__							)
     a_									=1
     a_									=df.select_dtypes(np.number							).columns
     a_									=(
         df.groupby(["Cluster"]							)[  # construct report dataframe
             numeric_cols
         ]  # group by cluster number
         .agg(
             [
                 ("sum", np.sum),
                 ("mean_with_zeros", lambda lowercase__							: np.mean(np.nan_to_num(lowercase__							)							)),
                 ("mean_without_zeros", lambda lowercase__							: x.replace(0							,						np.NaN							).mean()),
                 (
                     "mean_25-75",
                     lambda lowercase__							: np.mean(
                         np.nan_to_num(
                             sorted(lowercase__							)[
                                 round(len(lowercase__							) * 2_5 / 1_0_0							) : round(len(lowercase__							) * 7_5 / 1_0_0							)
                             ]							)							),
                 ),
                 ("mean_with_na", np.mean),
                 ("min", lambda lowercase__							: x.min()),
                 ("5%", lambda lowercase__							: x.quantile(0.05							)),
                 ("25%", lambda lowercase__							: x.quantile(0.25							)),
                 ("50%", lambda lowercase__							: x.quantile(0.50							)),
                 ("75%", lambda lowercase__							: x.quantile(0.75							)),
                 ("95%", lambda lowercase__							: x.quantile(0.95							)),
                 ("max", lambda lowercase__							: x.max()),
                 ("count", lambda lowercase__							: x.count()),
                 ("stdev", lambda lowercase__							: x.std()),
                 ("mode", lambda lowercase__							: x.mode()[0]),
                 ("median", lambda lowercase__							: x.median()),
                 ("# > 0", lambda lowercase__							: (x > 0).sum()),
             ]							)
         .T.reset_index()
         .rename(index=lowercase__							,						columns={"level_0": "Features", "level_1": "Type"}							)
     )  # rename columns
     # calculate the size of cluster(count of clientID's)
     a_									=report[
         (report["Features"] == "dummy") & (report["Type"] == "count")
     ].copy()  # avoid SettingWithCopyWarning
     a_									=(
         "ClusterSize"  # rename created cluster df to match report column names
     )
     a_									="# of Customers"
     a_									=pd.DataFrame(
         clustersize.iloc[:, 2:].values
         / clustersize.iloc[:, 2:].values.sum()							)
     a_									="% of Customers"  # rename created cluster df to match report column names
     a_									="ClusterProportion"
     a_									=clusterproportion.columns.tolist()
     a_									=cols[-2:] + cols[:-2]
     a_									=clusterproportion[cols]  # rearrange columns to match report
     a_									=report.columns
     a_									=pd.DataFrame(
         abs(
             report[report["Type"] == "count"].iloc[:, 2:].values
             - clustersize.iloc[:, 2:].values							)							)  # generating df with count of nan values
     a_									=0
     a_									="# of nan"
     a_									=report[
         report["Type"] == "count"
     ].Features.tolist()  # filling values in order to match report
     a_									=a.columns.tolist()
     a_									=cols[-2:] + cols[:-2]
     a_									=a[cols]  # rearrange columns to match report
     a_									=report.columns  # rename columns to match report
     a_									=report.drop(
         report[report.Type == "count"].index							)  # drop count values except cluster size
     a_									=pd.concat(
         [report, a, clustersize, clusterproportion]							,						axis=0							)  # concat report with clustert size and nan values
     a_									=report["Features"].isin(lowercase__							)
     a_									=report.columns.tolist()
     a_									=cols[0:2] + cols[-1:] + cols[2:-1]
     a_									=report[cols]
     a_									={
         "ClusterSize": 9,
         "ClusterProportion": 8,
         "mean_with_zeros": 7,
         "mean_with_na": 6,
         "max": 5,
         "50%": 4,
         "min": 3,
         "25%": 2,
         "75%": 1,
         "# of nan": 0,
         "# > 0": -1,
         "sum_with_na": -2,
     }
     a_									=(
         report.assign(
             Sortera=lambda lowercase__							: x.Type.map(lowercase__							)							,						Sortera=lambda lowercase__							: list(reversed(range(len(lowercase__							)							)							)							)							,						)
         .sort_values(["Sorter1", "Mark", "Sorter2"]							,						ascending=lowercase__							)
         .drop(["Sorter1", "Sorter2"]							,						axis=1							)
     )
     a_									=""
     a_									=report.reset_index()
     a_									=report.drop(columns=["index"]							)
     return report


if __name__ == "__main__":
  import doctest

  doctest.testmod()







'''simple docstring'''


from collections import OrderedDict
from typing import Any, List, Mapping, Optional

from ... import PreTrainedTokenizer, TensorType, is_torch_available
from ...configuration_utils import PretrainedConfig
from ...onnx import OnnxConfigWithPast, PatchingSpec
from ...utils import logging


lowercase											=      logging.get_logger(__name__)

lowercase											=      {
    '''gpt2''': '''https://huggingface.co/gpt2/resolve/main/config.json''',
    '''gpt2-medium''': '''https://huggingface.co/gpt2-medium/resolve/main/config.json''',
    '''gpt2-large''': '''https://huggingface.co/gpt2-large/resolve/main/config.json''',
    '''gpt2-xl''': '''https://huggingface.co/gpt2-xl/resolve/main/config.json''',
    '''distilgpt2''': '''https://huggingface.co/distilgpt2/resolve/main/config.json''',
}







class 						UpperCAmelCase						(		__a):


 '''simple docstring'''




 __magic_name__       :			str	=   "gpt2"
 __magic_name__       :			str	=   ["past_key_values"]
 __magic_name__       :			Dict	=   {
     "hidden_size": "n_embd",
     "max_position_embeddings": "n_positions",
     "num_attention_heads": "n_head",
     "num_hidden_layers": "n_layer",
 }




 def __init__( self				,	lowerCAmelCase_=5_0_2_5_7				,	lowerCAmelCase_=1_0_2_4				,	lowerCAmelCase_=7_6_8				,	lowerCAmelCase_=1_2				,	lowerCAmelCase_=1_2				,	lowerCAmelCase_=None				,	lowerCAmelCase_="gelu_new"				,	lowerCAmelCase_=0.1				,	lowerCAmelCase_=0.1				,	lowerCAmelCase_=0.1				,	lowerCAmelCase_=1e-5				,	lowerCAmelCase_=0.0_2				,	lowerCAmelCase_="cls_index"				,	lowerCAmelCase_=True				,	lowerCAmelCase_=None				,	lowerCAmelCase_=True				,	lowerCAmelCase_=0.1				,	lowerCAmelCase_=True				,	lowerCAmelCase_=True				,	lowerCAmelCase_=5_0_2_5_6				,	lowerCAmelCase_=5_0_2_5_6				,	lowerCAmelCase_=False				,	lowerCAmelCase_=False				,	**lowerCAmelCase_				,	)			->   Dict:



      """simple docstring"""







      a_									=vocab_size
      a_									=n_positions
      a_									=n_embd
      a_									=n_layer
      a_									=n_head
      a_									=n_inner
      a_									=activation_function
      a_									=resid_pdrop
      a_									=embd_pdrop
      a_									=attn_pdrop
      a_									=layer_norm_epsilon
      a_									=initializer_range
      a_									=summary_type
      a_									=summary_use_proj
      a_									=summary_activation
      a_									=summary_first_dropout
      a_									=summary_proj_to_labels
      a_									=scale_attn_weights
      a_									=use_cache
      a_									=scale_attn_by_inverse_layer_idx
      a_									=reorder_and_upcast_attn

      a_									=bos_token_id
      a_									=eos_token_id

      super().__init__(bos_token_id=lowerCAmelCase_				,	eos_token_id=lowerCAmelCase_				,	**lowerCAmelCase_)







class 						UpperCAmelCase						(		__a):


 '''simple docstring'''




 def __init__( self				,	lowerCAmelCase_				,	lowerCAmelCase_ = "default"				,	lowerCAmelCase_ = None				,	lowerCAmelCase_ = False				,	)			->   List[str]:



      """simple docstring"""







      super().__init__(lowerCAmelCase_				,	task=lowerCAmelCase_				,	patching_specs=lowerCAmelCase_				,	use_past=lowerCAmelCase_)
      if not getattr(self._config				,	"pad_token_id"				,	lowerCAmelCase_):
           # TODO: how to do that better?
           a_									=0




 @property
 def    lowercase_	( self)			->   Mapping[str, Mapping[int, str]]:



      """simple docstring"""







      a_									=OrderedDict({"input_ids": {0: "batch", 1: "sequence"}})
      if self.use_past:
           self.fill_with_past_key_values_(lowerCAmelCase_				,	direction="inputs")
           a_									={0: "batch", 1: "past_sequence + sequence"}
      else:
           a_									={0: "batch", 1: "sequence"}

      return common_inputs




 @property
 def    lowercase_	( self)			->   int:



      """simple docstring"""







      return self._config.n_layer




 @property
 def    lowercase_	( self)			->   int:



      """simple docstring"""







      return self._config.n_head




 def    lowercase_	( self				,	lowerCAmelCase_				,	lowerCAmelCase_ = -1				,	lowerCAmelCase_ = -1				,	lowerCAmelCase_ = False				,	lowerCAmelCase_ = None				,	)			->   Mapping[str, Any]:



      """simple docstring"""







      a_									=super(lowerCAmelCase_				,	self).generate_dummy_inputs(
          lowerCAmelCase_				,	batch_size=lowerCAmelCase_				,	seq_length=lowerCAmelCase_				,	is_pair=lowerCAmelCase_				,	framework=lowerCAmelCase_)

      # We need to order the input in the way they appears in the forward()
      a_									=OrderedDict({"input_ids": common_inputs["input_ids"]})

      # Need to add the past_keys
      if self.use_past:
           if not is_torch_available():
                raise ValueError("Cannot generate dummy past_keys inputs without PyTorch installed.")
           else:
                import torch

                a_		,    a_									=common_inputs["input_ids"].shape
                # Not using the same length for past_key_values
                a_									=seqlen + 2
                a_									=(
                    batch,
                    self.num_attention_heads,
                    past_key_values_length,
                    self._config.hidden_size // self.num_attention_heads,
                )
                a_									=[
                    (torch.zeros(lowerCAmelCase_), torch.zeros(lowerCAmelCase_)) for _ in range(self.num_layers)
                ]

      a_									=common_inputs["attention_mask"]
      if self.use_past:
           a_									=ordered_inputs["attention_mask"].dtype
           a_									=torch.cat(
               [ordered_inputs["attention_mask"], torch.ones(lowerCAmelCase_				,	lowerCAmelCase_				,	dtype=lowerCAmelCase_)]				,	dim=1)

      return ordered_inputs




 @property
 def    lowercase_	( self)			->   int:



      """simple docstring"""







      return 1_3


