






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

UpperCamelCase			=      """K-MEANS-CLUST/ """






def     A(  snake_case_						,       snake_case_						,       snake_case_=None		):
       """simple docstring"""





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

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

       return centroids






def     A(  snake_case_						,       snake_case_		):
       """simple docstring"""





       return pairwise_distances(snake_case_						,       snake_case_						,       metric="euclidean"		)






def     A(  snake_case_						,       snake_case_		):
       """simple docstring"""





       lowercase__:    Optional[Any]        =      centroid_pairwise_dist(snake_case_						,       snake_case_		)

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

       return cluster_assignment






def     A(  snake_case_						,       snake_case_						,       snake_case_		):
       """simple docstring"""





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

       return new_centroids






def     A(  snake_case_						,       snake_case_						,       snake_case_						,       snake_case_		):
       """simple docstring"""





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

       return heterogeneity






def     A(  snake_case_						,       snake_case_		):
       """simple docstring"""





       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     A(  snake_case_						,       snake_case_						,       snake_case_						,       snake_case_=500						,       snake_case_=None						,       snake_case_=False		):
       """simple docstring"""





       lowercase__:    Tuple        =      initial_centroids[:]
       lowercase__:    Dict        =      None

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

              # 1. Make cluster assignments using nearest centroids
              lowercase__:    Any        =      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.
              lowercase__:    Any        =      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:
                     lowercase__:    Tuple        =      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__:    Dict        =      compute_heterogeneity(snake_case_						,       snake_case_						,       snake_case_						,       snake_case_		)
                     record_heterogeneity.append(snake_case_		)

              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

  UpperCamelCase			=      ds.load_iris()
  UpperCamelCase			=      3
  UpperCamelCase			=      []
  UpperCamelCase			=      get_initial_centroids(dataset["""data"""], k, seed=0)
  UpperCamelCase,      UpperCamelCase			=      kmeans(
      dataset["""data"""],
      k,
      initial_centroids,
      maxiter=4_00,
      record_heterogeneity=heterogeneity,
      verbose=True,
  )
  plot_heterogeneity(heterogeneity, k)






def     A(  snake_case_						,       snake_case_						,       snake_case_=None		):
       """simple docstring"""





       if fill_missing_report:
              lowercase__:    Optional[Any]        =      df.fillna(value=snake_case_		)
       lowercase__:    Optional[int]        =      1
       lowercase__:    Dict        =      df.select_dtypes(np.number		).columns
       lowercase__:    Optional[Any]        =      (
           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)
       lowercase__:    Optional[Any]        =      report[
           (report["Features"] == "dummy") & (report["Type"] == "count")
       ].copy()  # avoid SettingWithCopyWarning
       lowercase__:    Optional[Any]        =      (
           "ClusterSize"  # rename created cluster df to match report column names
       )
       lowercase__:    Tuple        =      "# of Customers"
       lowercase__:    Tuple        =      pd.DataFrame(
           clustersize.iloc[:, 2:].values
           / clustersize.iloc[:, 2:].values.sum()		)
       lowercase__:    Any        =      "% of Customers"  # rename created cluster df to match report column names
       lowercase__:    List[str]        =      "ClusterProportion"
       lowercase__:    Optional[int]        =      clusterproportion.columns.tolist()
       lowercase__:    Dict        =      cols[-2:] + cols[:-2]
       lowercase__:    Optional[Any]        =      clusterproportion[cols]  # rearrange columns to match report
       lowercase__:    str        =      report.columns
       lowercase__:    Tuple        =      pd.DataFrame(
           abs(
               report[report["Type"] == "count"].iloc[:, 2:].values
               - clustersize.iloc[:, 2:].values		)		)  # generating df with count of nan values
       lowercase__:    str        =      0
       lowercase__:    Union[str, Any]        =      "# of nan"
       lowercase__:    Optional[int]        =      report[
           report["Type"] == "count"
       ].Features.tolist()  # filling values in order to match report
       lowercase__:    List[str]        =      a.columns.tolist()
       lowercase__:    List[Any]        =      cols[-2:] + cols[:-2]
       lowercase__:    Dict        =      a[cols]  # rearrange columns to match report
       lowercase__:    Tuple        =      report.columns  # rename columns to match report
       lowercase__:    Optional[Any]        =      report.drop(
           report[report.Type == "count"].index		)  # drop count values except cluster size
       lowercase__:    Optional[int]        =      pd.concat(
           [report, a, clustersize, clusterproportion]						,       axis=0		)  # concat report with clustert size and nan values
       lowercase__:    Tuple        =      report["Features"].isin(snake_case_		)
       lowercase__:    Any        =      report.columns.tolist()
       lowercase__:    List[str]        =      cols[0:2] + cols[-1:] + cols[2:-1]
       lowercase__:    Any        =      report[cols]
       lowercase__:    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__:    str        =      (
           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		)
       )
       lowercase__:    Dict        =      ""
       lowercase__:    int        =      report.reset_index()
       lowercase__:    List[Any]        =      report.drop(columns=["index"]		)
       return report


