





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   (     a,  a,  a=None)			->Optional[Any]:



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

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

					return centroids





def  __UpperCamelCase   (     a,  a)			->List[str]:
					return pairwise_distances(__lowerCamelCase,  __lowerCamelCase,  metric="euclidean")





def  __UpperCamelCase   (     a,  a)			->int:
					lowerCamelCase__      =							centroid_pairwise_dist(__lowerCamelCase,  __lowerCamelCase)

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

					return cluster_assignment





def  __UpperCamelCase   (     a,  a,  a)			->int:
					lowerCamelCase__      =							[]
					for i in range(__lowerCamelCase):
										# Select all data points that belong to cluster i. Fill in the blank (RHS only)
										lowerCamelCase__      =							data[cluster_assignment == i]
										# Compute the mean of the data points. Fill in the blank (RHS only)
										lowerCamelCase__      =							member_data_points.mean(axis=0)
										new_centroids.append(__lowerCamelCase)
					lowerCamelCase__      =							np.array(__lowerCamelCase)

					return new_centroids





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

					return heterogeneity





def  __UpperCamelCase   (     a,  a)			->Dict:
					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   (     a,  a,  a,  a=500,  a=None,  a=False)			->Any:
					lowerCamelCase__      =							initial_centroids[:]
					lowerCamelCase__      =							None

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

										# 1. Make cluster assignments using nearest centroids
										lowerCamelCase__      =							assign_clusters(__lowerCamelCase,  __lowerCamelCase)

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

										lowerCamelCase__      =							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=4_0_0,
						    record_heterogeneity=heterogeneity,
						    verbose=True,
						)
						plot_heterogeneity(heterogeneity, k)





def  __UpperCamelCase   (     a,  a,  a=None)			->List[Any]:



					if fill_missing_report:
										lowerCamelCase__      =							df.fillna(value=__lowerCamelCase)
					lowerCamelCase__      =							1
					lowerCamelCase__      =							df.select_dtypes(np.number).columns
					lowerCamelCase__      =							(
					    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(__lowerCamelCase))),
					            ("mean_without_zeros", lambda a: x.replace(0,  np.NaN).mean()),
					            (
					                "mean_25-75",
					                lambda a: 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 a: x.min()),
					            ("5%", lambda a: x.quantile(0.0_5)),
					            ("25%", lambda a: x.quantile(0.2_5)),
					            ("50%", lambda a: x.quantile(0.5_0)),
					            ("75%", lambda a: x.quantile(0.7_5)),
					            ("95%", lambda a: x.quantile(0.9_5)),
					            ("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=__lowerCamelCase,  columns={"level_0": "Features", "level_1": "Type"})
					)  # rename columns
					# calculate the size of cluster(count of clientID's)
					lowerCamelCase__      =							report[
					    (report["Features"] == "dummy") & (report["Type"] == "count")
					].copy()  # avoid SettingWithCopyWarning
					lowerCamelCase__      =							(
					    "ClusterSize"  # rename created cluster df to match report column names
					)
					lowerCamelCase__      =							"# of Customers"
					lowerCamelCase__      =							pd.DataFrame(
					    clustersize.iloc[:, 2:].values
					    / clustersize.iloc[:, 2:].values.sum())
					lowerCamelCase__      =							"% of Customers"  # rename created cluster df to match report column names
					lowerCamelCase__      =							"ClusterProportion"
					lowerCamelCase__      =							clusterproportion.columns.tolist()
					lowerCamelCase__      =							cols[-2:] + cols[:-2]
					lowerCamelCase__      =							clusterproportion[cols]  # rearrange columns to match report
					lowerCamelCase__      =							report.columns
					lowerCamelCase__      =							pd.DataFrame(
					    abs(
					        report[report["Type"] == "count"].iloc[:, 2:].values
					        - clustersize.iloc[:, 2:].values))  # generating df with count of nan values
					lowerCamelCase__      =							0
					lowerCamelCase__      =							"# of nan"
					lowerCamelCase__      =							report[
					    report["Type"] == "count"
					].Features.tolist()  # filling values in order to match report
					lowerCamelCase__      =							a.columns.tolist()
					lowerCamelCase__      =							cols[-2:] + cols[:-2]
					lowerCamelCase__      =							a[cols]  # rearrange columns to match report
					lowerCamelCase__      =							report.columns  # rename columns to match report
					lowerCamelCase__      =							report.drop(
					    report[report.Type == "count"].index)  # drop count values except cluster size
					lowerCamelCase__      =							pd.concat(
					    [report, a, clustersize, clusterproportion],  axis=0)  # concat report with clustert size and nan values
					lowerCamelCase__      =							report["Features"].isin(__lowerCamelCase)
					lowerCamelCase__      =							report.columns.tolist()
					lowerCamelCase__      =							cols[0:2] + cols[-1:] + cols[2:-1]
					lowerCamelCase__      =							report[cols]
					lowerCamelCase__      =							{
					    "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,
					}
					lowerCamelCase__      =							(
					    report.assign(
					        Sortera=lambda a: x.Type.map(__lowerCamelCase),  Sortera=lambda a: list(reversed(range(len(__lowerCamelCase)))),  )
					    .sort_values(["Sorter1", "Mark", "Sorter2"],  ascending=__lowerCamelCase)
					    .drop(["Sorter1", "Sorter2"],  axis=1)
					)
					lowerCamelCase__      =							""
					lowerCamelCase__      =							report.reset_index()
					lowerCamelCase__      =							report.drop(columns=["index"])
					return report


if __name__ == "__main__":
						import doctest

						doctest.testmod()





from __future__ import annotations

from random import randrange




def SCREAMING_SNAKE_CASE_  (				__lowerCamelCase:		list  ):







	'''simple docstring'''



	if len(__lowerCamelCase  ) < 2:
		return collection
	lowercase_			 = randrange(len(__lowerCamelCase  )  )  # Use random element as pivot
	lowercase_			 = collection[pivot_index]
	lowercase_			 = []  # All elements greater than pivot
	lowercase_			 = []  # All elements less than or equal to pivot

	for element in collection[:pivot_index]:
		(greater if element > pivot else lesser).append(__lowerCamelCase  )

	for element in collection[pivot_index + 1 :]:
		(greater if element > pivot else lesser).append(__lowerCamelCase  )

	return [*quick_sort(__lowerCamelCase  ), pivot, *quick_sort(__lowerCamelCase  )]


if __name__ == "__main__":
							SCREAMING_SNAKE_CASE__       			=				input("""Enter numbers separated by a comma:\n""").strip()
							SCREAMING_SNAKE_CASE__       			=				[int(item) for item in user_input.split(""",""")]
							print(quick_sort(unsorted))

