


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									=		'K-MEANS-CLUST/ '

def 		_UpperCAmelCase							(     SCREAMING_SNAKE_CASE__     :   Optional[Any]     ,	SCREAMING_SNAKE_CASE__     :   Optional[Any]     ,	SCREAMING_SNAKE_CASE__     :   int=None							):







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

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

     return centroids

def 		_UpperCAmelCase							(     SCREAMING_SNAKE_CASE__     :   Dict     ,	SCREAMING_SNAKE_CASE__     :   Optional[Any]							):
     return pairwise_distances(lowercase__     ,	lowercase__     ,	metric='euclidean'							)

def 		_UpperCAmelCase							(     SCREAMING_SNAKE_CASE__     :   List[str]     ,	SCREAMING_SNAKE_CASE__     :   str							):
     __UpperCamelCase       				=centroid_pairwise_dist(lowercase__     ,	lowercase__							)

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

     return cluster_assignment

def 		_UpperCAmelCase							(     SCREAMING_SNAKE_CASE__     :   Union[str, Any]     ,	SCREAMING_SNAKE_CASE__     :   List[Any]     ,	SCREAMING_SNAKE_CASE__     :   Optional[int]							):
     __UpperCamelCase       				=[]
     for i in range(lowercase__							):
          # Select all data points that belong to cluster i. Fill in the blank (RHS only)
          __UpperCamelCase       				=data[cluster_assignment == i]
          # Compute the mean of the data points. Fill in the blank (RHS only)
          __UpperCamelCase       				=member_data_points.mean(axis=0							)
          new_centroids.append(lowercase__							)
     __UpperCamelCase       				=np.array(lowercase__							)

     return new_centroids

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

     return heterogeneity

def 		_UpperCAmelCase							(     SCREAMING_SNAKE_CASE__     :   Optional[int]     ,	SCREAMING_SNAKE_CASE__     :   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 		_UpperCAmelCase							(     SCREAMING_SNAKE_CASE__     :   Optional[Any]     ,	SCREAMING_SNAKE_CASE__     :   List[str]     ,	SCREAMING_SNAKE_CASE__     :   Any     ,	SCREAMING_SNAKE_CASE__     :   Tuple=5_00     ,	SCREAMING_SNAKE_CASE__     :   Optional[Any]=None     ,	SCREAMING_SNAKE_CASE__     :   Optional[Any]=False							):
     __UpperCamelCase       				=initial_centroids[:]
     __UpperCamelCase       				=None

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

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

          # 2. Compute a new centroid for each of the k clusters, averaging all data
          #    points assigned to that cluster.
          __UpperCamelCase       				=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:
               __UpperCamelCase       				=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
               __UpperCamelCase       				=compute_heterogeneity(lowercase__     ,	lowercase__     ,	lowercase__     ,	lowercase__							)
               record_heterogeneity.append(lowercase__							)

          __UpperCamelCase       				=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									=		ds.load_iris()
   _A									=		3
   _A									=		[]
   _A									=		get_initial_centroids(dataset['data'], k, seed=0)
   _A			,	_A									=		kmeans(
       dataset['data'],
       k,
       initial_centroids,
       maxiter=400,
       record_heterogeneity=heterogeneity,
       verbose=True,
   )
   plot_heterogeneity(heterogeneity, k)

def 		_UpperCAmelCase							(     SCREAMING_SNAKE_CASE__     :   str     ,	SCREAMING_SNAKE_CASE__     :   Union[str, Any]     ,	SCREAMING_SNAKE_CASE__     :   int=None							):







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


if __name__ == "__main__":
   import doctest

   doctest.testmod()










'''simple docstring'''


lowercase											=      (1, 153, 370, 371, 1_634, 24_678_051, 115_132_219_018_763_992_565_095_597_973_971_522_401)
lowercase											=      (-153, -1, 0, 1.2, 200, "A", [], {}, None)






def 			UpperCAmelCase_							(		lowercase__							):


     '''simple docstring'''







     if not isinstance(lowercase__							,						lowercase__							) or n < 1:
          return False

     # Initialization of sum and number of digits.
     a_									=0
     a_									=0
     a_									=n
     # Calculation of digits of the number
     while temp > 0:
          number_of_digits += 1
          temp //= 1_0
     # Dividing number into separate digits and find Armstrong number
     a_									=n
     while temp > 0:
          a_									=temp % 1_0
          total += rem**number_of_digits
          temp //= 1_0
     return n == total






def 			UpperCAmelCase_							(		lowercase__							):


     '''simple docstring'''







     if not isinstance(lowercase__							,						lowercase__							) or n < 1:
          return False

     # Init a "histogram" of the digits
     a_									=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
     a_									=0
     a_									=0
     a_									=n
     while temp > 0:
          a_		,    a_									=divmod(lowercase__							,						1_0							)
          digit_histogram[rem] += 1
          digit_total += 1

     for cnt, i in zip(lowercase__							,						range(len(lowercase__							)							)							):
          total += cnt * i**digit_total

     return n == total






def 			UpperCAmelCase_							(		lowercase__							):


     '''simple docstring'''







     if not isinstance(lowercase__							,						lowercase__							) or n < 1:
          return False
     a_									=len(str(lowercase__							)							)  # the power that all digits will be raised to
     # check if sum of each digit multiplied expo times is equal to number
     return n == sum(int(lowercase__							) ** expo for i in str(lowercase__							)							)






def 			UpperCAmelCase_							(		):


     '''simple docstring'''







     a_									=int(input("Enter an integer to see if it is an Armstrong number: "							).strip()							)
     print(F"""{num} is {'' if armstrong_number(lowercase__							) else 'not '}an Armstrong number."""							)
     print(F"""{num} is {'' if narcissistic_number(lowercase__							) else 'not '}an Armstrong number."""							)
     print(F"""{num} is {'' if pluperfect_number(lowercase__							) else 'not '}an Armstrong number."""							)


if __name__ == "__main__":
  import doctest

  doctest.testmod()
  main()


