


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

a				:							Dict					=			'K-MEANS-CLUST/ '






def    _UpperCAmelCase	(   __lowerCamelCase ,     __lowerCamelCase ,     __lowerCamelCase=None       )		->Union[str, Any]:


 '''simple docstring'''
 if seed is not None:  # useful for obtaining consistent results
  np.random.seed(__lowerCamelCase       )
 snake_case   : int	  =      data.shape[0]  # number of data points

 # Pick K indices from range [0, N).
 snake_case   : Optional[Any]	  =      np.random.randint(0 ,     __lowerCamelCase ,     __lowerCamelCase       )

 # 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.
 snake_case   : str	  =      data[rand_indices, :]

 return centroids






def    _UpperCAmelCase	(   __lowerCamelCase ,     __lowerCamelCase       )		->Any:


 '''simple docstring'''
 return pairwise_distances(__lowerCamelCase ,     __lowerCamelCase ,     metric='''euclidean'''       )






def    _UpperCAmelCase	(   __lowerCamelCase ,     __lowerCamelCase       )		->Union[str, Any]:


 '''simple docstring'''
 # Compute distances between each data point and the set of centroids:
 # Fill in the blank (RHS only)
 snake_case   : Dict	  =      centroid_pairwise_dist(__lowerCamelCase ,     __lowerCamelCase       )

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

 return cluster_assignment






def    _UpperCAmelCase	(   __lowerCamelCase ,     __lowerCamelCase ,     __lowerCamelCase       )		->int:


 '''simple docstring'''
 snake_case   : Dict	  =      []
 for i in range(__lowerCamelCase       ):
  # Select all data points that belong to cluster i. Fill in the blank (RHS only)
  snake_case   : Dict	  =      data[cluster_assignment == i]
  # Compute the mean of the data points. Fill in the blank (RHS only)
  snake_case   : List[str]	  =      member_data_points.mean(axis=0       )
  new_centroids.append(__lowerCamelCase       )
 snake_case   : str	  =      np.array(__lowerCamelCase       )

 return new_centroids






def    _UpperCAmelCase	(   __lowerCamelCase ,     __lowerCamelCase ,     __lowerCamelCase ,     __lowerCamelCase       )		->Optional[Any]:


 '''simple docstring'''
 snake_case   : Any	  =      0.0
 for i in range(__lowerCamelCase       ):
  # Select all data points that belong to cluster i. Fill in the blank (RHS only)
  snake_case   : 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)
   snake_case   : Optional[int]	  =      pairwise_distances(
       __lowerCamelCase ,     [centroids[i]] ,     metric='''euclidean'''       )
   snake_case   : Dict	  =      distances**2
   heterogeneity += np.sum(__lowerCamelCase       )

 return heterogeneity






