code: 
  '''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 	_UpperCAmelCase				(  _lowerCamelCase						:       List[str]  ,      _lowerCamelCase						:       Dict  ,      _lowerCamelCase						:       Any=None		)    ->						List[str]:
    if seed is not None:  # useful for obtaining consistent results
      np.random.seed(__lowerCamelCase		)
    _lowerCAmelCase       :  int   				=					data.shape[0]  # number of data points
  
    # Pick K indices from range [0, N).
    _lowerCAmelCase       :  str   				=					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       :  Optional[int]   				=					data[rand_indices, :]
  
    return centroids
  
  
  def 	_UpperCAmelCase				(  _lowerCamelCase						:       List[Any]  ,      _lowerCamelCase						:       Optional[int]		)    ->						Optional[int]:
    return pairwise_distances(__lowerCamelCase  ,      __lowerCamelCase  ,      metric="""euclidean"""		)
  
  
  def 	_UpperCAmelCase				(  _lowerCamelCase						:       Union[str, Any]  ,      _lowerCamelCase						:       Optional[Any]		)    ->						str:
    _lowerCAmelCase       :  Optional[Any]   				=					centroid_pairwise_dist(__lowerCamelCase  ,      __lowerCamelCase		)
  
    # Compute cluster assignments for each data point:
    # Fill in the blank (RHS only)
    _lowerCAmelCase       :  str   				=					np.argmin(__lowerCamelCase  ,      axis=1		)
  
    return cluster_assignment
  
  
  def 	_UpperCAmelCase				(  _lowerCamelCase						:       Tuple  ,      _lowerCamelCase						:       Dict  ,      _lowerCamelCase						:       Optional[int]		)    ->						Optional[Any]:
    _lowerCAmelCase       :  Any   				=					[]
    for i in range(__lowerCamelCase		):
      # Select all data points that belong to cluster i. Fill in the blank (RHS only)
      _lowerCAmelCase       :  Any   				=					data[cluster_assignment == i]
      # Compute the mean of the data points. Fill in the blank (RHS only)
      _lowerCAmelCase       :  List[str]   				=					member_data_points.mean(axis=0		)
      new_centroids.append(__lowerCamelCase		)
    _lowerCAmelCase       :  str   				=					np.array(__lowerCamelCase		)
  
    return new_centroids
  
  
  def 	_UpperCAmelCase				(  _lowerCamelCase						:       Any  ,      _lowerCamelCase						:       Any  ,      _lowerCamelCase						:       Dict  ,      _lowerCamelCase						:       Union[str, Any]		)    ->						List[str]:
    _lowerCAmelCase       :  Tuple   				=					0.0
    for i in range(__lowerCamelCase		):
      # Select all data points that belong to cluster i. Fill in the blank (RHS only)
      _lowerCAmelCase       :  int   				=					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       :  Dict   				=					pairwise_distances(
            __lowerCamelCase  ,      [centroids[i]]  ,      metric="""euclidean"""		)
        _lowerCAmelCase       :  Optional[Any]   				=					distances**2
        heterogeneity += np.sum(__lowerCamelCase		)
  
    return heterogeneity
  
  
  def 	_UpperCAmelCase				(  _lowerCamelCase						:       List[str]  ,      _lowerCamelCase						:       Union[str, Any]		)    ->						Optional[Any]:
    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						:       List[Any]  ,      _lowerCamelCase						:       List[str]  ,      _lowerCamelCase						:       Dict  ,      _lowerCamelCase						:       int=5_00  ,      _lowerCamelCase						:       Optional[int]=None  ,      _lowerCamelCase						:       int=False		)    ->						Union[str, Any]:
    _lowerCAmelCase       :  Tuple   				=					initial_centroids[:]
    _lowerCAmelCase       :  Union[str, Any]   				=					None
  
    for itr in range(__lowerCamelCase		):
      if verbose:
        print(__lowerCamelCase  ,      end=""""""		)
  
      # 1. Make cluster assignments using nearest centroids
      _lowerCAmelCase       :  Optional[int]   				=					assign_clusters(__lowerCamelCase  ,      __lowerCamelCase		)
  
      # 2. Compute a new centroid for each of the k clusters, averaging all data
      #    points assigned to that cluster.
      _lowerCAmelCase       :  Any   				=					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       :  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
        _lowerCAmelCase       :  str   				=					compute_heterogeneity(__lowerCamelCase  ,      __lowerCamelCase  ,      __lowerCamelCase  ,      __lowerCamelCase		)
        record_heterogeneity.append(__lowerCamelCase		)
  
      _lowerCAmelCase       :  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_     			=       kmeans(
           dataset["""data"""],
           k,
           initial_centroids,
           maxiter=4_00,
           record_heterogeneity=heterogeneity,
           verbose=True,
       )
       plot_heterogeneity(heterogeneity, k)
  
  
  def 	_UpperCAmelCase				(  _lowerCamelCase						:       int  ,      _lowerCamelCase						:       str  ,      _lowerCamelCase						:       Any=None		)    ->						pd.DataFrame:
    # Fill missing values with given rules
    if fill_missing_report:
      _lowerCAmelCase       :  Union[str, Any]   				=					df.fillna(value=__lowerCamelCase		)
    _lowerCAmelCase       :  Union[str, Any]   				=					1
    _lowerCAmelCase       :  str   				=					df.select_dtypes(np.number		).columns
    _lowerCAmelCase       :  Optional[Any]   				=					(
        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 / 1_00		) : round(len(__lowerCamelCase		) * 75 / 1_00		)
                            ]		)		),
                ),
                ("""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)
    _lowerCAmelCase       :  Dict   				=					report[
        (report["""Features"""] == """dummy""") & (report["""Type"""] == """count""")
    ].copy()  # avoid SettingWithCopyWarning
    _lowerCAmelCase       :  Dict   				=					(
        """ClusterSize"""  # rename created cluster df to match report column names
    )
    _lowerCAmelCase       :  Optional[Any]   				=					"""# of Customers"""
    _lowerCAmelCase       :  Any   				=					pd.DataFrame(
        clustersize.iloc[:, 2:].values
        / clustersize.iloc[:, 2:].values.sum()		)
    _lowerCAmelCase       :  List[Any]   				=					"""% of Customers"""  # rename created cluster df to match report column names
    _lowerCAmelCase       :  str   				=					"""ClusterProportion"""
    _lowerCAmelCase       :  List[Any]   				=					clusterproportion.columns.tolist()
    _lowerCAmelCase       :  Optional[int]   				=					cols[-2:] + cols[:-2]
    _lowerCAmelCase       :  List[Any]   				=					clusterproportion[cols]  # rearrange columns to match report
    _lowerCAmelCase       :  Dict   				=					report.columns
    _lowerCAmelCase       :  str   				=					pd.DataFrame(
        abs(
            report[report["""Type"""] == """count"""].iloc[:, 2:].values
            - clustersize.iloc[:, 2:].values		)		)  # generating df with count of nan values
    _lowerCAmelCase       :  List[str]   				=					0
    _lowerCAmelCase       :  Dict   				=					"""# of nan"""
    _lowerCAmelCase       :  Tuple   				=					report[
        report["""Type"""] == """count"""
    ].Features.tolist()  # filling values in order to match report
    _lowerCAmelCase       :  Tuple   				=					a.columns.tolist()
    _lowerCAmelCase       :  str   				=					cols[-2:] + cols[:-2]
    _lowerCAmelCase       :  Optional[int]   				=					a[cols]  # rearrange columns to match report
    _lowerCAmelCase       :  Optional[Any]   				=					report.columns  # rename columns to match report
    _lowerCAmelCase       :  Optional[Any]   				=					report.drop(
        report[report.Type == """count"""].index		)  # drop count values except cluster size
    _lowerCAmelCase       :  str   				=					pd.concat(
        [report, a, clustersize, clusterproportion]  ,      axis=0		)  # concat report with clustert size and nan values
    _lowerCAmelCase       :  int   				=					report["""Features"""].isin(__lowerCamelCase		)
    _lowerCAmelCase       :  Optional[int]   				=					report.columns.tolist()
    _lowerCAmelCase       :  Optional[Any]   				=					cols[0:2] + cols[-1:] + cols[2:-1]
    _lowerCAmelCase       :  Any   				=					report[cols]
    _lowerCAmelCase       :  Optional[int]   				=					{
        """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       :  List[Any]   				=					(
        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		)
    )
    _lowerCAmelCase       :  str   				=					""""""
    _lowerCAmelCase       :  int   				=					report.reset_index()
    _lowerCAmelCase       :  Any   				=					report.drop(columns=["""index"""]		)
    return report
  
  
  if __name__ == "__main__":
       import doctest
  
       doctest.testmod()
  
  
  
style_context: 
  '''simple docstring'''
  
  from cva import COLOR_BGR2GRAY, cvtColor, imread, imshow, waitKey
  from numpy import divide, inta, multiply, ravel, sort, zeros_like
  
  
  def 	_UpperCAmelCase				(  _lowerCamelCase						:       str  ,      _lowerCamelCase						:       List[Any]=3		)    ->						Union[str, Any]:
    _lowerCAmelCase       :  str   				=					int(mask / 2		)
    # copy image size
    _lowerCAmelCase       :  Dict   				=					zeros_like(_lowerCamelCase		)
    for i in range(_lowerCamelCase  ,      gray_img.shape[0] - bd		):
      for j in range(_lowerCamelCase  ,      gray_img.shape[1] - bd		):
        # get mask according with mask
        _lowerCAmelCase       :  Union[str, Any]   				=					ravel(gray_img[i - bd : i + bd + 1, j - bd : j + bd + 1]		)
        # calculate mask median
        _lowerCAmelCase       :  str   				=					sort(_lowerCamelCase		)[inta(divide((multiply(_lowerCamelCase  ,      _lowerCamelCase		))  ,      2		) + 1		)]
        _lowerCAmelCase       :  Dict   				=					median
    return median_img
  
  
  if __name__ == "__main__":
       # read original image
       UpperCamelCase_     			=       imread("""../image_data/lena.jpg""")
       # turn image in gray scale value
       UpperCamelCase_     			=       cvtColor(img, COLOR_BGR2GRAY)
  
       # get values with two different mask size
       UpperCamelCase_     			=       median_filter(gray, 3)
       UpperCamelCase_     			=       median_filter(gray, 5)
  
       # show result images
       imshow("""median filter with 3x3 mask""", medianaxa)
       imshow("""median filter with 5x5 mask""", medianaxa)
       waitKey(0)
  
  
  