if __name__ == "__main__":
  import doctest

  doctest.testmod()














"""simple docstring"""





import warnings
from collections.abc import Callable
from typing import Any

import numpy
from matplotlib import pyplot

UpperCamelCase			=      0.25 + 0.0j
UpperCamelCase			=      -0.4 + 0.6j
UpperCamelCase			=      -0.1 + 0.651j
UpperCamelCase			=      -2.0
UpperCamelCase			=      56
UpperCamelCase			=      2.0
UpperCamelCase			=      6_66






def     A(  snake_case_						,       snake_case_		):
       """simple docstring"""





       return numpy.exp(snake_case_		) + c_parameter






def     A(  snake_case_						,       snake_case_		):
       """simple docstring"""





       return z_values * z_values + c_parameter






def     A(  snake_case_						,       snake_case_		):
       """simple docstring"""





       lowercase__:    str        =      numpy.linspace(-window_size						,       snake_case_						,       snake_case_		)
       lowercase__:    Union[str, Any]        =      x.reshape((nb_pixels, 1)		)
       lowercase__:    Any        =      numpy.linspace(-window_size						,       snake_case_						,       snake_case_		)
       lowercase__:    List[Any]        =      y.reshape((1, nb_pixels)		)
       return x + 1.0J * y






def     A(  snake_case_						,       snake_case_						,       snake_case_						,       snake_case_						,       snake_case_ = None						,       ):
       """simple docstring"""





       lowercase__:    List[Any]        =      z_a.astype("complex64"		)
       for _ in range(snake_case_		):
              lowercase__:    Any        =      eval_function(snake_case_						,       snake_case_		)
              if infinity is not None:
                     numpy.nan_to_num(snake_case_						,       copy=snake_case_						,       nan=snake_case_		)
                     lowercase__:    Union[str, Any]        =      infinity
       return z_n






def     A(  snake_case_						,       snake_case_						,       snake_case_						,       snake_case_						,       ):
       """simple docstring"""





       lowercase__:    Union[str, Any]        =      (abs(snake_case_		)).transpose()
       lowercase__:    List[Any]        =      abs_z_final[::-1, :]
       pyplot.matshow(abs_z_final < escape_radius		)
       pyplot.title(F"""Julia set of ${function_label}$, $c={function_params}$"""		)
       pyplot.show()






def     A(  ):
       """simple docstring"""





       warnings.filterwarnings(
           "ignore"						,       category=snake_case_						,       message="overflow encountered in multiply"		)
       warnings.filterwarnings(
           "ignore"						,       category=snake_case_						,       message="invalid value encountered in multiply"						,       )
       warnings.filterwarnings(
           "ignore"						,       category=snake_case_						,       message="overflow encountered in absolute"		)
       warnings.filterwarnings(
           "ignore"						,       category=snake_case_						,       message="overflow encountered in exp"		)


if __name__ == "__main__":
  UpperCamelCase			=      prepare_grid(window_size, nb_pixels)

  ignore_overflow_warnings()  # See file header for explanations

  UpperCamelCase			=      24
  UpperCamelCase			=      2 * abs(c_cauliflower) + 1
  UpperCamelCase			=      iterate_function(
      eval_quadratic_polynomial,
      c_cauliflower,
      nb_iterations,
      z_a,
      infinity=1.1 * escape_radius,
  )
  show_results("""z^2+c""", c_cauliflower, escape_radius, z_final)

  UpperCamelCase			=      64
  UpperCamelCase			=      2 * abs(c_polynomial_a) + 1
  UpperCamelCase			=      iterate_function(
      eval_quadratic_polynomial,
      c_polynomial_a,
      nb_iterations,
      z_a,
      infinity=1.1 * escape_radius,
  )
  show_results("""z^2+c""", c_polynomial_a, escape_radius, z_final)

  UpperCamelCase			=      1_61
  UpperCamelCase			=      2 * abs(c_polynomial_a) + 1
  UpperCamelCase			=      iterate_function(
      eval_quadratic_polynomial,
      c_polynomial_a,
      nb_iterations,
      z_a,
      infinity=1.1 * escape_radius,
  )
  show_results("""z^2+c""", c_polynomial_a, escape_radius, z_final)

  UpperCamelCase			=      12
  UpperCamelCase			=      10_000.0
  UpperCamelCase			=      iterate_function(
      eval_exponential,
      c_exponential,
      nb_iterations,
      z_a + 2,
      infinity=1.0e10,
  )
  show_results("""e^z+c""", c_exponential, escape_radius, z_final)






