//  [python]
def _build_model(dataframe=None,target_column=None,numerical_transformer=None,categorical_transformer=None
                ,pca=False, algorithm=None, balance_data=False,display_inline=True,
                grid_search=False,params=None,hashing=False,hash_size=500,project_path=None,
                **kwargs):
    
#     algorithm = algorithm.copy()
    data_path = os.path.join(project_path, 'data/')
    try:
        os.mkdir(data_path)
    except:
        pass
    
    identify_columns(dataframe,target_column,project_path=data_path,display_inline=display_inline,**kwargs)
    
    model_preprocessor_pipeline = os.path.join(project_path, 'model/')
    try:
        os.mkdir(model_preprocessor_pipeline)
    except:
        pass

    if os.path.exists(f"{project_path}/data/metadata/store_file.yaml"):
        config = yaml.safe_load(open(f"{project_path}/data/metadata/store_file.yaml"))
        numerical_attribute = config['num_feat']
        categorical_attribute = config['cat_feat']
        lower_categorical_attribute = config['lower_cat']
        hash_features = config['high_card_feat']
        input_columns = config['input_columns']
    else:
        raise ValueError('path: No file found in f"{project_path}/data/metadata/"')
    
    if hashing:
        hash_transformer = Pipeline([('imputer', Imputer(strategy='constant', fill_value='Missing')),
                                ('hasher', FeatureHasher(n_features=hash_size, input_type='string'))])
        categorical_attribute = lower_categorical_attribute
        data_transformer = ColumnTransformer(transformers=[
                                ('numerical', numerical_transformer, numerical_attribute),
                                ('categorical', categorical_transformer, categorical_attribute),
                                ('hasher', hash_transformer , hash_features)])
        use_cols =  numerical_attribute + categorical_attribute + hash_features
        
    else:
        data_transformer = ColumnTransformer(
        transformers=[
            ('numerical', numerical_transformer, numerical_attribute),
            ('categorical', categorical_transformer, categorical_attribute)])
        use_cols =  numerical_attribute + categorical_attribute
    
    train_df = manage_columns(dataframe,columns=input_columns,select_columns=True)
    y = dataframe[f'{target_column}'].loc[list(train_df.index)]
    
    if balance_data:
        oversample = SMOTE()
        data_transformer.fit(train_df)
        encoder = data_transformer.transform(train_df)
        X, y = oversample.fit_resample(encoder,y)
        train_df = X
        X_train_copy = encoder
        X_train, X_test, y_train, y_test = train_test_split(train_df, y,\
                                                            stratify=y, test_size=0.20, random_state=0)
        
    else:
    
        X_train, X_test, y_train, y_test = train_test_split(train_df, y,\
                                                            stratify=y, test_size=0.20, random_state=0)

        X_train_copy = X_train.copy()
        data_transformer.fit(X_train_copy)
        X_train_copy = data_transformer.transform(X_train_copy)
    
         
    if pca:
        print_divider('Applying PCA to the data')
        if scipy.sparse.issparse(X_train_copy):
            X_train_array = X_train_copy.toarray()
#         elif isinstance(X_train_copy, np.ndarray):
#             X_train_array = X_train_copy
        else:
            X_train_array = X_train_copy
