





"""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")

lowerCAmelCase:	Optional[Any]							      ="K-MEANS-CLUST/ "




def 			__snake_case						(      __A ,__A ,__A=None    )		->				Dict:
   if seed is not None:  # useful for obtaining consistent results
      np.random.seed(lowercase_    )
   lowercase    :			Dict  =       data.shape[0]  # number of data points

   # Pick K indices from range [0, N).
   lowercase    :			List[str]  =       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.
   lowercase    :			str  =       data[rand_indices, :]

   return centroids




def 			__snake_case						(      __A ,__A    )		->				Dict:
   return pairwise_distances(lowercase_ ,lowercase_ ,metric="""euclidean"""    )




def 			__snake_case						(      __A ,__A    )		->				Tuple:
   # Compute distances between each data point and the set of centroids:
   # Fill in the blank (RHS only)
   lowercase    :			Optional[int]  =       centroid_pairwise_dist(lowercase_ ,lowercase_    )

   # Compute cluster assignments for each data point:
   # Fill in the blank (RHS only)
   lowercase    :			Optional[Any]  =       np.argmin(lowercase_ ,axis=1    )

   return cluster_assignment




def 			__snake_case						(      __A ,__A ,__A    )		->				str:
   lowercase    :			Dict  =       []
   for i in range(lowercase_    ):
      # Select all data points that belong to cluster i. Fill in the blank (RHS only)
      lowercase    :			str  =       data[cluster_assignment == i]
      # Compute the mean of the data points. Fill in the blank (RHS only)
      lowercase    :			Optional[int]  =       member_data_points.mean(axis=0    )
      new_centroids.append(lowercase_    )
   lowercase    :			Tuple  =       np.array(lowercase_    )

   return new_centroids




def 			__snake_case						(      __A ,__A ,__A ,__A    )		->				List[Any]:
   lowercase    :			Dict  =       0.0
   for i in range(lowercase_    ):
      # Select all data points that belong to cluster i. Fill in the blank (RHS only)
      lowercase    :			Union[str, Any]  =       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)
         lowercase    :			Tuple  =       pairwise_distances(
             lowercase_ ,[centroids[i]] ,metric="""euclidean"""    )
         lowercase    :			str  =       distances**2
         heterogeneity += np.sum(lowercase_    )

   return heterogeneity




def 			__snake_case						(      __A ,__A    )		->				List[Any]:
   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""": 16}    )
   plt.show()




def 			__snake_case						(      __A ,__A ,__A ,__A=500 ,__A=None ,__A=False    )		->				Any:
   lowercase    :			List[Any]  =       initial_centroids[:]
   lowercase    :			List[str]  =       None

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

      # 1. Make cluster assignments using nearest centroids
      lowercase    :			Dict  =       assign_clusters(lowercase_ ,lowercase_    )

      # 2. Compute a new centroid for each of the k clusters, averaging all data
      #    points assigned to that cluster.
      lowercase    :			Tuple  =       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:
         lowercase    :			Dict  =       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
         lowercase    :			Optional[Any]  =       compute_heterogeneity(lowercase_ ,lowercase_ ,lowercase_ ,lowercase_    )
         record_heterogeneity.append(lowercase_    )

      lowercase    :			List[str]  =       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

   lowerCAmelCase:	Dict							      =ds.load_iris()
   lowerCAmelCase:	Any							      =3
   lowerCAmelCase:	int							      =[]
   lowerCAmelCase:	List[Any]							      =get_initial_centroids(dataset["data"], k, seed=0)
   lowerCAmelCase      ,						lowerCAmelCase:	Union[str, Any]							      =kmeans(
       dataset["data"],
       k,
       initial_centroids,
       maxiter=400,
       record_heterogeneity=heterogeneity,
       verbose=True,
   )
   plot_heterogeneity(heterogeneity, k)




