text: from re import X
  import numpy as np
  import pandas as pd
  import matplotlib.pyplot as plt
  from scipy.sparse import dia
  from sklearn.model_selection import train_test_split
  from pandas.plotting import scatter_matrix
  from scipy.stats import f_oneway
  from statsmodels.stats.multicomp import pairwise_tukeyhsd
  import seaborn as sns
  from sklearn.preprocessing import OneHotEncoder
  from sklearn.preprocessing import OrdinalEncoder
  from scipy.stats import iqr
  from sklearn.preprocessing import StandardScaler
  from sklearn.compose import ColumnTransformer
  from sklearn import linear_model
  from sklearn.linear_model import Ridge
  from sklearn.model_selection import cross_val_score
  from sklearn.model_selection import RepeatedKFold
  from sklearn.metrics import mean_squared_error
  from sklearn.linear_model import LinearRegression
  from sklearn.svm import SVR
  from sklearn.model_selection import GridSearchCV
  from sklearn.model_selection import StratifiedShuffleSplit
  from sklearn.ensemble import RandomForestRegressor
  
  # read data, using read_csv function from pandas module
  df = pd.read_csv("dataset/diamonds.csv")
  
  # display the first 5 rows for the dataframe
  print(df.head())
  
  print(df.describe())
  # return a description of data, the description containt an information about data:
  # count, mean, std, min value, 25%,50%, 75%, max value
  
  print(df.info())
  # display data information
  
  
  # # Replace x,y,z:
  
  df1 = df
  df["cubic_volume"] = df.x * df.y * df.z
  # create a diamond size series, by Multiplying The three dimensions of a diamond
  df.cubic_volume.replace(0, np.median(df.cubic_volume), inplace=True)
  # replace zeros values from cubic_volume series with the median
  df = df.drop("Unnamed: 0", axis=1)
  # delete ID "unnamed" attribute, because we don't need this 
  df = df.drop(['x', 'y', 'z'], axis=1)
  # delete x,y,z series 
  print(df.head())
  
  # # Delete Outliers:
  
  # outliers data records that differ dramatically from all others.
  # directly effect the machine learning model 
  # we use IQR  to detect outliers
  df_without_outliers = df
  for i in ['price', "carat", 'depth', 'table', 'cubic_volume']:
      q75, q25 = np.percentile(df[i], [75, 25])
      iqr = q75 - q25
      high_outlier = q75 + 1.5 * iqr
      low_outlier = q25 - 1.5 * iqr
      df_without_outliers = df_without_outliers[
          (df_without_outliers[i] < high_outlier) & (df_without_outliers[i] > low_outlier)]
  
  final_df = df_without_outliers
  
  print('outliers ratio:', (len(df) - len(final_df)) / len(df))
  print("number of outliers", len(df) - len(final_df))
  
  # # Data Visualization
  # 
  
  # Data With Outliers:
  
  # his diagram
  df.hist(figsize=(20, 14), bins=50)
  plt.show()
  
  fig, ax = plt.subplots(1, 4, figsize=(20, 6))
  # Create a figure and a subplots, with size of figure 20X6
  fig.subplots_adjust(wspace=0.25)
  j = 0
  for i in ['carat', 'depth', 'table', 'cubic_volume']:
      sns.regplot(data=df, x=i, y='price', color="#003f5c", line_kws={'color': '#ffa600'}, ax=ax[j])
      # method to  plot data and a linear regression model fit.
      j = j + 1
  
  fig.show()
  
  Numerical_attr = ["carat", "depth", "color", "x", "y", "z"]
  scatter_matrix(df1[Numerical_attr], figsize=(12, 12))
  # draw a matrix of scatter plots, with figure size of 12X12
  plt.show()
  
  # Without the (x,y,z)
  
  
  fig, ax = plt.subplots(1, 4, figsize=(20, 6))
  # Create a figure and a subplots, with size of figure 20X6
  fig.subplots_adjust(wspace=0.25)
  j = 0
  for i in ['carat', 'depth', 'table', 'cubic_volume']:
      sns.regplot(data=df, x=i, y='price', color="#003f5c", line_kws={'color': '#ffa600'}, ax=ax[j])
      # method to  plot data and a linear regression model fit.
      j = j + 1
  
  fig.show()
  
  fig, ax = plt.subplots(1, 4, figsize=(20, 6))
  # Create a figure and a subplots, with size of figure 20X6, n row is 1 an n column is 4
  # A kernel density estimate (KDE) plot is a method for visualizing the distribution of observations in a dataset,
  sns.kdeplot(data=df, x="carat", color="#003f5c", fill=True, edgecolor='red', alpha=1, ax=ax[0])
  sns.kdeplot(data=df, x="depth", color="#003f5c", fill=True, edgecolor='red', alpha=1, ax=ax[1])
  sns.kdeplot(data=df, x="table", color="#003f5c", fill=True, edgecolor='red', alpha=1, ax=ax[2])
  sns.kdeplot(data=df, x="cubic_volume", color="#003f5c", fill=True, edgecolor='red', alpha=1, ax=ax[3])
  fig.show()
  # diaplay the figures
  
  
  fig = plt.figure(figsize=(12, 8))
  # create a new figure, with size 12X8
  sns.heatmap(df.corr(), linewidths=2, annot=True, cmap="Blues")
  # heatmap is plot rectangular data as a color-encoded matrix.
  # compute pairwise correlation of columns, excluding NA/null values.
  # correlation is a term that is a measure of the strength of a linear relationship between two quantitative variables
  # positive correlation, negative correlation,neutral correlation  
  plt.title("Correlation", size=15, weight='bold')
  # set title for figure
  
  
  fig, ax = plt.subplots(1, 2, figsize=(15, 4))
  # Create a figure and a subplots, with size of figure 15X4
  sns.boxplot(data=df, x="carat", color="#003f5c", ax=ax[0])
  # A box plot shows the distribution of quantitative data in a way that facilitates comparisons between variables
  # or across levels of a categorical variable
  
  sns.boxplot(data=df, x="depth", color="#003f5c", ax=ax[1])
  fig, ax = plt.subplots(1, 2, figsize=(15, 4))
  # Create a figure and a subplots, with size of figure 15X4, n row is 1 an n column is 2
  sns.boxplot(data=df, x="table", color="#003f5c", ax=ax[0])
  sns.boxplot(data=df, x="cubic_volume", color="#003f5c", ax=ax[1])
  fig, ax = plt.subplots(1, 2, figsize=(15, 4))
  sns.boxplot(data=df, x="price", color="#003f5c", ax=ax[1])
  fig.show()
  
  # Data Without Outliers:
  
  
  fig, ax = plt.subplots(1, 2, figsize=(15, 4))
  sns.boxplot(data=df_without_outliers, x="carat", color="#003f5c", ax=ax[0])
  sns.boxplot(data=df_without_outliers, x="depth", color="#003f5c", ax=ax[1])
  fig, ax = plt.subplots(1, 2, figsize=(15, 4))
  sns.boxplot(data=df_without_outliers, x="table", color="#003f5c", ax=ax[0])
  sns.boxplot(data=df_without_outliers, x="cubic_volume", color="#003f5c", ax=ax[1])
  fig, ax = plt.subplots(1, 2, figsize=(15, 4))
  sns.boxplot(data=df_without_outliers, x="price", color="#003f5c", ax=ax[1])
  fig.show()
  
  fig, ax = plt.subplots(1, 4, figsize=(20, 6))
  # Create a figure and a subplots, with size of figure 20X6, n row is 1 an n column is 4
  # A kernel density estimate (KDE) plot is a method for visualizing the distribution of observations in a dataset,
  sns.kdeplot(data=df_without_outliers, x="carat", color="#003f5c", fill=True, edgecolor='red', alpha=1, ax=ax[0])
  sns.kdeplot(data=df_without_outliers, x="depth", color="#003f5c", fill=True, edgecolor='red', alpha=1, ax=ax[1])
  sns.kdeplot(data=df_without_outliers, x="table", color="#003f5c", fill=True, edgecolor='red', alpha=1, ax=ax[2])
  sns.kdeplot(data=df_without_outliers, x="cubic_volume", color="#003f5c", fill=True, edgecolor='red', alpha=1, ax=ax[3])
  fig.show()
  # diaplay the figures
  
  
  # # Train and Test Sets:
  
  
  train_set, test_set = train_test_split(final_df, test_size=0.2, random_state=1)
  # split the data  into random train and test subsets randomly
  diamonds_labels = train_set["price"].copy()
  # creating data label
  test_diamonds_labels = test_set["price"].copy()
  diamonds = train_set.drop("price", axis=1)
  # delete the price data, because we need the model to predict the price, so we need to delete this
  diamonds_testset = test_set.drop("price", axis=1)
  
  diamonds_labels = train_set["price"].copy()
  # creating data label
  test_diamonds_labels = test_set["price"].copy()
  diamonds = train_set.drop("price", axis=1)
  # delete the price data, because we need the model to predict the price, so we need to delete this
  diamonds_testset = test_set.drop("price", axis=1)
  diamonds_num = diamonds.drop(["cut", "color", "clarity"], axis=1)
  diamonds_num.head()
  # display the first 5 rows for the object based on position.
  
  
  # # Color ordinal encoding:
  
  diamond_color_ascending = ['J', 'I', 'H', 'G', 'F', 'E', 'D']
  # color is an cateigoral data, so we need to encode this as numarical data
  ordinal_encoder = OrdinalEncoder(categories=[diamond_color_ascending])
  # OrdinalEncoder: encode categorical features as an integer array.
  diamond_color_encoded = ordinal_encoder.fit_transform(diamonds[['color']])
  # fit_transform joins two steps, (fit)calculates the parameters, (transform)apply the transformation to any particular 
  diamond_color_encoded_df = pd.DataFrame(diamond_color_encoded)
  # add to data frame color encode
  
  ordinal_encoder = OrdinalEncoder(categories=[diamond_color_ascending])
  test_diamond_color_encoded = ordinal_encoder.fit_transform(diamonds_testset[['color']])
  test_diamond_color_ordinal_df = pd.DataFrame(test_diamond_color_encoded)
  
  # this code for train set and test set
  
  
  # # Cuts ordinal encoding:
  
  
  diamond_cuts_ascending = ['Fair', 'Good', 'Very Good', 'Premium', 'Ideal']
  ordinal_encoder = OrdinalEncoder(categories=[diamond_cuts_ascending])
  diamond_cut_encoded = ordinal_encoder.fit_transform(diamonds[['cut']])
  diamond_cut_ordinal_df = pd.DataFrame(diamond_cut_encoded)
  ordinal_encoder = OrdinalEncoder(categories=[diamond_cuts_ascending])
  test_diamond_cut_encoded = ordinal_encoder.fit_transform(diamonds_testset[['cut']])
  test_diamond_cut_ordinal_df = pd.DataFrame(test_diamond_cut_encoded)
  
  # #  Clarity ordinal encoding:
  
  
  diamond_clarity_ascending = ['I1', 'SI2', 'SI1', 'VS2', 'VS1', 'VVS2', 'VVS1', 'IF']
  ordinal_encoder = OrdinalEncoder(categories=[diamond_clarity_ascending])
  diamond_clarity_encoded = ordinal_encoder.fit_transform(train_set[['clarity']])
  diamond_clarity_encoded_df = pd.DataFrame(diamond_clarity_encoded)
  ordinal_encoder = OrdinalEncoder(categories=[diamond_clarity_ascending])
  test_diamond_clarity_encoded = ordinal_encoder.fit_transform(diamonds_testset[['clarity']])
  test_diamond_clarity_ordinal_df = pd.DataFrame(test_diamond_clarity_encoded)
  
  a = diamond_color_encoded_df.join(diamond_cut_ordinal_df, rsuffix='1')
  b = a.join(diamond_clarity_encoded_df)
  b.rename(columns={0: '02'}, inplace=True)
  encoded_df = b
  
  a_test = test_diamond_color_ordinal_df.join(test_diamond_cut_ordinal_df, rsuffix='1')
  b_test = a.join(diamond_clarity_encoded_df)
  b_test.rename(columns={0: '02'}, inplace=True)
  test_encoded_df = b_test
  # encoded dataframe:
  
  df[["clarity", "color", "cut"]].head(10)
  
  # # Standardization:
  
  
  numeric_coloumns = ["carat", "cubic_volume", "table", "depth"]
  pipeline = ColumnTransformer([
      ("num", StandardScaler(), numeric_coloumns,)
  ])
  diamonds_scaled = pipeline.fit_transform(diamonds)
  diamonds_scaled_df = pd.DataFrame(diamonds_scaled)
  final_train_set = diamonds_scaled_df.join(encoded_df)
  
  numeric_coloumns = ["carat", "cubic_volume", "table", "depth"]
  pipeline = ColumnTransformer([
      ("num", StandardScaler(), numeric_coloumns,)
  ])
  test_diamonds_scaled = pipeline.fit_transform(diamonds_testset)
  test_diamonds_scaled_df = pd.DataFrame(test_diamonds_scaled)
  final_test_set = test_diamonds_scaled_df.join(test_encoded_df)
  
  final_train_set.head(10)
  
  numeric_coloumns = ["carat", "cubic_volume", "table", "depth"]
  pipeline = ColumnTransformer([
      ("num", StandardScaler(), numeric_coloumns,)
  ])
  test_diamonds_scaled = pipeline.fit_transform(diamonds_testset)
  test_diamonds_scaled_df = pd.DataFrame(test_diamonds_scaled)
  final_test_set = test_diamonds_scaled_df.join(test_encoded_df)
  final_test_set.head()
  
  # #  Model Training:
  
  
  modelridge = Ridge(alpha=0.5)
  scores = cross_val_score(modelridge, final_train_set, diamonds_labels, scoring='neg_mean_squared_error', cv=10)
  rmse_scores = np.sqrt(-scores)
  print("mean:", rmse_scores.mean())
  print("std:", rmse_scores.std())
  
  from sklearn.tree import DecisionTreeRegressor
  
  tree_reg = DecisionTreeRegressor(random_state=42)
  tree_scores = cross_val_score(tree_reg, final_train_set, diamonds_labels, scoring='neg_mean_squared_error', cv=10)
  rmse_scores = np.sqrt(-tree_scores)
  print("mean:", rmse_scores.mean())
  print("std:", rmse_scores.std())
  
  from sklearn.linear_model import LinearRegression
  
  model = LinearRegression()
  model.fit(final_train_set, diamonds_labels)
  pred = model.predict(final_train_set)
  lin_mse = mean_squared_error(diamonds_labels, pred)
  lin_rmse = np.sqrt(lin_mse)
  print(lin_rmse)
  
  regressor = SVR(kernel='linear')
  linear_scores = cross_val_score(regressor, final_train_set, diamonds_labels, scoring='neg_mean_squared_error', cv=10)
  rmse_scores = np.sqrt(-linear_scores)
  print("mean:", rmse_scores.mean())
  print("std:", rmse_scores.std())
  
  from sklearn.model_selection import GridSearchCV
  
  param_grid = [
      {'n_estimators': [3, 10, 30], 'max_features': [2, 4, 6, 8]},
      {'bootstrap': [False], 'n_estimators': [3, 10], 'max_features': [2, 3, 4]},
  ]
  grid_search = GridSearchCV(forest_reg, param_grid, cv=10, scoring='neg_mean_squared_error', return_train_score=True)
  grid_search.fit(final_train_set, diamonds_labels)
  
  cvres = grid_search.cv_results_
  for mean_score, params in zip(cvres["mean_test_score"], cvres["params"]):
      print(np.sqrt(-mean_score), params)
  
  forest_reg = RandomForestRegressor(random_state=42, max_features=4, n_estimators=30)
  forst_scores = cross_val_score(forest_reg, final_train_set, diamonds_labels, scoring='neg_mean_squared_error', cv=10)
  rmse_scores = np.sqrt(-forst_scores)
  print("mean:", rmse_scores.mean())
  print("std:", rmse_scores.std())
  
  # # Model Testing:
  
  from sklearn.linear_model import LinearRegression
  
  model = LinearRegression()
  model.fit(final_train_set, diamonds_labels)
  pred = model.predict(final_test_set)
  lin_mse = mean_squared_error(test_diamonds_labels, pred)
  lin_rmse = np.sqrt(lin_mse)
  print(lin_rmse)
  
  forest_reg.fit(final_train_set, diamonds_labels)
  a = forest_reg.predict(final_test_set)
  
  dd = mean_squared_error(test_diamonds_labels, a)
  cc = np.sqrt(dd)
  print(cc)
  