def    _UpperCAmelCase	(   __lowerCamelCase ,     __lowerCamelCase       )		->List[Any]:


 '''simple docstring'''
 plt.figure(figsize=(7, 4)       )
 plt.plot(__lowerCamelCase ,     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    _UpperCAmelCase	(   __lowerCamelCase ,     __lowerCamelCase ,     __lowerCamelCase ,     __lowerCamelCase=500 ,     __lowerCamelCase=None ,     __lowerCamelCase=False       )		->Optional[int]:


 '''simple docstring'''
 snake_case   : List[Any]	  =      initial_centroids[:]
 snake_case   : str	  =      None

 for itr in range(__lowerCamelCase       ):
  if verbose:
   print(__lowerCamelCase ,     end=''''''       )

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

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

  # 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:
   snake_case   : Optional[Any]	  =      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
   snake_case   : List[str]	  =      compute_heterogeneity(__lowerCamelCase ,     __lowerCamelCase ,     __lowerCamelCase ,     __lowerCamelCase       )
   record_heterogeneity.append(__lowerCamelCase       )

  snake_case   : Union[str, Any]	  =      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

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






def    _UpperCAmelCase	(   __lowerCamelCase ,     __lowerCamelCase ,     __lowerCamelCase=None       )		->pd.DataFrame:


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


if __name__ == "__main__":
  import doctest

  doctest.testmod()










import math






def    _UpperCAmelCase	(   __lowerCamelCase       )		->str:


 '''simple docstring'''
 if number == 0:
  snake_case   : str	  =      '''Zero'''
  return words
 else:
  snake_case   : List[str]	  =      math.logaa(__lowerCamelCase       )
  snake_case   : List[Any]	  =      digits + 1
  snake_case   : List[str]	  =      {}
  snake_case   : Optional[int]	  =      ''''''
  snake_case   : Union[str, Any]	  =      '''One'''
  snake_case   : str	  =      '''Two'''
  snake_case   : Dict	  =      '''Three'''
  snake_case   : Dict	  =      '''Four'''
  snake_case   : int	  =      '''Five'''
  snake_case   : Optional[Any]	  =      '''Six'''
  snake_case   : Optional[Any]	  =      '''Seven'''
  snake_case   : Tuple	  =      '''Eight'''
  snake_case   : Dict	  =      '''Nine'''

  snake_case   : Tuple	  =      {}
  snake_case   : List[str]	  =      ''''''
  snake_case   : Tuple	  =      '''Twenty'''
  snake_case   : Optional[int]	  =      '''Thirty'''
  snake_case   : Optional[Any]	  =      '''Forty'''
  snake_case   : str	  =      '''Fifty'''
  snake_case   : int	  =      '''Sixty'''
  snake_case   : Optional[int]	  =      '''Seventy'''
  snake_case   : Dict	  =      '''Eighty'''
  snake_case   : List[str]	  =      '''Ninety'''

  snake_case   : List[str]	  =      {}
  snake_case   : int	  =      '''Ten'''
  snake_case   : Union[str, Any]	  =      '''Eleven'''
  snake_case   : Dict	  =      '''Twelve'''
  snake_case   : Any	  =      '''Thirteen'''
  snake_case   : str	  =      '''Fourteen'''
  snake_case   : Optional[int]	  =      '''Fifteen'''
  snake_case   : Any	  =      '''Sixteen'''
  snake_case   : List[Any]	  =      '''Seventeen'''
  snake_case   : List[str]	  =      '''Eighteen'''
  snake_case   : Tuple	  =      '''Nineteen'''

  snake_case   : Tuple	  =      {}
  snake_case   : List[Any]	  =      '''Hundred,'''
  snake_case   : Tuple	  =      '''Thousand,'''
  snake_case   : List[Any]	  =      '''Lakh,'''
  snake_case   : Union[str, Any]	  =      '''Crore,'''

  snake_case   : int	  =      number
  snake_case   : List[Any]	  =      ''''''
  snake_case   : Optional[int]	  =      0
  snake_case   : Optional[int]	  =      int(__lowerCamelCase       )
  while counter < digits:
   snake_case   : Optional[Any]	  =      temp_num % 10
   if counter % 2 == 0:
    snake_case   : int	  =      ''''''
    if counter in placevalue and current != 0:
     snake_case   : Any	  =      placevalue[counter]
    if counter == 2:
     snake_case   : str	  =      singles[current] + addition + words
    elif counter == 0:
     if ((temp_num % 100) // 10) == 1:
      snake_case   : Tuple	  =      teens[current] + addition + words
      snake_case   : Optional[int]	  =      temp_num // 10
      counter += 1
     else:
      snake_case   : Union[str, Any]	  =      singles[current] + addition + words

    else:
     snake_case   : List[str]	  =      doubles[current] + addition + words

   else:
    if counter == 1:
     if current == 1:
      snake_case   : str	  =      teens[number % 10] + words
     else:
      snake_case   : Tuple	  =      ''''''
      if counter in placevalue:
       snake_case   : Optional[int]	  =      placevalue[counter]
      snake_case   : List[Any]	  =      doubles[current] + addition + words
    else:
     snake_case   : List[str]	  =      ''''''
     if counter in placevalue:
      if current == 0 and ((temp_num % 100) // 10) == 0:
       snake_case   : Dict	  =      ''''''
      else:
       snake_case   : List[Any]	  =      placevalue[counter]
     if ((temp_num % 100) // 10) == 1:
      snake_case   : int	  =      teens[current] + addition + words
      snake_case   : Dict	  =      temp_num // 10
      counter += 1
     else:
      snake_case   : Optional[int]	  =      singles[current] + addition + words
   counter += 1
   snake_case   : Optional[int]	  =      temp_num // 10
 return words


if __name__ == "__main__":
  import doctest

  doctest.testmod()