def 			__snake_case						(      __A ,__A ,__A=None    )		->				pd.DataFrame:
   # Fill missing values with given rules
   if fill_missing_report:
      lowercase    :			Tuple  =       df.fillna(value=lowercase_    )
   lowercase    :			Tuple  =       1
   lowercase    :			Dict  =       df.select_dtypes(np.number    ).columns
   lowercase    :			int  =       (
       df.groupby(["""Cluster"""]    )[  # construct report dataframe
           numeric_cols
       ]  # group by cluster number
       .agg(
           [
               ("""sum""", np.sum),
               ("""mean_with_zeros""", lambda __A    : np.mean(np.nan_to_num(lowercase_    )    )),
               ("""mean_without_zeros""", lambda __A    : x.replace(0 ,np.NaN    ).mean()),
               (
                   """mean_25-75""",
                   lambda __A    : np.mean(
                       np.nan_to_num(
                           sorted(lowercase_    )[
                               round(len(lowercase_    ) * 25 / 100    ) : round(len(lowercase_    ) * 75 / 100    )
                           ]    )    ),
               ),
               ("""mean_with_na""", np.mean),
               ("""min""", lambda __A    : x.min()),
               ("""5%""", lambda __A    : x.quantile(0.05    )),
               ("""25%""", lambda __A    : x.quantile(0.25    )),
               ("""50%""", lambda __A    : x.quantile(0.50    )),
               ("""75%""", lambda __A    : x.quantile(0.75    )),
               ("""95%""", lambda __A    : x.quantile(0.95    )),
               ("""max""", lambda __A    : x.max()),
               ("""count""", lambda __A    : x.count()),
               ("""stdev""", lambda __A    : x.std()),
               ("""mode""", lambda __A    : x.mode()[0]),
               ("""median""", lambda __A    : x.median()),
               ("""# > 0""", lambda __A    : (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)
   lowercase    :			Dict  =       report[
       (report['''Features'''] == '''dummy''') & (report['''Type'''] == '''count''')
   ].copy()  # avoid SettingWithCopyWarning
   lowercase    :			List[str]  =       (
       '''ClusterSize'''  # rename created cluster df to match report column names
   )
   lowercase    :			Optional[Any]  =       '''# of Customers'''
   lowercase    :			str  =       pd.DataFrame(
       clustersize.iloc[:, 2:].values
       / clustersize.iloc[:, 2:].values.sum()    )
   lowercase    :			Tuple  =       '''% of Customers'''  # rename created cluster df to match report column names
   lowercase    :			Tuple  =       '''ClusterProportion'''
   lowercase    :			List[Any]  =       clusterproportion.columns.tolist()
   lowercase    :			Dict  =       cols[-2:] + cols[:-2]
   lowercase    :			Union[str, Any]  =       clusterproportion[cols]  # rearrange columns to match report
   lowercase    :			Dict  =       report.columns
   lowercase    :			Optional[Any]  =       pd.DataFrame(
       abs(
           report[report["""Type"""] == """count"""].iloc[:, 2:].values
           - clustersize.iloc[:, 2:].values    )    )  # generating df with count of nan values
   lowercase    :			List[str]  =       0
   lowercase    :			int  =       '''# of nan'''
   lowercase    :			List[str]  =       report[
       report['''Type'''] == '''count'''
   ].Features.tolist()  # filling values in order to match report
   lowercase    :			Tuple  =       a.columns.tolist()
   lowercase    :			List[str]  =       cols[-2:] + cols[:-2]
   lowercase    :			List[Any]  =       a[cols]  # rearrange columns to match report
   lowercase    :			Dict  =       report.columns  # rename columns to match report
   lowercase    :			Optional[int]  =       report.drop(
       report[report.Type == """count"""].index    )  # drop count values except cluster size
   lowercase    :			List[str]  =       pd.concat(
       [report, a, clustersize, clusterproportion] ,axis=0    )  # concat report with clustert size and nan values
   lowercase    :			List[Any]  =       report['''Features'''].isin(lowercase_    )
   lowercase    :			Tuple  =       report.columns.tolist()
   lowercase    :			Any  =       cols[0:2] + cols[-1:] + cols[2:-1]
   lowercase    :			List[str]  =       report[cols]
   lowercase    :			List[Any]  =       {
       '''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,
   }
   lowercase    :			Optional[Any]  =       (
       report.assign(
           Sortera=lambda __A    : x.Type.map(lowercase_    ) ,Sortera=lambda __A    : list(reversed(range(len(lowercase_    )    )    )    ) ,)
       .sort_values(["""Sorter1""", """Mark""", """Sorter2"""] ,ascending=lowercase_    )
       .drop(["""Sorter1""", """Sorter2"""] ,axis=1    )
   )
   lowercase    :			Tuple  =       ''''''
   lowercase    :			List[str]  =       report.reset_index()
   lowercase    :			List[str]  =       report.drop(columns=["""index"""]    )
   return report


if __name__ == "__main__":
   import doctest

   doctest.testmod()









"""simple docstring"""
import torch.nn as nn

from .imports import is_fpa_available


if is_fpa_available():
   import transformer_engine.pytorch as te




def 			__snake_case						(      __A ,__A=True ,__A=True ,__A=True    )		->				Union[str, Any]:
   if not is_fpa_available():
      raise ImportError("""Using `convert_model` requires transformer_engine to be installed."""    )
   for name, module in model.named_children():
      if isinstance(__A ,nn.Linear    ) and to_transformer_engine and _convert_linear:
         # Return early if the linear layer weights are not multiples of 16
         if any(p % 16 != 0 for p in module.weight.shape    ):
            return
         lowercase    :			Optional[int]  =       module.bias is not None
         lowercase    :			Union[str, Any]  =       te.Linear(
             module.in_features ,module.out_features ,bias=__A ,params_dtype=module.weight.dtype    )
         lowercase    :			Union[str, Any]  =       module.weight.data.clone()
         if has_bias:
            lowercase    :			Dict  =       module.bias.data.clone()

         setattr(__A ,__A ,__A    )
      elif isinstance(__A ,nn.LayerNorm    ) and to_transformer_engine and _convert_ln:
         lowercase    :			List[str]  =       te.LayerNorm(module.normalized_shape[0] ,eps=module.eps ,params_dtype=module.weight.dtype    )
         lowercase    :			Optional[Any]  =       module.weight.data.clone()
         lowercase    :			Any  =       module.bias.data.clone()

         setattr(__A ,__A ,__A    )
      elif isinstance(__A ,te.Linear    ) and not to_transformer_engine and _convert_linear:
         lowercase    :			Any  =       module.bias is not None
         lowercase    :			List[Any]  =       nn.Linear(
             module.in_features ,module.out_features ,bias=__A ,params_dtype=module.weight.dtype    )
         lowercase    :			Union[str, Any]  =       module.weight.data.clone()
         if has_bias:
            lowercase    :			Optional[Any]  =       module.bias.data.clone()

         setattr(__A ,__A ,__A    )
      elif isinstance(__A ,te.LayerNorm    ) and not to_transformer_engine and _convert_ln:
         lowercase    :			Any  =       nn.LayerNorm(module.normalized_shape[0] ,eps=module.eps ,params_dtype=module.weight.dtype    )
         lowercase    :			str  =       module.weight.data.clone()
         lowercase    :			List[str]  =       module.bias.data.clone()

         setattr(__A ,__A ,__A    )
      else:
         convert_model(
             __A ,to_transformer_engine=__A ,_convert_linear=_convert_linear ,_convert_ln=_convert_ln ,)







def 			__snake_case						(      __A    )		->				Union[str, Any]:
   if not is_fpa_available():
      raise ImportError("""Using `has_transformer_engine_layers` requires transformer_engine to be installed."""    )
   for m in model.modules():
      if isinstance(__A ,(te.LayerNorm, te.Linear)    ):
         return True
   return False