#         X_train_copy = data_transformer.fit_transform(X_train_copy)
        pca_ = PCA().fit(X_train_array)
        pca_evr = pca_.explained_variance_ratio_
        cumsum_ = np.cumsum(pca_evr)
        dim_95 = np.argmax(cumsum_ >= 0.95) + 1
        instances_, dims_ =  X_train_copy.shape
        dim_reduction = PCA(dim_95)
        print(f"\nDimension reduced from {dims_} to {dim_95} while retaining 95% of variance.")
        if hashing:
            preprocessor = Pipeline(steps=[('data_transformer', data_transformer),\
                                       ('to_dense', DenseTransformer()),\
                                       ('reduce_dim',dim_reduction)])
        else:
            preprocessor = Pipeline(steps=[('data_transformer', data_transformer),\
                                       ('reduce_dim',dim_reduction)])
    else:
        if hashing:
            preprocessor = Pipeline(steps=[('data_transformer', data_transformer),\
                                   ('to_dense', DenseTransformer())])
        else:
            preprocessor = Pipeline(steps=[('data_transformer', data_transformer)])
    
    classifier = Pipeline(steps=[('preprocessor', preprocessor),
                      ('model', algorithm)])
    
    exclusive_keyword = ['model','fit','hyperparameters']
    
    if params:
        model_params = {}
        fit_params = {}
        hyperparamers_params = {}
        keys = [key for key in params.keys()]
        for first_key in keys:
            for key,value in params[first_key].items():
                key = f'model__{key}'
                if first_key == 'model':
                    model_params[key] = value
                elif first_key == 'fit':
                    fit_params[key] = value 
                elif first_key == 'hyperparameters':
                    hyperparamers_params [key] = value
                else:
                    raise ValueError(f'params:Only one of parameters {exclusive_keyword} should be set')
    
    if grid_search:
        # We can utilize params grid to check for best hyperparameters or transformers
        # The syntax here is pipeline_step_name__parameters and we need to chain if we have nested pipelines 
        parameters_grid = {}
        for key,value in params.items():
            parameters_grid[f'model__{key}'] = value
                # Doing a Grid Search
        grid_search = GridSearchCV(classifier, param_grid=parameters_grid)
        # fitting on our dataset
        grid_search.fit(X_train, y_train)  # Semicolon to not print estimator in notebook
        # set config to diagram for visualizing the pipelines/composite estimator
            
        
        model_path = os.path.join(model_preprocessor_pipeline,f'{algorithm.__class__.__name__}.pkl')
        store_pipeline(grid_search.best_estimator_,model_path)
            
        set_config(display='diagram')
        # Lets visualize the best estimator from grid search.
        output = grid_search.best_estimator_
        # saving pipeline as html format
        with open(f'{model_preprocessor_pipeline}/titanic_data_pipeline_estimator.html', 'w') as f:  
            f.write(estimator_html_repr(grid_search.best_estimator_))
            
    else:
        if params:
            kwargsList = inspect.getfullargspec(algorithm.fit)[0]
            if len(fit_params)>0:
                
    #             X_val = data_transformer.transform(X_test) 
    #             if 'eval_set' in kwargsList:
    #                 fit_params['model__eval_set'] =  (X_test, y_test)
                try:
                    classifier.set_params(**model_params)
                    classifier.fit(X_train, y_train,**fit_params)
                except:
                    if 'cat_features' in kwargsList:
                        cate_features_index = [X_train.columns.get_loc(col) for col in X_train.columns][len(numerical_attribute):]
                    fit_params['model__cat_features'] = cate_features_index
                    classifier.set_params(**model_params)
                    classifier.fit(X_train, y_train,**fit_params)
            else:
                try:
                    classifier.set_params(**model_params)
                    classifier.fit(X_train, y_train) 
                except:
                    if 'cat_features' in kwargsList:
                        cate_features_index = [X_train.columns.get_loc(col) for col in X_train.columns][len(numerical_attribute):]
                    fit_params['model__cat_features'] = cate_features_index
                    classifier.set_params(**model_params)
                    classifier.fit(X_train, y_train,**fit_params) 
        else:
            classifier.set_params(**model_params)
            classifier.fit(X_train, y_train)
            
        model_path = os.path.join(model_preprocessor_pipeline,f'{algorithm.__class__.__name__}.pkl')
        store_pipeline(classifier,model_path)
        
#         set config to diagram for visualizing the pipelines/composite estimators
        set_config(display='diagram')
        output = classifier
        
        with open(f'{model_preprocessor_pipeline}/titanic_data_pipeline_estimator.html', 'w') as f:  
            f.write(estimator_html_repr(classifier))
        
            
#     X_test = data_transformer.transform(X_test)        
    y_pred = output.predict(X_test)
    
    print_divider('Metric Performance')
            
    met_perf = get_scores(y_test,y_pred)
    
    print(f'\nMetric performance on test data\n{met_perf}\n\n')
    print('\nconfusion matrix')
    
    print(confusion_matrix(y_test, y_pred))
    
    return output