


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			:			List[str]			      =					"K-MEANS-CLUST/ "


def   a						(				SCREAMING_SNAKE_CASE_   :		str				,      SCREAMING_SNAKE_CASE_   :		List[Any]				,      SCREAMING_SNAKE_CASE_   :		Any=None							):






       """simple docstring"""





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

       # Pick K indices from range [0, N).
       UpperCamelCase     :						Any 						=		np.random.randint(0				,      SCREAMING_SNAKE_CASE_				,      SCREAMING_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.
       UpperCamelCase     :						List[Any] 						=		data[rand_indices, :]

       return centroids


def   a						(				SCREAMING_SNAKE_CASE_   :		Optional[Any]				,      SCREAMING_SNAKE_CASE_   :		Union[str, Any]							):






       """simple docstring"""





       return pairwise_distances(SCREAMING_SNAKE_CASE_				,      SCREAMING_SNAKE_CASE_				,      metric='''euclidean'''							)


def   a						(				SCREAMING_SNAKE_CASE_   :		List[str]				,      SCREAMING_SNAKE_CASE_   :		Optional[Any]							):






       """simple docstring"""





       UpperCamelCase     :						Any 						=		centroid_pairwise_dist(SCREAMING_SNAKE_CASE_				,      SCREAMING_SNAKE_CASE_							)

       # Compute cluster assignments for each data point:
       # Fill in the blank (RHS only)
       UpperCamelCase     :						List[Any] 						=		np.argmin(SCREAMING_SNAKE_CASE_				,      axis=1							)

       return cluster_assignment


def   a						(				SCREAMING_SNAKE_CASE_   :		int				,      SCREAMING_SNAKE_CASE_   :		Union[str, Any]				,      SCREAMING_SNAKE_CASE_   :		Dict							):






       """simple docstring"""





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

       return new_centroids


def   a						(				SCREAMING_SNAKE_CASE_   :		Dict				,      SCREAMING_SNAKE_CASE_   :		Union[str, Any]				,      SCREAMING_SNAKE_CASE_   :		int				,      SCREAMING_SNAKE_CASE_   :		Dict							):






       """simple docstring"""





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

       return heterogeneity


def   a						(				SCREAMING_SNAKE_CASE_   :		Optional[int]				,      SCREAMING_SNAKE_CASE_   :		List[Any]							):






       """simple docstring"""





       plt.figure(figsize=(7, 4)							)
       plt.plot(SCREAMING_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''': 1_6}							)
       plt.show()


def   a						(				SCREAMING_SNAKE_CASE_   :		Dict				,      SCREAMING_SNAKE_CASE_   :		List[str]				,      SCREAMING_SNAKE_CASE_   :		List[Any]				,      SCREAMING_SNAKE_CASE_   :		List[Any]=5_0_0				,      SCREAMING_SNAKE_CASE_   :		str=None				,      SCREAMING_SNAKE_CASE_   :		Any=False							):






       """simple docstring"""





       UpperCamelCase     :						List[str] 						=		initial_centroids[:]
       UpperCamelCase     :						str 						=		None

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

              # 1. Make cluster assignments using nearest centroids
              UpperCamelCase     :						List[Any] 						=		assign_clusters(SCREAMING_SNAKE_CASE_				,      SCREAMING_SNAKE_CASE_							)

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

              UpperCamelCase     :						List[Any] 						=		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			:			Optional[Any]			      =					ds.load_iris()
  __UpperCAmelCase			:			Union[str, Any]			      =					3
  __UpperCAmelCase			:			int			      =					[]
  __UpperCAmelCase			:			Any			      =					get_initial_centroids(dataset["data"], k, seed=0)
  __UpperCAmelCase      ,     __UpperCAmelCase			:			List[Any]			      =					kmeans(
      dataset["data"],
      k,
      initial_centroids,
      maxiter=400,
      record_heterogeneity=heterogeneity,
      verbose=True,
  )
  plot_heterogeneity(heterogeneity, k)


def   a						(				SCREAMING_SNAKE_CASE_   :		Dict				,      SCREAMING_SNAKE_CASE_   :		Tuple				,      SCREAMING_SNAKE_CASE_   :		Dict=None							):






       """simple docstring"""





       if fill_missing_report:
              UpperCamelCase     :						Optional[Any] 						=		df.fillna(value=SCREAMING_SNAKE_CASE_							)
       UpperCamelCase     :						Any 						=		1
       UpperCamelCase     :						Union[str, Any] 						=		df.select_dtypes(np.number							).columns
       UpperCamelCase     :						str 						=		(
           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(SCREAMING_SNAKE_CASE_							)							)),
                   ('''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(SCREAMING_SNAKE_CASE_							)[
                                   round(len(SCREAMING_SNAKE_CASE_							) * 2_5 / 1_0_0							) : round(len(SCREAMING_SNAKE_CASE_							) * 7_5 / 1_0_0							)
                               ]							)							),
                   ),
                   ('''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=SCREAMING_SNAKE_CASE_				,      columns={'''level_0''': '''Features''', '''level_1''': '''Type'''}							)
       )  # rename columns
       # calculate the size of cluster(count of clientID's)
       UpperCamelCase     :						Dict 						=		report[
           (report["""Features"""] == """dummy""") & (report["""Type"""] == """count""")
       ].copy()  # avoid SettingWithCopyWarning
       UpperCamelCase     :						Any 						=		(
           """ClusterSize"""  # rename created cluster df to match report column names
       )
       UpperCamelCase     :						Any 						=		"""# of Customers"""
       UpperCamelCase     :						Dict 						=		pd.DataFrame(
           clustersize.iloc[:, 2:].values
           / clustersize.iloc[:, 2:].values.sum()							)
       UpperCamelCase     :						Dict 						=		"""% of Customers"""  # rename created cluster df to match report column names
       UpperCamelCase     :						Dict 						=		"""ClusterProportion"""
       UpperCamelCase     :						Union[str, Any] 						=		clusterproportion.columns.tolist()
       UpperCamelCase     :						int 						=		cols[-2:] + cols[:-2]
       UpperCamelCase     :						Union[str, Any] 						=		clusterproportion[cols]  # rearrange columns to match report
       UpperCamelCase     :						str 						=		report.columns
       UpperCamelCase     :						Any 						=		pd.DataFrame(
           abs(
               report[report['''Type'''] == '''count'''].iloc[:, 2:].values
               - clustersize.iloc[:, 2:].values							)							)  # generating df with count of nan values
       UpperCamelCase     :						Tuple 						=		0
       UpperCamelCase     :						Any 						=		"""# of nan"""
       UpperCamelCase     :						Tuple 						=		report[
           report["""Type"""] == """count"""
       ].Features.tolist()  # filling values in order to match report
       UpperCamelCase     :						int 						=		a.columns.tolist()
       UpperCamelCase     :						Optional[int] 						=		cols[-2:] + cols[:-2]
       UpperCamelCase     :						Tuple 						=		a[cols]  # rearrange columns to match report
       UpperCamelCase     :						int 						=		report.columns  # rename columns to match report
       UpperCamelCase     :						List[str] 						=		report.drop(
           report[report.Type == '''count'''].index							)  # drop count values except cluster size
       UpperCamelCase     :						Optional[Any] 						=		pd.concat(
           [report, a, clustersize, clusterproportion]				,      axis=0							)  # concat report with clustert size and nan values
       UpperCamelCase     :						Any 						=		report["""Features"""].isin(SCREAMING_SNAKE_CASE_							)
       UpperCamelCase     :						Union[str, Any] 						=		report.columns.tolist()
       UpperCamelCase     :						List[str] 						=		cols[0:2] + cols[-1:] + cols[2:-1]
       UpperCamelCase     :						Optional[Any] 						=		report[cols]
       UpperCamelCase     :						List[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,
       }
       UpperCamelCase     :						Any 						=		(
           report.assign(
               Sortera=lambda SCREAMING_SNAKE_CASE_							: x.Type.map(SCREAMING_SNAKE_CASE_							)				,      Sortera=lambda SCREAMING_SNAKE_CASE_							: list(reversed(range(len(SCREAMING_SNAKE_CASE_							)							)							)							)				,      )
           .sort_values(['''Sorter1''', '''Mark''', '''Sorter2''']				,      ascending=SCREAMING_SNAKE_CASE_							)
           .drop(['''Sorter1''', '''Sorter2''']				,      axis=1							)
       )
       UpperCamelCase     :						Optional[int] 						=		""""""
       UpperCamelCase     :						Optional[int] 						=		report.reset_index()
       UpperCamelCase     :						Optional[int] 						=		report.drop(columns=['''index''']							)
       return report


if __name__ == "__main__":
  import doctest

  doctest.testmod()









from datetime import date

import requests

a 			=							'https://api.carbonintensity.org.uk/intensity'
def    a__    (	):
   lowercase__    :						Union[str, Any]       =			requests.get(A       ).json()["""data"""][0]
   return last_half_hour["intensity"]["actual"]
def    a__    (	A		,					A       ):
   return requests.get(F'''{BASE_URL}/{start}/{end}'''       ).json()["data"]


if __name__ == "__main__":
 for entry in fetch_from_to(start=date(2020, 10, 1), end=date(2020, 10, 3)):
  print('from {from} to {to}: {intensity[actual]}'.format(**entry))
 print(F'{fetch_last_half_hour() = }')


