






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

__A   :							List[Any]     	=						'K-MEANS-CLUST/ '


def     _UpperCamelCase				(  snake_case__				,      snake_case__				,      snake_case__=None				):
      if seed is not None:  # useful for obtaining consistent results
            np.random.seed(snake_case__				)
      __A		 =   data.shape[0]  # number of data points

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

      # 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				(  snake_case__				,      snake_case__				):
      return pairwise_distances(snake_case__				,      snake_case__				,      metric="euclidean"				)


def     _UpperCamelCase				(  snake_case__				,      snake_case__				):
      # Compute distances between each data point and the set of centroids:
      # Fill in the blank (RHS only)
      __A		 =   centroid_pairwise_dist(snake_case__				,      snake_case__				)

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

      return cluster_assignment


def     _UpperCamelCase				(  snake_case__				,      snake_case__				,      snake_case__				):
      __A		 =   []
      for i in range(snake_case__				):
            # 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(snake_case__				)
      __A		 =   np.array(snake_case__				)

      return new_centroids


def     _UpperCamelCase				(  snake_case__				,      snake_case__				,      snake_case__				,      snake_case__				):
      __A		 =   0.0
      for i in range(snake_case__				):
            # 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(
                      snake_case__				,      [centroids[i]]				,      metric="euclidean"				)
                  __A		 =   distances**2
                  heterogeneity += np.sum(snake_case__				)

      return heterogeneity


def     _UpperCamelCase				(  snake_case__				,      snake_case__				):
      plt.figure(figsize=(7, 4)				)
      plt.plot(snake_case__				,      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				(  snake_case__				,      snake_case__				,      snake_case__				,      snake_case__=500				,      snake_case__=None				,      snake_case__=False				):
      __A		 =   initial_centroids[:]
      __A		 =   None

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

            # 1. Make cluster assignments using nearest centroids
            __A		 =   assign_clusters(snake_case__				,      snake_case__				)

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

            # 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(snake_case__				,      snake_case__				,      snake_case__				,      snake_case__				)
                  record_heterogeneity.append(snake_case__				)

            __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

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


def     _UpperCamelCase				(  snake_case__				,      snake_case__				,      snake_case__=None				):
      # Fill missing values with given rules
      if fill_missing_report:
            __A		 =   df.fillna(value=snake_case__				)
      __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 snake_case__				: np.mean(np.nan_to_num(snake_case__				)				)),
                  ("mean_without_zeros", lambda snake_case__				: x.replace(0				,      np.NaN				).mean()),
                  (
                      "mean_25-75",
                      lambda snake_case__				: np.mean(
                          np.nan_to_num(
                              sorted(snake_case__				)[
                                  round(len(snake_case__				) * 25 / 100				) : round(len(snake_case__				) * 75 / 100				)
                              ]				)				),
                  ),
                  ("mean_with_na", np.mean),
                  ("min", lambda snake_case__				: x.min()),
                  ("5%", lambda snake_case__				: x.quantile(0.05				)),
                  ("25%", lambda snake_case__				: x.quantile(0.25				)),
                  ("50%", lambda snake_case__				: x.quantile(0.50				)),
                  ("75%", lambda snake_case__				: x.quantile(0.75				)),
                  ("95%", lambda snake_case__				: x.quantile(0.95				)),
                  ("max", lambda snake_case__				: x.max()),
                  ("count", lambda snake_case__				: x.count()),
                  ("stdev", lambda snake_case__				: x.std()),
                  ("mode", lambda snake_case__				: x.mode()[0]),
                  ("median", lambda snake_case__				: x.median()),
                  ("# > 0", lambda snake_case__				: (x > 0).sum()),
              ]				)
          .T.reset_index()
          .rename(index=snake_case__				,      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(snake_case__				)
      __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 snake_case__				: x.Type.map(snake_case__				)				,      Sortera=lambda snake_case__				: list(reversed(range(len(snake_case__				)				)				)				)				,      )
          .sort_values(["Sorter1", "Mark", "Sorter2"]				,      ascending=snake_case__				)
          .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'''







import inspect
import os
import unittest

import torch

import accelerate
from accelerate import debug_launcher
from accelerate.test_utils import (
    execute_subprocess_async,
    require_cpu,
    require_multi_gpu,
    require_single_gpu,
    test_sync,
)
from accelerate.utils import patch_environment






class        a__     (      unittest.TestCase    ):
     '''simple docstring'''







     def      _UpperCamelCase (self     :						int       )	->							Optional[int]:
           __A		 =   inspect.getfile(accelerate.test_utils       )
           __A		 =   os.path.sep.join(mod_file.split(os.path.sep       )[:-1] + ["scripts", "test_sync.py"]       )






     @require_cpu
     def      _UpperCamelCase (self     :						str       )	->							Optional[Any]:
           debug_launcher(test_sync.main					,					num_processes=1       )






     @require_cpu
     def      _UpperCamelCase (self     :						Union[str, Any]       )	->							Optional[Any]:
           debug_launcher(test_sync.main       )






     @require_single_gpu
     def      _UpperCamelCase (self     :						Union[str, Any]       )	->							List[str]:
           test_sync.main()






     @require_multi_gpu
     def      _UpperCamelCase (self     :						Optional[int]       )	->							List[str]:
           print(f"Found {torch.cuda.device_count()} devices."       )
           __A		 =   ["torchrun", f"--nproc_per_node={torch.cuda.device_count()}", self.test_file_path]
           with patch_environment(omp_num_threads=1       ):
                 execute_subprocess_async(lowercase__					,					env=os.environ.copy()       )


