From 198bf02e9d6e96aa4709ff5e12a54a897f383214 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Fri, 4 Mar 2022 14:50:44 +0900 Subject: [PATCH 01/27] Add ML > DataSets --- data/m_ml/mlLibrary.js | 104 ++++++++++++++++++++++++++++++++++ html/m_ml/dataSets.html | 19 +++++++ js/m_ml/DataSets.js | 120 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 240 insertions(+), 3 deletions(-) create mode 100644 html/m_ml/dataSets.html diff --git a/data/m_ml/mlLibrary.js b/data/m_ml/mlLibrary.js index 6119e80a..4ada0871 100644 --- a/data/m_ml/mlLibrary.js +++ b/data/m_ml/mlLibrary.js @@ -20,6 +20,110 @@ define([ * ] */ var ML_LIBRARIES = { + /** Data Sets */ + 'load_boston': { + name: 'load_boston', + import: 'from sklearn.datasets import load_boston', + code: 'load_boston()', + options: [ + + ] + }, + 'load_iris': { + name: 'load_iris', + import: 'from sklearn.datasets import load_iris', + code: 'load_iris()', + options: [ + + ] + }, + 'load_diabetes': { + name: 'load_diabetes', + import: 'from sklearn.datasets import load_diabetes', + code: 'load_diabetes()', + options: [ + + ] + }, + 'load_digits': { + name: 'load_digits', + import: 'from sklearn.datasets import load_digits', + code: 'load_digits(${n_class})', + options: [ + { name: 'n_class', component: ['input_number'], default: 10, usePair: true }, + ] + }, + 'load_linnerud': { + name: 'load_linnerud', + import: 'from sklearn.datasets import load_linnerud', + code: 'load_linnerud()', + options: [ + + ] + }, + 'load_wine': { + name: 'load_wine', + import: 'from sklearn.datasets import load_wine', + code: 'load_wine()', + options: [ + + ] + }, + 'load_breast_cancer': { + name: 'load_breast_cancer', + import: 'from sklearn.datasets import load_breast_cancer', + code: 'load_breast_cancer()', + options: [ + + ] + }, + 'make_classification': { + name: 'make_classification', + import: 'from sklearn.datasets import make_classification', + code: 'make_classification(${n_samples}${n_features}${n_repeated}${n_classes}${shuffle}${random_state}${etc})', + options: [ + { name: 'n_samples', component: ['input_number'], default: 100, usePair: true }, + { name: 'n_features', component: ['input_number'], default: 20, usePair: true }, + { name: 'n_repeated', component: ['input_number'], default: 0, usePair: true }, + { name: 'n_classes', component: ['input_number'], default: 2, usePair: true }, + { name: 'shuffle', component: ['bool_select'], default: 'True', usePair: true }, + { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } + ] + }, + 'make_blobs': { + name: 'make_blobs', + import: 'from sklearn.datasets import make_blobs', + code: 'make_blobs(${n_samples}${n_features}${shuffle}${random_state}${etc})', + options: [ + { name: 'n_samples', component: ['input_number'], default: 100, usePair: true }, + { name: 'n_features', component: ['input_number'], default: 20, usePair: true }, + { name: 'shuffle', component: ['bool_select'], default: 'True', usePair: true }, + { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } + ] + }, + 'make_circles': { + name: 'make_circles', + import: 'from sklearn.datasets import make_circles', + code: 'make_circles(${n_samples}${shuffle}${noise}${random_state}${factor}${etc})', + options: [ + { name: 'n_samples', component: ['input_number'], default: 100, usePair: true }, + { name: 'shuffle', component: ['bool_select'], default: 'True', usePair: true }, + { name: 'noise', component: ['input_number'], usePair: true }, + { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true }, + { name: 'factor', component: ['input_number'], default: 0.8, usePair: true } + ] + }, + 'make_moons': { + name: 'make_moons', + import: 'from sklearn.datasets import make_moons', + code: 'make_moons(${n_samples}${shuffle}${noise}${random_state}${etc})', + options: [ + { name: 'n_samples', component: ['input_number'], default: 100, usePair: true }, + { name: 'shuffle', component: ['bool_select'], default: 'True', usePair: true }, + { name: 'noise', component: ['input_number'], usePair: true }, + { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } + ] + }, /** Data Preparation - Encoding */ 'prep-onehot': { name: 'OneHotEncoder', diff --git a/html/m_ml/dataSets.html b/html/m_ml/dataSets.html new file mode 100644 index 00000000..5af731b8 --- /dev/null +++ b/html/m_ml/dataSets.html @@ -0,0 +1,19 @@ + +
+
+
+ + +
+
+ +
+
+
+ + +
+
+ \ No newline at end of file diff --git a/js/m_ml/DataSets.js b/js/m_ml/DataSets.js index cb480970..bdd2bd5f 100644 --- a/js/m_ml/DataSets.js +++ b/js/m_ml/DataSets.js @@ -13,11 +13,14 @@ // [CLASS] DataSets //============================================================================ define([ + 'text!vp_base/html/m_ml/dataSets.html!strip', 'vp_base/js/com/com_util', 'vp_base/js/com/com_Const', 'vp_base/js/com/com_String', 'vp_base/js/com/component/PopupComponent', -], function(com_util, com_Const, com_String, PopupComponent) { + 'vp_base/js/com/com_generatorV2', + 'vp_base/data/m_ml/mlLibrary', +], function(dsHTML, com_util, com_Const, com_String, PopupComponent, com_generator, ML_LIBRARIES) { /** * DataSets @@ -29,15 +32,126 @@ define([ this.config.dataview = false; this.state = { - + loadType: 'load_boston', + userOption: '', + allocateTo: 'ldata', ...this.state } + + this.mlConfig = ML_LIBRARIES; + this.loadTypeList = { + 'Load Data': [ + 'load_boston', 'load_iris', 'load_diabetes', 'load_digits', 'load_linnerud', 'load_wine', 'load_breast_cancer' + ], + 'Create Data': [ + 'make_classification', 'make_blobs', 'make_circles', 'make_moons' + ] + } + + } + + _bindEvent() { + super._bindEvent(); + let that = this; + + // select model + $(this.wrapSelector('#loadType')).on('change', function() { + let loadType = $(this).val(); + that.state.loadType = loadType; + $(that.wrapSelector('.vp-data-option-box')).html(that.templateForOption(loadType)); + + // change allocateTo default variable name + if (that.loadTypeList['Load Data'].includes(loadType)) { + $(that.wrapSelector('#allocateTo')).val('ldata'); + that.state.allocateTo = 'ldata'; + } else { + $(that.wrapSelector('#allocateTo')).val('df'); + that.state.allocateTo = 'df'; + } + }); } templateForBody() { - return 'Data Set test'; + let page = $(dsHTML); + + let that = this; + // load types + let loadTypeTag = new com_String(); + Object.keys(this.loadTypeList).forEach(category => { + let optionTag = new com_String(); + that.loadTypeList[category].forEach(opt => { + let optConfig = that.mlConfig[opt]; + let selectedFlag = ''; + if (opt == that.state.modelType) { + selectedFlag = 'selected'; + } + optionTag.appendFormatLine('', + opt, selectedFlag, optConfig.name); + }) + loadTypeTag.appendFormatLine('{1}', + category, optionTag.toString()); + }); + $(page).find('#loadType').html(loadTypeTag.toString()); + + // render option page + $(page).find('.vp-data-option-box').html(this.templateForOption(this.state.loadType)); + + return page; } + templateForOption(loadType) { + let config = this.mlConfig[loadType]; + let state = this.state; + + let optBox = new com_String(); + // render tag + config.options.forEach(opt => { + optBox.appendFormatLine('' + , opt.name, opt.name, opt.name); + let content = com_generator.renderContent(this, opt.component[0], opt, state); + optBox.appendLine(content[0].outerHTML); + }); + + // show user option + if (config.code.includes('${etc}')) { + // render user option + optBox.appendFormatLine('', 'userOption', 'User option'); + optBox.appendFormatLine('', + 'userOption', 'key=value, ...', this.state.userOption); + } + return optBox.toString(); + } + + generateCode() { + let { loadType, userOption, allocateTo } = this.state; + let code = new com_String(); + let config = this.mlConfig[loadType]; + code.appendLine(config.import); + code.appendLine(); + + // model code + let modelCode = config.code; + modelCode = com_generator.vp_codeGenerator(this, config, this.state, userOption); + + if (this.loadTypeList['Load Data'].includes(loadType)) { + code.appendFormatLine('{0} = {1}', allocateTo, modelCode); + // FIXME: decide between 2 codes + // code.appendFormat("df_{0} = pd.concat([pd.DataFrame({1}.data, columns={2}.feature_names), pd.DataFrame({3}.target, columns=['target'])], axis=1)", allocateTo, allocateTo, allocateTo, allocateTo); + code.appendFormat("df_{0} = pd.DataFrame(np.hstack(({1}.data, {2}.target.reshape(-1,1))), columns=np.hstack(({3}.feature_names, ['target'])))", allocateTo, allocateTo, allocateTo, allocateTo); + } else { + code.appendFormatLine("_X, _y = {0}", modelCode); + code.appendLine("_columns = np.hstack((['X{}'.format(i+1) for i in range(len(_X[0]))],['target']))"); + code.appendFormat("{0} = pd.DataFrame(np.hstack((_X, _y.reshape(-1,1))), columns=_columns)", allocateTo); + } + + if (allocateTo != '') { + code.appendLine(); + code.append(allocateTo); + } + + + return code.toString(); + } } return DataSets; From 3a81ca879be83040d51b10c52c429c8564cc19b9 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Fri, 4 Mar 2022 15:47:14 +0900 Subject: [PATCH 02/27] Set default title for Hide VP Note --- html/menuFrame.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/menuFrame.html b/html/menuFrame.html index 084cba6e..37919802 100644 --- a/html/menuFrame.html +++ b/html/menuFrame.html @@ -51,7 +51,7 @@
-
+
From cff4cbeee0c0a5f9e0741b29231a81831512e37f Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Mon, 7 Mar 2022 02:04:44 +0900 Subject: [PATCH 03/27] Fix AutoML --- data/m_ml/mlLibrary.js | 74 ++++++++++++++++++++++++++++----------- js/com/com_generatorV2.js | 3 +- js/m_ml/AutoML.js | 7 ++-- js/m_ml/DataPrep.js | 14 +++++--- 4 files changed, 67 insertions(+), 31 deletions(-) diff --git a/data/m_ml/mlLibrary.js b/data/m_ml/mlLibrary.js index 4ada0871..9d72c776 100644 --- a/data/m_ml/mlLibrary.js +++ b/data/m_ml/mlLibrary.js @@ -128,9 +128,10 @@ define([ 'prep-onehot': { name: 'OneHotEncoder', import: 'from sklearn.preprocessing import OneHotEncoder', - code: 'OneHotEncoder()', + code: 'OneHotEncoder(${handle_unknown}${etc})', options: [ - + { name: 'handle_unknown', component: ['option_suggest'], usePair: true, + options: ['error', 'ignore'], default: 'error' }, ] }, 'prep-label': { @@ -144,66 +145,77 @@ define([ 'prep-ordinal': { name: 'OrdinalEncoder', import: 'from sklearn.preprocessing import OrdinalEncoder', - code: 'OrdinalEncoder()', + code: 'OrdinalEncoder(${handle_unknown}${unknown_values}${etc})', options: [ - + { name: 'handle_unknown', component: ['option_suggest'], usePair: true, + options: ['error', 'use_encoded_value'], default: 'error' }, + { name: 'unknown_values', component: ['input'], usePair: true } ] }, 'prep-target': { name: 'TargetEncoder', install: '!pip install category_encoders', import: 'from category_encoders.target_encoder import TargetEncoder', - code: 'TargetEncoder()', + code: 'TargetEncoder(${cols}${handle_missing}${handle_unknown}${smoothing}${etc})', options: [ - + { name: 'cols', component: ['var_suggest', '1darr'], usePair: true }, + { name: 'handle_missing', component: ['option_suggest'], usePair: true, + options: ['error', 'return_nan', 'value'], default: 'value' }, + { name: 'handle_unknown', component: ['option_suggest'], usePair: true, + options: ['error', 'return_nan', 'value'], default: 'value' }, + { name: 'smoothing', component: ['input_number'], default: 1.0, usePair: true } ] }, 'prep-smote': { name: 'SMOTE', install: '!pip install imblearn', - import: 'from imlearn.over_sampling import SMOTE', - code: 'SMOTE()', + import: 'from imblearn.over_sampling import SMOTE', + code: 'SMOTE(${random_state}${k_neighbors}${etc})', options: [ - + { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true }, + { name: 'k_neighbors', component: ['input_number'], default: 5, usePair: true } ] }, /** Data Preparation - Scaling */ 'prep-standard': { name: 'StandardScaler', import: 'from sklearn.preprocessing import StandardScaler', - code: 'StandardScaler()', + code: 'StandardScaler(${with_mean}${with_std}${etc})', options: [ - + { name: 'with_mean', component: ['bool_select'], default: 'True', usePair: true }, + { name: 'with_std', component: ['bool_select'], default: 'True', usePair: true } ] }, 'prep-robust': { name: 'RobustScaler', import: 'from sklearn.preprocessing import RobustScaler', - code: 'RobustScaler()', + code: 'RobustScaler(${with_centering}${with_scaling}${etc})', options: [ - + { name: 'with_centering', component: ['bool_select'], default: 'True', usePair: true }, + { name: 'with_scaling', component: ['bool_select'], default: 'True', usePair: true } ] }, 'prep-minmax': { name: 'MinMaxScaler', import: 'from sklearn.preprocessing import MinMaxScaler', - code: 'MinMaxScaler()', + code: 'MinMaxScaler(${feature_range}${etc})', options: [ - + { name: 'feature_range', component: ['input'], placeholder: '(min, max)', default: '(0, 1)', usePair: true } ] }, 'prep-normalizer': { name: 'Normalizer', import: 'from sklearn.preprocessing import Normalizer', - code: 'Normalizer()', + code: 'Normalizer(${norm}${etc})', options: [ - + { name: 'norm', component: ['option_suggest'], usePair: true, + options: ['l1', 'l2', 'max'], default: 'l2' }, ] }, 'prep-func-trsfrm-log': { name: 'Log Scaling', import: 'from sklearn.preprocessing import FunctionTransformer', - code: 'FunctionTransformer(np.log1p)', + code: 'FunctionTransformer(np.log1p${etc})', options: [ ] @@ -211,7 +223,7 @@ define([ 'prep-func-trsfrm-exp': { name: 'Exponential Scaling', import: 'from sklearn.preprocessing import FunctionTransformer', - code: 'FunctionTransformer(np.expm1)', + code: 'FunctionTransformer(np.expm1${etc})', options: [ ] @@ -220,7 +232,7 @@ define([ 'ln-rgs': { name: 'LinearRegression', import: 'from sklearn.linear_model import LinearRegression', - code: 'LinearRegression(${fit_intercept})', + code: 'LinearRegression(${fit_intercept}${etc})', options: [ { name: 'fit_intercept', component: ['bool_select'], default: 'True', usePair: true } ] @@ -429,8 +441,19 @@ define([ ] }, /** Auto ML */ + 'auto-sklearn-rgs': { + name: 'AutoSklearnRegressor (Linux only)', + install: 'pip install auto-sklearn', + import: 'from autosklearn import AutoSklearnRegressor', + link: 'https://automl.github.io/auto-sklearn/master/api.html#regression', + code: 'AutoSklearnRegressor(${etc})', + options: [ + + ] + }, 'tpot-rgs': { name: 'TPOTRegressor', + install: 'pip install tpot', import: 'from tpot import TPOTRegressor', code: 'TPOTRegressor(${generation}${population_size}${cv}${random_state}${etc})', options: [ @@ -440,8 +463,19 @@ define([ { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } ] }, + 'auto-sklearn-clf': { + name: 'AutoSklearnClassifier (Linux only)', + install: 'pip install auto-sklearn', + import: 'from autosklearn import AutoSklearnClassifier', + link: 'https://automl.github.io/auto-sklearn/master/api.html#classification', + code: 'AutoSklearnClassifier(${etc})', + options: [ + + ] + }, 'tpot-clf': { name: 'TPOTClassifier', + install: 'pip install tpot', import: 'from tpot import TPOTClassifier', code: 'TPOTClassifier(${generation}${population_size}${cv}${random_state}${etc})', options: [ diff --git a/js/com/com_generatorV2.js b/js/com/com_generatorV2.js index 05da2e0b..76544590 100644 --- a/js/com/com_generatorV2.js +++ b/js/com/com_generatorV2.js @@ -37,7 +37,8 @@ define([ 'col_select': 'Select Column', 'textarea': 'Input textarea', 'input_number': 'Input number', - 'input': 'Input text' + 'input_text': 'Input text', + 'input': 'Input value' } const _VP_BOOL_OPTIONS = [ diff --git a/js/m_ml/AutoML.js b/js/m_ml/AutoML.js index 4f0548e5..873d9be6 100644 --- a/js/m_ml/AutoML.js +++ b/js/m_ml/AutoML.js @@ -50,11 +50,8 @@ define([ this.modelConfig = ML_LIBRARIES; this.modelTypeList = { - // 'Regression': ['ln-rgs', 'sv-rgs', 'dt-rgs', 'rf-rgs', 'gbm-rgs', 'xgb-rgs', 'lgbm-rgs', 'cb-rgs'], - // 'Classfication': ['lg-rgs', 'sv-clf', 'dt-clf', 'rf-clf', 'gbm-clf', 'xgb-clf', 'lgbm-clf', 'cb-clf'], - 'Auto ML': ['tpot-rgs', 'tpot-clf'], - // 'Clustering': ['k-means', 'agg-cls', 'gaus-mix', 'dbscan'], - // 'Dimension Reduction': ['pca', 'lda', 'svd', 'nmf'] + 'Regression': ['auto-sklearn-rgs', 'tpot-rgs'], + 'Classification': ['auto-sklearn-clf', 'tpot-clf'] } diff --git a/js/m_ml/DataPrep.js b/js/m_ml/DataPrep.js index 333fd0c7..3639f595 100644 --- a/js/m_ml/DataPrep.js +++ b/js/m_ml/DataPrep.js @@ -17,12 +17,13 @@ define([ 'vp_base/js/com/com_util', 'vp_base/js/com/com_Const', 'vp_base/js/com/com_String', + 'vp_base/js/com/com_interface', 'vp_base/js/com/com_generatorV2', 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', 'vp_base/js/com/component/InstanceEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, InstanceEditor) { +], function(msHtml, com_util, com_Const, com_String, com_interface, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, InstanceEditor) { /** * DataPrep @@ -222,10 +223,13 @@ define([ let content = com_generator.renderContent(this, opt.component[0], opt, state); optBox.appendLine(content[0].outerHTML); }); - // render user option - optBox.appendFormatLine('', 'userOption', 'User option'); - optBox.appendFormatLine('', - 'userOption', 'key=value, ...', this.state.userOption); + // show user option + if (config.code.includes('${etc}')) { + // render user option + optBox.appendFormatLine('', 'userOption', 'User option'); + optBox.appendFormatLine('', + 'userOption', 'key=value, ...', this.state.userOption); + } return optBox.toString(); } From 611e1aae01223c07f64a3f32bbf11d5e2dfc3653 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Fri, 11 Mar 2022 11:37:03 +0900 Subject: [PATCH 04/27] Add auto-sklearn to AutoML --- html/m_ml/model.html | 15 +++++++++------ js/com/com_Config.js | 4 ++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/html/m_ml/model.html b/html/m_ml/model.html index 630ed259..f33a2914 100644 --- a/html/m_ml/model.html +++ b/html/m_ml/model.html @@ -19,12 +19,6 @@ -
- - - - -
@@ -42,6 +36,15 @@
+
+ +
+ \ No newline at end of file diff --git a/js/com/com_Config.js b/js/com/com_Config.js index 74987dba..eb8d41ec 100644 --- a/js/com/com_Config.js +++ b/js/com/com_Config.js @@ -483,13 +483,13 @@ define([ */ Config.ML_DATA_DICT = { 'Regression': [ - 'LinearRegression', 'SVR', 'DecisionTreeRegressor', 'RandomForestRegression', 'GradientBoostingRegressor', 'XGBRegressor', 'LGBMRegressor', 'CatBoostRegressor', + 'LinearRegression', 'SVR', 'DecisionTreeRegressor', 'RandomForestRegressor', 'GradientBoostingRegressor', 'XGBRegressor', 'LGBMRegressor', 'CatBoostRegressor', ], 'Classification': [ 'LogisticRegression', 'SVC', 'DecisionTreeClassifier', 'RandomForestClassifier', 'GradientBoostingClassifier', 'XGBClassifier', 'LGBMClassifier', 'CatBoostClassifier', ], 'Auto ML': [ - 'TPOTRegression', 'TPOTClassifier' + 'AutoSklearnRegressor', 'AutoSklearnClassifier', 'TPOTRegression', 'TPOTClassifier' ], 'Clustering': [ 'KMeans', 'AgglomerativeClustering', 'GaussianMixture', 'DBSCAN', From 38c8edd9dfd776544b62ad04892bcd437659bbd0 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Fri, 11 Mar 2022 12:04:49 +0900 Subject: [PATCH 05/27] Add ML apps icon & color --- css/boardFrame.css | 4 ++-- css/menuFrame.css | 9 ++++++++ data/libraries.json | 38 ++++++++++++++++---------------- img/apps/apps_automl.svg | 9 ++++++++ img/apps/apps_classification.svg | 8 +++++++ img/apps/apps_clustering.svg | 6 +++++ img/apps/apps_dataprep.svg | 5 +++++ img/apps/apps_dataset.svg | 7 ++++++ img/apps/apps_dimension.svg | 6 +++++ img/apps/apps_regression.svg | 10 +++++++++ js/menu/MenuItem.js | 5 +---- 11 files changed, 82 insertions(+), 25 deletions(-) create mode 100644 img/apps/apps_automl.svg create mode 100644 img/apps/apps_classification.svg create mode 100644 img/apps/apps_clustering.svg create mode 100644 img/apps/apps_dataprep.svg create mode 100644 img/apps/apps_dataset.svg create mode 100644 img/apps/apps_dimension.svg create mode 100644 img/apps/apps_regression.svg diff --git a/css/boardFrame.css b/css/boardFrame.css index 57bf5ab6..1614a371 100644 --- a/css/boardFrame.css +++ b/css/boardFrame.css @@ -238,11 +238,11 @@ background-color: rgb(253, 177, 133); } .vp-block.machine_learning .vp-block-header { - background-color: rgb(249, 227, 214); + background-color: #E8ECD0; } .vp-block.machine_learning.vp-focus .vp-block-header, .vp-block.machine_learning.vp-focus-child .vp-block-header { - background-color: rgb(253, 177, 133); + background-color: #C6CE94; } .vp-block.logic-define .vp-block-header { background-color: rgb(213, 231, 222); diff --git a/css/menuFrame.css b/css/menuFrame.css index 68303d1e..2e3bec6f 100644 --- a/css/menuFrame.css +++ b/css/menuFrame.css @@ -229,6 +229,15 @@ .vp-menuitem.apps.vp-color-apps4 { background: #E56139; } +.vp-menuitem.apps.vp-color-apps5 { + background: #BEB727; +} +.vp-menuitem.apps.vp-color-apps6 { + background: #91A541; +} +.vp-menuitem.apps.vp-color-apps7 { + background: #718E41; +} .vp-menuitem.apps.vp-color-preparing { background: var(--gray-color); } diff --git a/data/libraries.json b/data/libraries.json index d2e0cad9..c04ad2a8 100644 --- a/data/libraries.json +++ b/data/libraries.json @@ -3111,8 +3111,8 @@ "desc" : "Data sets for machine learning", "file" : "m_ml/DataSets", "apps" : { - "color": 1, - "icon": "apps/apps_white.svg" + "color": 5, + "icon": "apps/apps_dataset.svg" } }, { @@ -3125,8 +3125,8 @@ "desc" : "Data preparation for machine learning", "file" : "m_ml/DataPrep", "apps" : { - "color": 1, - "icon": "apps/apps_white.svg" + "color": 5, + "icon": "apps/apps_dataprep.svg" } }, { @@ -3139,7 +3139,7 @@ "desc" : "Data split for machine learning", "file" : "m_ml/dataSplit", "apps" : { - "color": 1, + "color": 5, "icon": "apps/apps_datasplit.svg" } }, @@ -3147,28 +3147,28 @@ "id" : "ml_regression", "type" : "function", "level": 1, - "name" : "Regression", + "name" : "Regressor", "tag" : "REGRESSION,MODEL,MACHINE LEARNING,ML", "path" : "visualpython - machine_learning - regression", "desc" : "Regression model for machine learning", "file" : "m_ml/Regression", "apps" : { - "color": 1, - "icon": "apps/apps_model.svg" + "color": 5, + "icon": "apps/apps_regression.svg" } }, { "id" : "ml_classification", "type" : "function", "level": 1, - "name" : "Classification", + "name" : "Classifier", "tag" : "CLASSIFICATION,MODEL,MACHINE LEARNING,ML", "path" : "visualpython - machine_learning - classification", "desc" : "Classification model for machine learning", "file" : "m_ml/Classification", "apps" : { - "color": 1, - "icon": "apps/apps_model.svg" + "color": 6, + "icon": "apps/apps_classification.svg" } }, { @@ -3181,22 +3181,22 @@ "desc" : "Clustering model for machine learning", "file" : "m_ml/Clustering", "apps" : { - "color": 1, - "icon": "apps/apps_model.svg" + "color": 6, + "icon": "apps/apps_clustering.svg" } }, { "id" : "ml_dimensionReduction", "type" : "function", "level": 1, - "name" : "Dimension Reduction", + "name" : "Dimension", "tag" : "DIMENSION REDUCTION,MODEL,MACHINE LEARNING,ML", "path" : "visualpython - machine_learning - dimension_reduction", "desc" : "Dimension reduction model for machine learning", "file" : "m_ml/DimensionReduction", "apps" : { - "color": 1, - "icon": "apps/apps_model.svg" + "color": 6, + "icon": "apps/apps_dimension.svg" } }, { @@ -3209,8 +3209,8 @@ "desc" : "AutoML model for machine learning", "file" : "m_ml/AutoML", "apps" : { - "color": 1, - "icon": "apps/apps_model.svg" + "color": 6, + "icon": "apps/apps_automl.svg" } }, { @@ -3223,7 +3223,7 @@ "desc" : "Performance evaluation for machine learning", "file" : "m_ml/evaluation", "apps" : { - "color": 1, + "color": 7, "icon": "apps/apps_evaluate.svg" } } diff --git a/img/apps/apps_automl.svg b/img/apps/apps_automl.svg new file mode 100644 index 00000000..06a0ff7f --- /dev/null +++ b/img/apps/apps_automl.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/img/apps/apps_classification.svg b/img/apps/apps_classification.svg new file mode 100644 index 00000000..5e6d91ea --- /dev/null +++ b/img/apps/apps_classification.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/img/apps/apps_clustering.svg b/img/apps/apps_clustering.svg new file mode 100644 index 00000000..ae50c87c --- /dev/null +++ b/img/apps/apps_clustering.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/img/apps/apps_dataprep.svg b/img/apps/apps_dataprep.svg new file mode 100644 index 00000000..7219b79b --- /dev/null +++ b/img/apps/apps_dataprep.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/img/apps/apps_dataset.svg b/img/apps/apps_dataset.svg new file mode 100644 index 00000000..37028753 --- /dev/null +++ b/img/apps/apps_dataset.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/img/apps/apps_dimension.svg b/img/apps/apps_dimension.svg new file mode 100644 index 00000000..264f3902 --- /dev/null +++ b/img/apps/apps_dimension.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/img/apps/apps_regression.svg b/img/apps/apps_regression.svg new file mode 100644 index 00000000..cb67005f --- /dev/null +++ b/img/apps/apps_regression.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/js/menu/MenuItem.js b/js/menu/MenuItem.js index f57643bc..2d3d3d7c 100644 --- a/js/menu/MenuItem.js +++ b/js/menu/MenuItem.js @@ -55,10 +55,7 @@ define([ switch(color) { case 0: return 'vp-color-preparing'; - case 1: - case 2: - case 3: - case 4: + default: return 'vp-color-apps' + color; } } else { From 151143f727d5472eb448fd2a7dc1c4a128f285c7 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Fri, 11 Mar 2022 12:14:55 +0900 Subject: [PATCH 06/27] Fix DataSets code to create DataFrame --- js/m_ml/DataSets.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/js/m_ml/DataSets.js b/js/m_ml/DataSets.js index bdd2bd5f..479bdf02 100644 --- a/js/m_ml/DataSets.js +++ b/js/m_ml/DataSets.js @@ -133,20 +133,24 @@ define([ let modelCode = config.code; modelCode = com_generator.vp_codeGenerator(this, config, this.state, userOption); + let allocateToVar = allocateTo; if (this.loadTypeList['Load Data'].includes(loadType)) { code.appendFormatLine('{0} = {1}', allocateTo, modelCode); - // FIXME: decide between 2 codes - // code.appendFormat("df_{0} = pd.concat([pd.DataFrame({1}.data, columns={2}.feature_names), pd.DataFrame({3}.target, columns=['target'])], axis=1)", allocateTo, allocateTo, allocateTo, allocateTo); - code.appendFormat("df_{0} = pd.DataFrame(np.hstack(({1}.data, {2}.target.reshape(-1,1))), columns=np.hstack(({3}.feature_names, ['target'])))", allocateTo, allocateTo, allocateTo, allocateTo); + code.appendLine("# Create DataFrame"); + code.appendFormatLine("df_{0} = pd.DataFrame(data={1}.data, columns={2}.feature_names)", allocateTo, allocateTo, allocateTo); + code.appendFormat("df_{0}['target'] = {1}.target", allocateTo, allocateTo); + allocateToVar = 'df_' + allocateTo; } else { code.appendFormatLine("_X, _y = {0}", modelCode); - code.appendLine("_columns = np.hstack((['X{}'.format(i+1) for i in range(len(_X[0]))],['target']))"); - code.appendFormat("{0} = pd.DataFrame(np.hstack((_X, _y.reshape(-1,1))), columns=_columns)", allocateTo); + code.appendLine("# Create DataFrame"); + code.appendLine("_feature_names = ['X{}'.format(i+1) for i in range(len(_X[0]))]"); + code.appendFormatLine("{0} = pd.DataFrame(data=_X, columns=_feature_names)", allocateTo); + code.appendFormat("{0}['target'] = _y", allocateTo); } - if (allocateTo != '') { + if (allocateToVar != '') { code.appendLine(); - code.append(allocateTo); + code.append(allocateToVar); } From 769ed3f67670c6a439d73bfce00e8b4fac02e7d9 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Fri, 11 Mar 2022 15:51:23 +0900 Subject: [PATCH 07/27] Add some models --- data/m_ml/mlLibrary.js | 72 +++++++++++++++++++++++++++++++++-- js/com/com_Config.js | 8 ++-- js/m_ml/Classification.js | 6 +-- js/m_ml/DataPrep.js | 8 +--- js/m_ml/DimensionReduction.js | 6 +-- js/m_ml/Regression.js | 6 +-- 6 files changed, 77 insertions(+), 29 deletions(-) diff --git a/data/m_ml/mlLibrary.js b/data/m_ml/mlLibrary.js index 9d72c776..ed6e2438 100644 --- a/data/m_ml/mlLibrary.js +++ b/data/m_ml/mlLibrary.js @@ -228,6 +228,14 @@ define([ ] }, + 'prep-poly-feat': { + name: 'Polynomial Features', + import: 'from sklearn.preprocessing import PolynomialFeatures', + code: 'PolynomialFeatures(${etc})', + options: [ + + ] + }, /** Regression */ 'ln-rgs': { name: 'LinearRegression', @@ -237,6 +245,30 @@ define([ { name: 'fit_intercept', component: ['bool_select'], default: 'True', usePair: true } ] }, + 'ridge': { + name: 'Ridge', + import: 'from sklearn.linear_model import Ridge', + code: 'Ridge(${etc})', + options: [ + //TODO: + ] + }, + 'lasso': { + name: 'Lasso', + import: 'from sklearn.linear_model import Lasso', + code: 'Lasso(${etc})', + options: [ + //TODO: + ] + }, + 'elasticnet': { + name: 'ElasticNet', + import: 'from sklearn.linear_model import ElasticNet', + code: 'ElasticNet(${etc})', + options: [ + //TODO: + ] + }, 'sv-rgs': { name: 'SVR', import: 'from sklearn.svm import SVR', @@ -344,6 +376,30 @@ define([ { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } ] }, + 'bern-nb': { + name: 'BernoulliNB', + import: 'from sklearn.naive_bayes import BernoulliNB', + code: 'BernoulliNB(${etc})', + options: [ + //TODO: + ] + }, + 'mulnom-nb': { + name: 'MultinomialNB', + import: 'from sklearn.naive_bayes import MultinomialNB', + code: 'MultinomialNB(${etc})', + options: [ + //TODO: + ] + }, + 'gaus-nb': { + name: 'GaussianNB', + import: 'from sklearn.naive_bayes import GaussianNB', + code: 'GaussianNB(${etc})', + options: [ + //TODO: + ] + }, 'sv-clf': { name: 'SupportVectorClassifier', import: 'from sklearn.svm import SVC', @@ -524,7 +580,7 @@ define([ }, /** Dimension Reduction */ 'pca': { - name: 'Principal Component Analysis', + name: 'PCA(Principal Component Analysis)', import: 'from sklearn.decomposition import PCA', code: 'PCA(${n_components}${random_state}${etc})', options: [ @@ -533,7 +589,7 @@ define([ ] }, 'lda': { - name: 'Linear Discriminant Analysis', + name: 'LDA(Linear Discriminant Analysis)', import: 'from sklearn.discriminant_analysis import LinearDiscriminantAnalysis', code: 'LinearDiscriminantAnalysis(${n_components}${etc})', options: [ @@ -550,13 +606,23 @@ define([ ] }, 'nmf': { - name: 'Non-Negative Matrix Factorization', + name: 'NMF(Non-Negative Matrix Factorization)', import: 'from sklearn.decomposition import NMF', code: 'NMF(${n_components}${random_state}${etc})', options: [ { name: 'n_components', component: ['input_number'], placeholder: 'None', usePair: true }, { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } ] + }, + 'tsne': { + name: 'TSNE(T-distributed Stochastic Neighbor Embedding)', + import: 'from sklearn.manifold import TSNE', + code: 'TSNE(${n_components}${learning_rate}${random_state}${etc})', + options: [ + { name: 'n_components', component: ['input_number'], placeholder: 'None', usePair: true }, + { name: 'learning_rate', component: ['input_number'], default: 200.0, usePair: true }, + { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } + ] } } diff --git a/js/com/com_Config.js b/js/com/com_Config.js index eb8d41ec..45921134 100644 --- a/js/com/com_Config.js +++ b/js/com/com_Config.js @@ -483,10 +483,10 @@ define([ */ Config.ML_DATA_DICT = { 'Regression': [ - 'LinearRegression', 'SVR', 'DecisionTreeRegressor', 'RandomForestRegressor', 'GradientBoostingRegressor', 'XGBRegressor', 'LGBMRegressor', 'CatBoostRegressor', + 'LinearRegression', 'Ridge', 'Lasso', 'ElasticNet', 'SVR', 'DecisionTreeRegressor', 'RandomForestRegressor', 'GradientBoostingRegressor', 'XGBRegressor', 'LGBMRegressor', 'CatBoostRegressor', ], 'Classification': [ - 'LogisticRegression', 'SVC', 'DecisionTreeClassifier', 'RandomForestClassifier', 'GradientBoostingClassifier', 'XGBClassifier', 'LGBMClassifier', 'CatBoostClassifier', + 'LogisticRegression', 'BernoulliNB', 'MultinomialNB', 'GaussianNB', 'SVC', 'DecisionTreeClassifier', 'RandomForestClassifier', 'GradientBoostingClassifier', 'XGBClassifier', 'LGBMClassifier', 'CatBoostClassifier', ], 'Auto ML': [ 'AutoSklearnRegressor', 'AutoSklearnClassifier', 'TPOTRegression', 'TPOTClassifier' @@ -495,13 +495,13 @@ define([ 'KMeans', 'AgglomerativeClustering', 'GaussianMixture', 'DBSCAN', ], 'Dimension Reduction': [ - 'PCA', 'LinearDiscriminantAnalysis', 'TruncatedSVD', 'NMF' + 'PCA', 'LinearDiscriminantAnalysis', 'TruncatedSVD', 'NMF', 'TSNE' ], 'Data Preparation': [ /** Encoding */ 'OneHotEncoder', 'LabelEncoder', 'OrdinalEncoder', 'TargetEncoder', 'SMOTE', /** Scaling */ - 'StandardScaler', 'RobustScaler', 'MinMaxScaler', 'Normalizer', 'FunctionTransformer' + 'StandardScaler', 'RobustScaler', 'MinMaxScaler', 'Normalizer', 'FunctionTransformer', 'PolynomialFeatures' ] }; diff --git a/js/m_ml/Classification.js b/js/m_ml/Classification.js index dc97f0e7..c6cb9bec 100644 --- a/js/m_ml/Classification.js +++ b/js/m_ml/Classification.js @@ -50,11 +50,7 @@ define([ this.modelConfig = ML_LIBRARIES; this.modelTypeList = { - // 'Regression': ['ln-rgs', 'sv-rgs', 'dt-rgs', 'rf-rgs', 'gbm-rgs', 'xgb-rgs', 'lgbm-rgs', 'cb-rgs'], - 'Classfication': ['lg-rgs', 'sv-clf', 'dt-clf', 'rf-clf', 'gbm-clf', 'xgb-clf', 'lgbm-clf', 'cb-clf'], - // 'Auto ML': ['tpot-rgs', 'tpot-clf'], - // 'Clustering': ['k-means', 'agg-cls', 'gaus-mix', 'dbscan'], - // 'Dimension Reduction': ['pca', 'lda', 'svd', 'nmf'] + 'Classfication': ['lg-rgs', 'bern-nb', 'mulnom-nb', 'gaus-nb', 'sv-clf', 'dt-clf', 'rf-clf', 'gbm-clf', 'xgb-clf', 'lgbm-clf', 'cb-clf'], } diff --git a/js/m_ml/DataPrep.js b/js/m_ml/DataPrep.js index 3639f595..54ce4cf3 100644 --- a/js/m_ml/DataPrep.js +++ b/js/m_ml/DataPrep.js @@ -52,13 +52,7 @@ define([ this.modelTypeList = { 'Encoding': ['prep-onehot', 'prep-label', 'prep-ordinal', 'prep-target', 'prep-smote'], - 'Scaling': ['prep-standard', 'prep-robust', 'prep-minmax', 'prep-normalizer', 'prep-func-trsfrm-log', 'prep-func-trsfrm-exp'] - - // 'Regression': ['ln-rgs', 'sv-rgs', 'dt-rgs', 'rf-rgs', 'gbm-rgs', 'xgb-rgs', 'lgbm-rgs', 'cb-rgs'], - // 'Classfication': ['lg-rgs', 'sv-clf', 'dt-clf', 'rf-clf', 'gbm-clf', 'xgb-clf', 'lgbm-clf', 'cb-clf'], - // 'Auto ML': ['tpot-rgs', 'tpot-clf'], - // 'Clustering': ['k-means', 'agg-cls', 'gaus-mix', 'dbscan'], - // 'Dimension Reduction': ['pca', 'lda', 'svd', 'nmf'] + 'Scaling': ['prep-standard', 'prep-robust', 'prep-minmax', 'prep-normalizer', 'prep-func-trsfrm-log', 'prep-func-trsfrm-exp', 'prep-poly-feat'] } diff --git a/js/m_ml/DimensionReduction.js b/js/m_ml/DimensionReduction.js index 93ba2686..bd6eb20a 100644 --- a/js/m_ml/DimensionReduction.js +++ b/js/m_ml/DimensionReduction.js @@ -50,11 +50,7 @@ define([ this.modelConfig = ML_LIBRARIES; this.modelTypeList = { - // 'Regression': ['ln-rgs', 'sv-rgs', 'dt-rgs', 'rf-rgs', 'gbm-rgs', 'xgb-rgs', 'lgbm-rgs', 'cb-rgs'], - // 'Classfication': ['lg-rgs', 'sv-clf', 'dt-clf', 'rf-clf', 'gbm-clf', 'xgb-clf', 'lgbm-clf', 'cb-clf'], - // 'Auto ML': ['tpot-rgs', 'tpot-clf'], - // 'Clustering': ['k-means', 'agg-cls', 'gaus-mix', 'dbscan'], - 'Dimension Reduction': ['pca', 'lda', 'svd', 'nmf'] + 'Dimension Reduction': ['pca', 'lda', 'svd', 'nmf', 'tsne'] } diff --git a/js/m_ml/Regression.js b/js/m_ml/Regression.js index 7a08dd68..97d3b7cb 100644 --- a/js/m_ml/Regression.js +++ b/js/m_ml/Regression.js @@ -50,11 +50,7 @@ define([ this.modelConfig = ML_LIBRARIES; this.modelTypeList = { - 'Regression': ['ln-rgs', 'sv-rgs', 'dt-rgs', 'rf-rgs', 'gbm-rgs', 'xgb-rgs', 'lgbm-rgs', 'cb-rgs'], - // 'Classfication': ['lg-rgs', 'sv-clf', 'dt-clf', 'rf-clf', 'gbm-clf', 'xgb-clf', 'lgbm-clf', 'cb-clf'], - // 'Auto ML': ['tpot-rgs', 'tpot-clf'], - // 'Clustering': ['k-means', 'agg-cls', 'gaus-mix', 'dbscan'], - // 'Dimension Reduction': ['pca', 'lda', 'svd', 'nmf'] + 'Regression': ['ln-rgs', 'ridge', 'lasso', 'elasticnet', 'sv-rgs', 'dt-rgs', 'rf-rgs', 'gbm-rgs', 'xgb-rgs', 'lgbm-rgs', 'cb-rgs'], } From 2caaf0e0bda7eef8e64dd09d69ecb52e9c3bc440 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Fri, 11 Mar 2022 19:19:13 +0900 Subject: [PATCH 08/27] Fix ModelSelection page using ModelEditor --- css/component/instanceEditor.css | 4 +- html/m_ml/evaluation.html | 4 +- html/m_ml/model.html | 4 +- js/com/com_generatorV2.js | 5 +- js/com/component/InstanceEditor.js | 2 - js/com/component/ModelEditor.js | 324 +++++++++++++++++++++++++++++ js/m_ml/AutoML.js | 27 ++- js/m_ml/Classification.js | 27 ++- js/m_ml/Clustering.js | 27 ++- js/m_ml/DimensionReduction.js | 27 ++- js/m_ml/Regression.js | 27 ++- js/m_ml/evaluation.js | 2 +- 12 files changed, 418 insertions(+), 62 deletions(-) create mode 100644 js/com/component/ModelEditor.js diff --git a/css/component/instanceEditor.css b/css/component/instanceEditor.css index 922872b3..1df973c2 100644 --- a/css/component/instanceEditor.css +++ b/css/component/instanceEditor.css @@ -17,8 +17,8 @@ .vp-ins-select-container .vp-ins-search-icon { position: absolute; color: #C4C4C4; - right: 5px; - top: 5px; + right: 7px; + top: 7px; } .vp-ins-select-box { margin-top: 5px; diff --git a/html/m_ml/evaluation.html b/html/m_ml/evaluation.html index b263afc7..8079b5d9 100644 --- a/html/m_ml/evaluation.html +++ b/html/m_ml/evaluation.html @@ -7,11 +7,9 @@
diff --git a/html/m_ml/model.html b/html/m_ml/model.html index f33a2914..9a94fc9c 100644 --- a/html/m_ml/model.html +++ b/html/m_ml/model.html @@ -20,8 +20,8 @@
- - + +
diff --git a/js/com/com_generatorV2.js b/js/com/com_generatorV2.js index 76544590..c7c86b73 100644 --- a/js/com/com_generatorV2.js +++ b/js/com/com_generatorV2.js @@ -11,8 +11,9 @@ define([ 'vp_base/js/com/com_util', 'vp_base/js/com/com_makeDom', - 'vp_base/js/com/component/SuggestInput' -], function (com_util, com_makeDom, SuggestInput) { + 'vp_base/js/com/component/SuggestInput', + 'vp_base/js/com/component/VarSelector2' +], function (com_util, com_makeDom, SuggestInput, VarSelector2) { /** * show result after code executed */ diff --git a/js/com/component/InstanceEditor.js b/js/com/component/InstanceEditor.js index c3d78f35..ee3daf02 100644 --- a/js/com/component/InstanceEditor.js +++ b/js/com/component/InstanceEditor.js @@ -1,5 +1,3 @@ -const { param } = require("jquery"); - define([ 'css!vp_base/css/component/instanceEditor.css', 'vp_base/js/com/com_String', diff --git a/js/com/component/ModelEditor.js b/js/com/component/ModelEditor.js new file mode 100644 index 00000000..b6a3d218 --- /dev/null +++ b/js/com/component/ModelEditor.js @@ -0,0 +1,324 @@ +define([ + 'css!vp_base/css/component/instanceEditor.css', + 'vp_base/js/com/com_String', + 'vp_base/js/com/com_util', + 'vp_base/js/com/com_generatorV2', + 'vp_base/js/com/component/Component', + 'vp_base/js/com/component/SuggestInput' +], function(insCss, com_String, com_util, com_generator, Component, SuggestInput) { + + // temporary const + const VP_INS_BOX = 'vp-ins-box'; + const VP_INS_SELECT_CONTAINER = 'vp-ins-select-container'; + const VP_INS_SELECT_TITLE = 'vp-ins-select-title'; + const VP_INS_SEARCH = 'vp-ins-search'; + const VP_INS_TYPE = 'vp-ins-type'; + const VP_INS_SELECT_BOX = 'vp-ins-select-box'; + const VP_INS_SELECT_LIST = 'vp-ins-select-list'; + const VP_INS_SELECT_ITEM = 'vp-ins-select-item'; + + const VP_INS_PARAMETER_BOX = 'vp-ins-parameter-box'; + const VP_INS_PARAMETER = 'vp-ins-parameter'; + + const VP_CREATE_VAR_BOX = 'vp-create-var-box'; + const VP_CREATE_VAR = 'vp-create-var'; + const VP_CREATE_VAR_BTN = 'vp-create-var-btn'; + + class ModelEditor extends Component { + constructor(pageThis, targetId, containerId='vp_wrapper') { + super(null, { pageThis: pageThis, targetId: targetId, containerId: containerId }); + } + + _init() { + super._init(); + + this.pageThis = this.state.pageThis; + this.targetId = this.state.targetId; + this.containerId = this.state.containerId; + + this.state = { + action: {}, + info: {}, + config: {}, + ...this.state + } + } + + render() { + ; + } + + getModelCategory(modelType) { + let mlDict = vpConfig.getMLDataDict(); + let keys = Object.keys(mlDict); + let modelCategory = ''; + for (let i = 0; i < keys.length; i++) { + let key = keys[i]; + if (mlDict[key].includes(modelType)) { + modelCategory = key; + break; + } + } + return modelCategory; + } + + getAction(modelType) { + let category = this.getModelCategory(modelType); + let defaultActions = { + 'fit': { + name: 'fit', + code: '${model}.fit(${featureData}, ${targetData})', + options: [ + { name: 'featureData', component: ['var_select'], var_type: ['DataFrame'], default: 'X_train' }, + { name: 'targetData', component: ['var_select'], var_type: ['DataFrame'], default: 'y_train' } + ] + }, + 'predict': { + name: 'predict', + code: '${model}.predict(${featureData})', + options: [ + { name: 'featureData', component: ['var_select'], var_type: ['DataFrame'], default: 'X_train' } + ] + }, + 'predict_proba': { + name: 'predict_proba', + code: '${model}.predict_proba(${featureData})', + options: [ + { name: 'featureData', component: ['var_select'], var_type: ['DataFrame'], default: 'X_train' } + ] + }, + 'transform': { + name: 'transform', + code: '${model}.transform(${featureData})', + options: [ + { name: 'featureData', component: ['var_select'], var_type: ['DataFrame'], default: 'X_train' } + ] + } + }; + let actions = {}; + switch (category) { + case 'Regression': + actions = { + 'fit': defaultActions['fit'], + 'predict': defaultActions['predict'], + } + break; + case 'Classification': + actions = { + 'fit': defaultActions['fit'], + 'predict': defaultActions['predict'], + 'predict_proba': defaultActions['predict_proba'], + } + break; + case 'Auto ML': + actions = { + 'fit': defaultActions['fit'], + 'predict': defaultActions['predict'], + } + break; + case 'Clustering': + actions = { + 'fit': defaultActions['fit'], + 'predict': defaultActions['predict'], + } + break; + case 'Dimension Reduction': + actions = { + 'fit': defaultActions['fit'], + 'transform': defaultActions['transform'], + } + break; + } + return actions; + } + + getInfo(modelType) { + let category = this.getModelCategory(modelType); + let infos = {}; + let defaultInfos = { + 'score': { + name: 'score', + code: '${model}.score()', + options: [ + + ] + } + } + switch (category) { + case 'Regression': + infos = { + 'score': defaultInfos['score'] + } + break; + case 'Classification': + break; + case 'Auto ML': + break; + case 'Clustering': + break; + case 'Dimension Reduction': + break; + } + return infos; + } + + renderPage() { + var tag = new com_String(); + tag.appendFormatLine('
', VP_INS_BOX, this.uuid); // vp-select-base + + tag.appendFormatLine('
', VP_INS_SELECT_CONTAINER, 'action'); + tag.appendFormatLine('
Action
', VP_INS_SELECT_TITLE); + + tag.appendFormatLine('
', 'position: relative;'); + tag.appendFormatLine('', VP_INS_SEARCH, 'attr'); + tag.appendFormatLine('', VP_INS_TYPE, 'action'); + tag.appendFormatLine('', 'fa fa-search', 'vp-ins-search-icon'); + tag.appendLine('
'); + + tag.appendFormatLine('
', VP_INS_SELECT_BOX, 'action'); + tag.appendFormatLine('
    ', VP_INS_SELECT_LIST, 'action'); + tag.appendLine('
'); + tag.appendLine('
'); // VP_INS_SELECT_BOX + tag.appendLine('
'); // VP_INS_SELECT_CONTAINER + + tag.appendFormatLine('
', VP_INS_SELECT_CONTAINER, 'info'); + tag.appendFormatLine('
Info
', VP_INS_SELECT_TITLE); + + tag.appendFormatLine('
', 'position: relative;'); + tag.appendFormatLine('', VP_INS_SEARCH, 'method'); + tag.appendFormatLine('', VP_INS_TYPE, 'info'); + tag.appendFormatLine('', 'fa fa-search', 'vp-ins-search-icon'); + tag.appendLine('
'); + + tag.appendFormatLine('
', VP_INS_SELECT_BOX, 'info'); + tag.appendFormatLine('
    ', VP_INS_SELECT_LIST, 'info'); + tag.appendLine('
'); + tag.appendLine('
'); // VP_INS_SELECT_BOX + tag.appendLine('
'); // VP_INS_SELECT_CONTAINER + + tag.appendFormatLine('
Options
', VP_INS_SELECT_TITLE); + tag.appendFormatLine('
', VP_INS_PARAMETER_BOX); + // TODO: option box + + tag.appendLine('
'); // VP_INS_PARAMETER + + tag.appendLine('
'); // VP_INS_BOX END + + $(this.pageThis.wrapSelector('#' + this.containerId)).html(tag.toString()); + + return tag.toString(); + } + + reload() { + this.renderPage(); + + let targetTag = $(this.pageThis.wrapSelector('#' + this.targetId)); + let model = $(targetTag).val(); + let modelType = $(targetTag).find('option:selected').data('type'); + + let actions = this.getAction(modelType); + let infos = this.getInfo(modelType); + this.state.action = { ...actions }; + this.state.info = { ...infos }; + + var actListTag = new com_String(); + var infoListTag = new com_String(); + + Object.keys(actions).forEach(actKey => { + actListTag.appendFormatLine('
  • {4}
  • ', + VP_INS_SELECT_ITEM, actKey, 'action', actKey, actKey); + }); + Object.keys(infos).forEach(infoKey => { + infoListTag.appendFormatLine('
  • {4}
  • ', + VP_INS_SELECT_ITEM, infoKey, 'info', infoKey, infoKey); + }); + + $(this.wrapSelector('.' + VP_INS_SELECT_LIST + '.action')).html(actListTag.toString()); + $(this.wrapSelector('.' + VP_INS_SELECT_LIST + '.info')).html(infoListTag.toString()); + + let that = this; + // action search suggest + var suggestInput = new SuggestInput(); + suggestInput.addClass('vp-input action'); + suggestInput.addClass(VP_INS_SEARCH); + suggestInput.setPlaceholder("Search Action"); + suggestInput.setSuggestList(function () { return Object.keys(actions); }); + suggestInput.setSelectEvent(function (value, item) { + $(this.wrapSelector()).val(value); + $(that.wrapSelector('.' + VP_INS_TYPE + '.action')).val(item.type); + + $(that.pageThis.wrapSelector('#' + that.targetId)).trigger({ + type: "model_editor_selected", + varName: value, + varOptions: actions[value], + isMethod: false + }); + }); + $(that.wrapSelector('.' + VP_INS_SEARCH + '.action')).replaceWith(function () { + return suggestInput.toTagString(); + }); + + // info search suggest + suggestInput = new SuggestInput(); + suggestInput.addClass('vp-input info'); + suggestInput.addClass(VP_INS_SEARCH); + suggestInput.setPlaceholder("Search info"); + suggestInput.setSuggestList(function () { return Object.keys(infos); }); + suggestInput.setSelectEvent(function (value, item) { + $(this.wrapSelector()).val(value); + $(that.wrapSelector('.' + VP_INS_TYPE + '.info')).val(item.type); + + $(that.pageThis.wrapSelector('#' + that.targetId)).trigger({ + type: "model_editor_selected", + varName: value, + varOptions: infos[value], + isMethod: true + }); + }); + $(that.wrapSelector('.' + VP_INS_SEARCH + '.info')).replaceWith(function () { + return suggestInput.toTagString(); + }); + + // bind event + this._bindEvent(); + } + + _bindEvent() { + super._bindEvent(); + let that = this; + + $(this.wrapSelector('.' + VP_INS_SELECT_ITEM)).on('click', function() { + let name = $(this).data('var-name'); + let type = $(this).data('var-type'); + let config = that.state[type][name]; + let optBox = new com_String(); + // render tag + config.options.forEach(opt => { + optBox.appendFormatLine('' + , opt.name, opt.name, opt.name); + let content = com_generator.renderContent(that, opt.component[0], opt, that.pageThis.state); + optBox.appendLine(content[0].outerHTML); + }); + // replace option box + $(that.wrapSelector('.' + VP_INS_PARAMETER_BOX)).html(optBox.toString()); + + that.state.config = config; + }); + } + + show() { + $(this.wrapSelector()).show(); + this.reload(); + } + + hide() { + $(this.wrapSelector()).hide(); + } + + getCode() { + return com_generator.vp_codeGenerator(this.pageThis, this.state.config, this.pageThis.state); + } + } + + return ModelEditor; +}); \ No newline at end of file diff --git a/js/m_ml/AutoML.js b/js/m_ml/AutoML.js index 873d9be6..9886c24d 100644 --- a/js/m_ml/AutoML.js +++ b/js/m_ml/AutoML.js @@ -21,8 +21,8 @@ define([ 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', - 'vp_base/js/com/component/InstanceEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, InstanceEditor) { + 'vp_base/js/com/component/ModelEditor' +], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { /** * AutoML @@ -40,7 +40,7 @@ define([ userOption: '', featureData: 'X_train', targetData: 'y_train', - allocateTo: 'model', + allocateToCreation: 'model', // model selection model: '', method: '', @@ -91,6 +91,11 @@ define([ com_interface.insertCell('code', config.install); } }); + + // change model + $(this.wrapSelector('#model')).on('change', function() { + that.modelEditor.show(); + }) } templateForBody() { @@ -168,7 +173,7 @@ define([ that.state.model = $(that.wrapSelector('#model')).val(); } - that.insEditor.show(); + that.modelEditor.show(); }); //================================================================ @@ -226,13 +231,13 @@ define([ render() { super.render(); - // Instance Editor - this.insEditor = new InstanceEditor(this, "model", "instanceEditor"); - this.insEditor.show(); + // Model Editor + this.modelEditor = new ModelEditor(this, "model", "instanceEditor"); + this.modelEditor.show(); } generateCode() { - let { modelControlType, modelType, userOption, featureData, targetData, allocateTo } = this.state; + let { modelControlType, modelType, userOption, featureData, targetData, allocateToCreation } = this.state; let code = new com_String(); if (modelControlType == 'creation') { /** @@ -248,14 +253,16 @@ define([ // model code let modelCode = config.code; modelCode = com_generator.vp_codeGenerator(this, config, this.state, userOption); - code.appendFormat('{0} = {1}', allocateTo, modelCode); + code.appendFormat('{0} = {1}', allocateToCreation, modelCode); } else { /** * Model Selection * --- * ... */ - + let modelCode = this.modelEditor.getCode(); + modelCode = modelCode.replace('${model}', model); + code.append(modelCode); } diff --git a/js/m_ml/Classification.js b/js/m_ml/Classification.js index c6cb9bec..c50c86f3 100644 --- a/js/m_ml/Classification.js +++ b/js/m_ml/Classification.js @@ -21,8 +21,8 @@ define([ 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', - 'vp_base/js/com/component/InstanceEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, InstanceEditor) { + 'vp_base/js/com/component/ModelEditor' +], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { /** * Classification @@ -40,7 +40,7 @@ define([ userOption: '', featureData: 'X_train', targetData: 'y_train', - allocateTo: 'model', + allocateToCreation: 'model', // model selection model: '', method: '', @@ -90,6 +90,11 @@ define([ com_interface.insertCell('code', config.install); } }); + + // change model + $(this.wrapSelector('#model')).on('change', function() { + that.modelEditor.show(); + }) } templateForBody() { @@ -167,7 +172,7 @@ define([ that.state.model = $(that.wrapSelector('#model')).val(); } - that.insEditor.show(); + that.modelEditor.show(); }); //================================================================ @@ -225,13 +230,13 @@ define([ render() { super.render(); - // Instance Editor - this.insEditor = new InstanceEditor(this, "model", "instanceEditor"); - this.insEditor.show(); + // Model Editor + this.modelEditor = new ModelEditor(this, "model", "instanceEditor"); + this.modelEditor.show(); } generateCode() { - let { modelControlType, modelType, userOption, featureData, targetData, allocateTo } = this.state; + let { modelControlType, modelType, userOption, featureData, targetData, allocateToCreation } = this.state; let code = new com_String(); if (modelControlType == 'creation') { /** @@ -247,14 +252,16 @@ define([ // model code let modelCode = config.code; modelCode = com_generator.vp_codeGenerator(this, config, this.state, userOption); - code.appendFormat('{0} = {1}', allocateTo, modelCode); + code.appendFormat('{0} = {1}', allocateToCreation, modelCode); } else { /** * Model Selection * --- * ... */ - + let modelCode = this.modelEditor.getCode(); + modelCode = modelCode.replace('${model}', model); + code.append(modelCode); } diff --git a/js/m_ml/Clustering.js b/js/m_ml/Clustering.js index 9d609a88..1d94c308 100644 --- a/js/m_ml/Clustering.js +++ b/js/m_ml/Clustering.js @@ -21,8 +21,8 @@ define([ 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', - 'vp_base/js/com/component/InstanceEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, InstanceEditor) { + 'vp_base/js/com/component/ModelEditor' +], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { /** * Clustering @@ -40,7 +40,7 @@ define([ userOption: '', featureData: 'X_train', targetData: 'y_train', - allocateTo: 'model', + allocateToCreation: 'model', // model selection model: '', method: '', @@ -94,6 +94,11 @@ define([ com_interface.insertCell('code', config.install); } }); + + // change model + $(this.wrapSelector('#model')).on('change', function() { + that.modelEditor.show(); + }) } templateForBody() { @@ -171,7 +176,7 @@ define([ that.state.model = $(that.wrapSelector('#model')).val(); } - that.insEditor.show(); + that.modelEditor.show(); }); //================================================================ @@ -229,13 +234,13 @@ define([ render() { super.render(); - // Instance Editor - this.insEditor = new InstanceEditor(this, "model", "instanceEditor"); - this.insEditor.show(); + // Model Editor + this.modelEditor = new ModelEditor(this, "model", "instanceEditor"); + this.modelEditor.show(); } generateCode() { - let { modelControlType, modelType, userOption, featureData, targetData, allocateTo } = this.state; + let { modelControlType, modelType, userOption, featureData, targetData, allocateToCreation } = this.state; let code = new com_String(); if (modelControlType == 'creation') { /** @@ -251,14 +256,16 @@ define([ // model code let modelCode = config.code; modelCode = com_generator.vp_codeGenerator(this, config, this.state, userOption); - code.appendFormat('{0} = {1}', allocateTo, modelCode); + code.appendFormat('{0} = {1}', allocateToCreation, modelCode); } else { /** * Model Selection * --- * ... */ - + let modelCode = this.modelEditor.getCode(); + modelCode = modelCode.replace('${model}', model); + code.append(modelCode); } diff --git a/js/m_ml/DimensionReduction.js b/js/m_ml/DimensionReduction.js index bd6eb20a..b0fa25d2 100644 --- a/js/m_ml/DimensionReduction.js +++ b/js/m_ml/DimensionReduction.js @@ -21,8 +21,8 @@ define([ 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', - 'vp_base/js/com/component/InstanceEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, InstanceEditor) { + 'vp_base/js/com/component/ModelEditor' +], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { /** * DimensionReduction @@ -40,7 +40,7 @@ define([ userOption: '', featureData: 'X_train', targetData: 'y_train', - allocateTo: 'model', + allocateToCreation: 'model', // model selection model: '', method: '', @@ -90,6 +90,11 @@ define([ com_interface.insertCell('code', config.install); } }); + + // change model + $(this.wrapSelector('#model')).on('change', function() { + that.modelEditor.show(); + }) } templateForBody() { @@ -167,7 +172,7 @@ define([ that.state.model = $(that.wrapSelector('#model')).val(); } - that.insEditor.show(); + that.modelEditor.show(); }); //================================================================ @@ -225,13 +230,13 @@ define([ render() { super.render(); - // Instance Editor - this.insEditor = new InstanceEditor(this, "model", "instanceEditor"); - this.insEditor.show(); + // Model Editor + this.modelEditor = new ModelEditor(this, "model", "instanceEditor"); + this.modelEditor.show(); } generateCode() { - let { modelControlType, modelType, userOption, featureData, targetData, allocateTo } = this.state; + let { modelControlType, modelType, userOption, featureData, targetData, allocateToCreation } = this.state; let code = new com_String(); if (modelControlType == 'creation') { /** @@ -247,14 +252,16 @@ define([ // model code let modelCode = config.code; modelCode = com_generator.vp_codeGenerator(this, config, this.state, userOption); - code.appendFormat('{0} = {1}', allocateTo, modelCode); + code.appendFormat('{0} = {1}', allocateToCreation, modelCode); } else { /** * Model Selection * --- * ... */ - + let modelCode = this.modelEditor.getCode(); + modelCode = modelCode.replace('${model}', model); + code.append(modelCode); } diff --git a/js/m_ml/Regression.js b/js/m_ml/Regression.js index 97d3b7cb..2503b96a 100644 --- a/js/m_ml/Regression.js +++ b/js/m_ml/Regression.js @@ -21,8 +21,8 @@ define([ 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', - 'vp_base/js/com/component/InstanceEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, InstanceEditor) { + 'vp_base/js/com/component/ModelEditor' +], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { /** * Regression @@ -40,7 +40,7 @@ define([ userOption: '', featureData: 'X_train', targetData: 'y_train', - allocateTo: 'model', + allocateToCreation: 'model', // model selection model: '', method: '', @@ -90,6 +90,11 @@ define([ com_interface.insertCell('code', config.install); } }); + + // change model + $(this.wrapSelector('#model')).on('change', function() { + that.modelEditor.show(); + }) } templateForBody() { @@ -167,7 +172,7 @@ define([ that.state.model = $(that.wrapSelector('#model')).val(); } - that.insEditor.show(); + that.modelEditor.show(); }); //================================================================ @@ -225,13 +230,13 @@ define([ render() { super.render(); - // Instance Editor - this.insEditor = new InstanceEditor(this, "model", "instanceEditor"); - this.insEditor.show(); + // Model Editor + this.modelEditor = new ModelEditor(this, "model", "instanceEditor"); + this.modelEditor.show(); } generateCode() { - let { modelControlType, modelType, userOption, featureData, targetData, allocateTo } = this.state; + let { modelControlType, modelType, userOption, allocateToCreation, model } = this.state; let code = new com_String(); if (modelControlType == 'creation') { /** @@ -247,14 +252,16 @@ define([ // model code let modelCode = config.code; modelCode = com_generator.vp_codeGenerator(this, config, this.state, userOption); - code.appendFormat('{0} = {1}', allocateTo, modelCode); + code.appendFormat('{0} = {1}', allocateToCreation, modelCode); } else { /** * Model Selection * --- * ... */ - + let modelCode = this.modelEditor.getCode(); + modelCode = modelCode.replace('${model}', model); + code.append(modelCode); } diff --git a/js/m_ml/evaluation.js b/js/m_ml/evaluation.js index 432e8f31..75bf3484 100644 --- a/js/m_ml/evaluation.js +++ b/js/m_ml/evaluation.js @@ -31,7 +31,7 @@ define([ this.config.dataview = false; this.state = { - modelType: 'clf', + modelType: 'rgs', predictData: 'pred', targetData: 'y_test', // classification From 742077655c7cda30ff15d2e1eaf1efbc11be644a Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Fri, 11 Mar 2022 19:47:28 +0900 Subject: [PATCH 09/27] Fix Model editor #1 --- css/component/instanceEditor.css | 4 ++ js/com/component/ModelEditor.js | 68 ++++++++++++++++++++++---------- js/m_ml/AutoML.js | 5 +-- js/m_ml/Classification.js | 5 +-- js/m_ml/Clustering.js | 5 +-- js/m_ml/DimensionReduction.js | 5 +-- js/m_ml/Regression.js | 5 +-- 7 files changed, 57 insertions(+), 40 deletions(-) diff --git a/css/component/instanceEditor.css b/css/component/instanceEditor.css index 1df973c2..4f321f65 100644 --- a/css/component/instanceEditor.css +++ b/css/component/instanceEditor.css @@ -74,6 +74,10 @@ .vp-ins-parameter-box { grid-column: 1/3; } +.vp-ins-parameter-box:empty::after { + content: '(Empty)'; + color: var(--gray-color); +} .vp-ins-parameter { width: 100% !important; } diff --git a/js/com/component/ModelEditor.js b/js/com/component/ModelEditor.js index b6a3d218..d29b6f09 100644 --- a/js/com/component/ModelEditor.js +++ b/js/com/component/ModelEditor.js @@ -20,10 +20,6 @@ define([ const VP_INS_PARAMETER_BOX = 'vp-ins-parameter-box'; const VP_INS_PARAMETER = 'vp-ins-parameter'; - const VP_CREATE_VAR_BOX = 'vp-create-var-box'; - const VP_CREATE_VAR = 'vp-create-var'; - const VP_CREATE_VAR_BTN = 'vp-create-var-btn'; - class ModelEditor extends Component { constructor(pageThis, targetId, containerId='vp_wrapper') { super(null, { pageThis: pageThis, targetId: targetId, containerId: containerId }); @@ -69,29 +65,29 @@ define([ name: 'fit', code: '${model}.fit(${featureData}, ${targetData})', options: [ - { name: 'featureData', component: ['var_select'], var_type: ['DataFrame'], default: 'X_train' }, - { name: 'targetData', component: ['var_select'], var_type: ['DataFrame'], default: 'y_train' } + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' }, + { name: 'targetData', label: 'Target Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'y_train' } ] }, 'predict': { name: 'predict', code: '${model}.predict(${featureData})', options: [ - { name: 'featureData', component: ['var_select'], var_type: ['DataFrame'], default: 'X_train' } + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' } ] }, 'predict_proba': { name: 'predict_proba', code: '${model}.predict_proba(${featureData})', options: [ - { name: 'featureData', component: ['var_select'], var_type: ['DataFrame'], default: 'X_train' } + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' } ] }, 'transform': { name: 'transform', code: '${model}.transform(${featureData})', options: [ - { name: 'featureData', component: ['var_select'], var_type: ['DataFrame'], default: 'X_train' } + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' } ] } }; @@ -138,19 +134,37 @@ define([ let defaultInfos = { 'score': { name: 'score', - code: '${model}.score()', + code: '${model}.score(${featureData}, {targetData})', options: [ - + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X' }, + { name: 'targetData', label: 'Target Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'y' } + ] + }, + 'cross_val_score': { + name: 'cross_val_score', + import: 'from sklearn.model_selection import cross_val_score', + code: '${allocateScore} = cross_val_score(${model}, ${featureData}, ${targetData}${scoring}${cv})', + options: [ + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X' }, + { name: 'targetData', label: 'Target Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'y' }, + { name: 'scoring', component: ['input'], usePair: true }, + { name: 'cv', component: ['input'], usePair: true }, + { name: 'allocateScore', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } ] } } switch (category) { case 'Regression': infos = { - 'score': defaultInfos['score'] + 'score': defaultInfos['score'], + 'cross_val_score': defaultInfos['cross_val_score'] } break; case 'Classification': + infos = { + 'score': defaultInfos['score'], + 'cross_val_score': defaultInfos['cross_val_score'] + } break; case 'Auto ML': break; @@ -197,11 +211,7 @@ define([ tag.appendLine('
    '); // VP_INS_SELECT_CONTAINER tag.appendFormatLine('
    Options
    ', VP_INS_SELECT_TITLE); - tag.appendFormatLine('
    ', VP_INS_PARAMETER_BOX); - // TODO: option box - - tag.appendLine('
    '); // VP_INS_PARAMETER - + tag.appendFormatLine('
    ', VP_INS_PARAMETER_BOX); tag.appendLine(''); // VP_INS_BOX END $(this.pageThis.wrapSelector('#' + this.containerId)).html(tag.toString()); @@ -294,8 +304,12 @@ define([ let optBox = new com_String(); // render tag config.options.forEach(opt => { + let label = opt.name; + if (opt.label != undefined) { + label = opt.label; + } optBox.appendFormatLine('' - , opt.name, opt.name, opt.name); + , opt.name, opt.name, label); let content = com_generator.renderContent(that, opt.component[0], opt, that.pageThis.state); optBox.appendLine(content[0].outerHTML); }); @@ -303,6 +317,10 @@ define([ $(that.wrapSelector('.' + VP_INS_PARAMETER_BOX)).html(optBox.toString()); that.state.config = config; + + // add selection + $(that.wrapSelector('.' + VP_INS_SELECT_ITEM)).removeClass('selected'); + $(this).addClass('selected'); }); } @@ -315,8 +333,18 @@ define([ $(this.wrapSelector()).hide(); } - getCode() { - return com_generator.vp_codeGenerator(this.pageThis, this.state.config, this.pageThis.state); + getCode(replaceDict={}) { + let code = new com_String(); + if (this.state.config.import != undefined) { + code.appendLine(this.state.config.import); + code.appendLine(); + } + let modelCode = com_generator.vp_codeGenerator(this.pageThis, this.state.config, this.pageThis.state); + Object.keys(replaceDict).forEach(key => { + modelCode = modelCode.replace(key, replaceDict[key]); + }); + code.append(modelCode); + return code.toString(); } } diff --git a/js/m_ml/AutoML.js b/js/m_ml/AutoML.js index 9886c24d..4a4b2939 100644 --- a/js/m_ml/AutoML.js +++ b/js/m_ml/AutoML.js @@ -260,10 +260,7 @@ define([ * --- * ... */ - let modelCode = this.modelEditor.getCode(); - modelCode = modelCode.replace('${model}', model); - code.append(modelCode); - + code.append(this.modelEditor.getCode({'${model}': model})); } return code.toString(); diff --git a/js/m_ml/Classification.js b/js/m_ml/Classification.js index c50c86f3..bcf5b134 100644 --- a/js/m_ml/Classification.js +++ b/js/m_ml/Classification.js @@ -259,10 +259,7 @@ define([ * --- * ... */ - let modelCode = this.modelEditor.getCode(); - modelCode = modelCode.replace('${model}', model); - code.append(modelCode); - + code.append(this.modelEditor.getCode({'${model}': model})); } return code.toString(); diff --git a/js/m_ml/Clustering.js b/js/m_ml/Clustering.js index 1d94c308..b3a48b04 100644 --- a/js/m_ml/Clustering.js +++ b/js/m_ml/Clustering.js @@ -263,10 +263,7 @@ define([ * --- * ... */ - let modelCode = this.modelEditor.getCode(); - modelCode = modelCode.replace('${model}', model); - code.append(modelCode); - + code.append(this.modelEditor.getCode({'${model}': model})); } return code.toString(); diff --git a/js/m_ml/DimensionReduction.js b/js/m_ml/DimensionReduction.js index b0fa25d2..c96b241f 100644 --- a/js/m_ml/DimensionReduction.js +++ b/js/m_ml/DimensionReduction.js @@ -259,10 +259,7 @@ define([ * --- * ... */ - let modelCode = this.modelEditor.getCode(); - modelCode = modelCode.replace('${model}', model); - code.append(modelCode); - + code.append(this.modelEditor.getCode({'${model}': model})); } return code.toString(); diff --git a/js/m_ml/Regression.js b/js/m_ml/Regression.js index 2503b96a..f9339b50 100644 --- a/js/m_ml/Regression.js +++ b/js/m_ml/Regression.js @@ -259,10 +259,7 @@ define([ * --- * ... */ - let modelCode = this.modelEditor.getCode(); - modelCode = modelCode.replace('${model}', model); - code.append(modelCode); - + code.append(this.modelEditor.getCode({'${model}': model})); } return code.toString(); From f2f55b6fe45f20cd8fe33256239e404df9b2ee92 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Fri, 4 Mar 2022 14:50:44 +0900 Subject: [PATCH 10/27] Add ML > DataSets --- data/m_ml/mlLibrary.js | 104 ++++++++++++++++++++++++++++++++++ html/m_ml/dataSets.html | 19 +++++++ js/m_ml/DataSets.js | 120 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 240 insertions(+), 3 deletions(-) create mode 100644 html/m_ml/dataSets.html diff --git a/data/m_ml/mlLibrary.js b/data/m_ml/mlLibrary.js index 6119e80a..4ada0871 100644 --- a/data/m_ml/mlLibrary.js +++ b/data/m_ml/mlLibrary.js @@ -20,6 +20,110 @@ define([ * ] */ var ML_LIBRARIES = { + /** Data Sets */ + 'load_boston': { + name: 'load_boston', + import: 'from sklearn.datasets import load_boston', + code: 'load_boston()', + options: [ + + ] + }, + 'load_iris': { + name: 'load_iris', + import: 'from sklearn.datasets import load_iris', + code: 'load_iris()', + options: [ + + ] + }, + 'load_diabetes': { + name: 'load_diabetes', + import: 'from sklearn.datasets import load_diabetes', + code: 'load_diabetes()', + options: [ + + ] + }, + 'load_digits': { + name: 'load_digits', + import: 'from sklearn.datasets import load_digits', + code: 'load_digits(${n_class})', + options: [ + { name: 'n_class', component: ['input_number'], default: 10, usePair: true }, + ] + }, + 'load_linnerud': { + name: 'load_linnerud', + import: 'from sklearn.datasets import load_linnerud', + code: 'load_linnerud()', + options: [ + + ] + }, + 'load_wine': { + name: 'load_wine', + import: 'from sklearn.datasets import load_wine', + code: 'load_wine()', + options: [ + + ] + }, + 'load_breast_cancer': { + name: 'load_breast_cancer', + import: 'from sklearn.datasets import load_breast_cancer', + code: 'load_breast_cancer()', + options: [ + + ] + }, + 'make_classification': { + name: 'make_classification', + import: 'from sklearn.datasets import make_classification', + code: 'make_classification(${n_samples}${n_features}${n_repeated}${n_classes}${shuffle}${random_state}${etc})', + options: [ + { name: 'n_samples', component: ['input_number'], default: 100, usePair: true }, + { name: 'n_features', component: ['input_number'], default: 20, usePair: true }, + { name: 'n_repeated', component: ['input_number'], default: 0, usePair: true }, + { name: 'n_classes', component: ['input_number'], default: 2, usePair: true }, + { name: 'shuffle', component: ['bool_select'], default: 'True', usePair: true }, + { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } + ] + }, + 'make_blobs': { + name: 'make_blobs', + import: 'from sklearn.datasets import make_blobs', + code: 'make_blobs(${n_samples}${n_features}${shuffle}${random_state}${etc})', + options: [ + { name: 'n_samples', component: ['input_number'], default: 100, usePair: true }, + { name: 'n_features', component: ['input_number'], default: 20, usePair: true }, + { name: 'shuffle', component: ['bool_select'], default: 'True', usePair: true }, + { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } + ] + }, + 'make_circles': { + name: 'make_circles', + import: 'from sklearn.datasets import make_circles', + code: 'make_circles(${n_samples}${shuffle}${noise}${random_state}${factor}${etc})', + options: [ + { name: 'n_samples', component: ['input_number'], default: 100, usePair: true }, + { name: 'shuffle', component: ['bool_select'], default: 'True', usePair: true }, + { name: 'noise', component: ['input_number'], usePair: true }, + { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true }, + { name: 'factor', component: ['input_number'], default: 0.8, usePair: true } + ] + }, + 'make_moons': { + name: 'make_moons', + import: 'from sklearn.datasets import make_moons', + code: 'make_moons(${n_samples}${shuffle}${noise}${random_state}${etc})', + options: [ + { name: 'n_samples', component: ['input_number'], default: 100, usePair: true }, + { name: 'shuffle', component: ['bool_select'], default: 'True', usePair: true }, + { name: 'noise', component: ['input_number'], usePair: true }, + { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } + ] + }, /** Data Preparation - Encoding */ 'prep-onehot': { name: 'OneHotEncoder', diff --git a/html/m_ml/dataSets.html b/html/m_ml/dataSets.html new file mode 100644 index 00000000..5af731b8 --- /dev/null +++ b/html/m_ml/dataSets.html @@ -0,0 +1,19 @@ + +
    +
    +
    + + +
    +
    + +
    +
    +
    + + +
    +
    + \ No newline at end of file diff --git a/js/m_ml/DataSets.js b/js/m_ml/DataSets.js index cb480970..bdd2bd5f 100644 --- a/js/m_ml/DataSets.js +++ b/js/m_ml/DataSets.js @@ -13,11 +13,14 @@ // [CLASS] DataSets //============================================================================ define([ + 'text!vp_base/html/m_ml/dataSets.html!strip', 'vp_base/js/com/com_util', 'vp_base/js/com/com_Const', 'vp_base/js/com/com_String', 'vp_base/js/com/component/PopupComponent', -], function(com_util, com_Const, com_String, PopupComponent) { + 'vp_base/js/com/com_generatorV2', + 'vp_base/data/m_ml/mlLibrary', +], function(dsHTML, com_util, com_Const, com_String, PopupComponent, com_generator, ML_LIBRARIES) { /** * DataSets @@ -29,15 +32,126 @@ define([ this.config.dataview = false; this.state = { - + loadType: 'load_boston', + userOption: '', + allocateTo: 'ldata', ...this.state } + + this.mlConfig = ML_LIBRARIES; + this.loadTypeList = { + 'Load Data': [ + 'load_boston', 'load_iris', 'load_diabetes', 'load_digits', 'load_linnerud', 'load_wine', 'load_breast_cancer' + ], + 'Create Data': [ + 'make_classification', 'make_blobs', 'make_circles', 'make_moons' + ] + } + + } + + _bindEvent() { + super._bindEvent(); + let that = this; + + // select model + $(this.wrapSelector('#loadType')).on('change', function() { + let loadType = $(this).val(); + that.state.loadType = loadType; + $(that.wrapSelector('.vp-data-option-box')).html(that.templateForOption(loadType)); + + // change allocateTo default variable name + if (that.loadTypeList['Load Data'].includes(loadType)) { + $(that.wrapSelector('#allocateTo')).val('ldata'); + that.state.allocateTo = 'ldata'; + } else { + $(that.wrapSelector('#allocateTo')).val('df'); + that.state.allocateTo = 'df'; + } + }); } templateForBody() { - return 'Data Set test'; + let page = $(dsHTML); + + let that = this; + // load types + let loadTypeTag = new com_String(); + Object.keys(this.loadTypeList).forEach(category => { + let optionTag = new com_String(); + that.loadTypeList[category].forEach(opt => { + let optConfig = that.mlConfig[opt]; + let selectedFlag = ''; + if (opt == that.state.modelType) { + selectedFlag = 'selected'; + } + optionTag.appendFormatLine('', + opt, selectedFlag, optConfig.name); + }) + loadTypeTag.appendFormatLine('{1}', + category, optionTag.toString()); + }); + $(page).find('#loadType').html(loadTypeTag.toString()); + + // render option page + $(page).find('.vp-data-option-box').html(this.templateForOption(this.state.loadType)); + + return page; } + templateForOption(loadType) { + let config = this.mlConfig[loadType]; + let state = this.state; + + let optBox = new com_String(); + // render tag + config.options.forEach(opt => { + optBox.appendFormatLine('' + , opt.name, opt.name, opt.name); + let content = com_generator.renderContent(this, opt.component[0], opt, state); + optBox.appendLine(content[0].outerHTML); + }); + + // show user option + if (config.code.includes('${etc}')) { + // render user option + optBox.appendFormatLine('', 'userOption', 'User option'); + optBox.appendFormatLine('', + 'userOption', 'key=value, ...', this.state.userOption); + } + return optBox.toString(); + } + + generateCode() { + let { loadType, userOption, allocateTo } = this.state; + let code = new com_String(); + let config = this.mlConfig[loadType]; + code.appendLine(config.import); + code.appendLine(); + + // model code + let modelCode = config.code; + modelCode = com_generator.vp_codeGenerator(this, config, this.state, userOption); + + if (this.loadTypeList['Load Data'].includes(loadType)) { + code.appendFormatLine('{0} = {1}', allocateTo, modelCode); + // FIXME: decide between 2 codes + // code.appendFormat("df_{0} = pd.concat([pd.DataFrame({1}.data, columns={2}.feature_names), pd.DataFrame({3}.target, columns=['target'])], axis=1)", allocateTo, allocateTo, allocateTo, allocateTo); + code.appendFormat("df_{0} = pd.DataFrame(np.hstack(({1}.data, {2}.target.reshape(-1,1))), columns=np.hstack(({3}.feature_names, ['target'])))", allocateTo, allocateTo, allocateTo, allocateTo); + } else { + code.appendFormatLine("_X, _y = {0}", modelCode); + code.appendLine("_columns = np.hstack((['X{}'.format(i+1) for i in range(len(_X[0]))],['target']))"); + code.appendFormat("{0} = pd.DataFrame(np.hstack((_X, _y.reshape(-1,1))), columns=_columns)", allocateTo); + } + + if (allocateTo != '') { + code.appendLine(); + code.append(allocateTo); + } + + + return code.toString(); + } } return DataSets; From 02c2e27c752edf7ce4f45d8d3e1231868a2e57a7 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Fri, 4 Mar 2022 15:47:14 +0900 Subject: [PATCH 11/27] Set default title for Hide VP Note --- html/menuFrame.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/menuFrame.html b/html/menuFrame.html index 084cba6e..37919802 100644 --- a/html/menuFrame.html +++ b/html/menuFrame.html @@ -51,7 +51,7 @@
    -
    +
    From 839618091451ac80df0572fa211be61c9a304616 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Mon, 7 Mar 2022 02:04:44 +0900 Subject: [PATCH 12/27] Fix AutoML --- data/m_ml/mlLibrary.js | 74 ++++++++++++++++++++++++++++----------- js/com/com_generatorV2.js | 3 +- js/m_ml/AutoML.js | 7 ++-- js/m_ml/DataPrep.js | 14 +++++--- 4 files changed, 67 insertions(+), 31 deletions(-) diff --git a/data/m_ml/mlLibrary.js b/data/m_ml/mlLibrary.js index 4ada0871..9d72c776 100644 --- a/data/m_ml/mlLibrary.js +++ b/data/m_ml/mlLibrary.js @@ -128,9 +128,10 @@ define([ 'prep-onehot': { name: 'OneHotEncoder', import: 'from sklearn.preprocessing import OneHotEncoder', - code: 'OneHotEncoder()', + code: 'OneHotEncoder(${handle_unknown}${etc})', options: [ - + { name: 'handle_unknown', component: ['option_suggest'], usePair: true, + options: ['error', 'ignore'], default: 'error' }, ] }, 'prep-label': { @@ -144,66 +145,77 @@ define([ 'prep-ordinal': { name: 'OrdinalEncoder', import: 'from sklearn.preprocessing import OrdinalEncoder', - code: 'OrdinalEncoder()', + code: 'OrdinalEncoder(${handle_unknown}${unknown_values}${etc})', options: [ - + { name: 'handle_unknown', component: ['option_suggest'], usePair: true, + options: ['error', 'use_encoded_value'], default: 'error' }, + { name: 'unknown_values', component: ['input'], usePair: true } ] }, 'prep-target': { name: 'TargetEncoder', install: '!pip install category_encoders', import: 'from category_encoders.target_encoder import TargetEncoder', - code: 'TargetEncoder()', + code: 'TargetEncoder(${cols}${handle_missing}${handle_unknown}${smoothing}${etc})', options: [ - + { name: 'cols', component: ['var_suggest', '1darr'], usePair: true }, + { name: 'handle_missing', component: ['option_suggest'], usePair: true, + options: ['error', 'return_nan', 'value'], default: 'value' }, + { name: 'handle_unknown', component: ['option_suggest'], usePair: true, + options: ['error', 'return_nan', 'value'], default: 'value' }, + { name: 'smoothing', component: ['input_number'], default: 1.0, usePair: true } ] }, 'prep-smote': { name: 'SMOTE', install: '!pip install imblearn', - import: 'from imlearn.over_sampling import SMOTE', - code: 'SMOTE()', + import: 'from imblearn.over_sampling import SMOTE', + code: 'SMOTE(${random_state}${k_neighbors}${etc})', options: [ - + { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true }, + { name: 'k_neighbors', component: ['input_number'], default: 5, usePair: true } ] }, /** Data Preparation - Scaling */ 'prep-standard': { name: 'StandardScaler', import: 'from sklearn.preprocessing import StandardScaler', - code: 'StandardScaler()', + code: 'StandardScaler(${with_mean}${with_std}${etc})', options: [ - + { name: 'with_mean', component: ['bool_select'], default: 'True', usePair: true }, + { name: 'with_std', component: ['bool_select'], default: 'True', usePair: true } ] }, 'prep-robust': { name: 'RobustScaler', import: 'from sklearn.preprocessing import RobustScaler', - code: 'RobustScaler()', + code: 'RobustScaler(${with_centering}${with_scaling}${etc})', options: [ - + { name: 'with_centering', component: ['bool_select'], default: 'True', usePair: true }, + { name: 'with_scaling', component: ['bool_select'], default: 'True', usePair: true } ] }, 'prep-minmax': { name: 'MinMaxScaler', import: 'from sklearn.preprocessing import MinMaxScaler', - code: 'MinMaxScaler()', + code: 'MinMaxScaler(${feature_range}${etc})', options: [ - + { name: 'feature_range', component: ['input'], placeholder: '(min, max)', default: '(0, 1)', usePair: true } ] }, 'prep-normalizer': { name: 'Normalizer', import: 'from sklearn.preprocessing import Normalizer', - code: 'Normalizer()', + code: 'Normalizer(${norm}${etc})', options: [ - + { name: 'norm', component: ['option_suggest'], usePair: true, + options: ['l1', 'l2', 'max'], default: 'l2' }, ] }, 'prep-func-trsfrm-log': { name: 'Log Scaling', import: 'from sklearn.preprocessing import FunctionTransformer', - code: 'FunctionTransformer(np.log1p)', + code: 'FunctionTransformer(np.log1p${etc})', options: [ ] @@ -211,7 +223,7 @@ define([ 'prep-func-trsfrm-exp': { name: 'Exponential Scaling', import: 'from sklearn.preprocessing import FunctionTransformer', - code: 'FunctionTransformer(np.expm1)', + code: 'FunctionTransformer(np.expm1${etc})', options: [ ] @@ -220,7 +232,7 @@ define([ 'ln-rgs': { name: 'LinearRegression', import: 'from sklearn.linear_model import LinearRegression', - code: 'LinearRegression(${fit_intercept})', + code: 'LinearRegression(${fit_intercept}${etc})', options: [ { name: 'fit_intercept', component: ['bool_select'], default: 'True', usePair: true } ] @@ -429,8 +441,19 @@ define([ ] }, /** Auto ML */ + 'auto-sklearn-rgs': { + name: 'AutoSklearnRegressor (Linux only)', + install: 'pip install auto-sklearn', + import: 'from autosklearn import AutoSklearnRegressor', + link: 'https://automl.github.io/auto-sklearn/master/api.html#regression', + code: 'AutoSklearnRegressor(${etc})', + options: [ + + ] + }, 'tpot-rgs': { name: 'TPOTRegressor', + install: 'pip install tpot', import: 'from tpot import TPOTRegressor', code: 'TPOTRegressor(${generation}${population_size}${cv}${random_state}${etc})', options: [ @@ -440,8 +463,19 @@ define([ { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } ] }, + 'auto-sklearn-clf': { + name: 'AutoSklearnClassifier (Linux only)', + install: 'pip install auto-sklearn', + import: 'from autosklearn import AutoSklearnClassifier', + link: 'https://automl.github.io/auto-sklearn/master/api.html#classification', + code: 'AutoSklearnClassifier(${etc})', + options: [ + + ] + }, 'tpot-clf': { name: 'TPOTClassifier', + install: 'pip install tpot', import: 'from tpot import TPOTClassifier', code: 'TPOTClassifier(${generation}${population_size}${cv}${random_state}${etc})', options: [ diff --git a/js/com/com_generatorV2.js b/js/com/com_generatorV2.js index 05da2e0b..76544590 100644 --- a/js/com/com_generatorV2.js +++ b/js/com/com_generatorV2.js @@ -37,7 +37,8 @@ define([ 'col_select': 'Select Column', 'textarea': 'Input textarea', 'input_number': 'Input number', - 'input': 'Input text' + 'input_text': 'Input text', + 'input': 'Input value' } const _VP_BOOL_OPTIONS = [ diff --git a/js/m_ml/AutoML.js b/js/m_ml/AutoML.js index 4f0548e5..873d9be6 100644 --- a/js/m_ml/AutoML.js +++ b/js/m_ml/AutoML.js @@ -50,11 +50,8 @@ define([ this.modelConfig = ML_LIBRARIES; this.modelTypeList = { - // 'Regression': ['ln-rgs', 'sv-rgs', 'dt-rgs', 'rf-rgs', 'gbm-rgs', 'xgb-rgs', 'lgbm-rgs', 'cb-rgs'], - // 'Classfication': ['lg-rgs', 'sv-clf', 'dt-clf', 'rf-clf', 'gbm-clf', 'xgb-clf', 'lgbm-clf', 'cb-clf'], - 'Auto ML': ['tpot-rgs', 'tpot-clf'], - // 'Clustering': ['k-means', 'agg-cls', 'gaus-mix', 'dbscan'], - // 'Dimension Reduction': ['pca', 'lda', 'svd', 'nmf'] + 'Regression': ['auto-sklearn-rgs', 'tpot-rgs'], + 'Classification': ['auto-sklearn-clf', 'tpot-clf'] } diff --git a/js/m_ml/DataPrep.js b/js/m_ml/DataPrep.js index 333fd0c7..3639f595 100644 --- a/js/m_ml/DataPrep.js +++ b/js/m_ml/DataPrep.js @@ -17,12 +17,13 @@ define([ 'vp_base/js/com/com_util', 'vp_base/js/com/com_Const', 'vp_base/js/com/com_String', + 'vp_base/js/com/com_interface', 'vp_base/js/com/com_generatorV2', 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', 'vp_base/js/com/component/InstanceEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, InstanceEditor) { +], function(msHtml, com_util, com_Const, com_String, com_interface, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, InstanceEditor) { /** * DataPrep @@ -222,10 +223,13 @@ define([ let content = com_generator.renderContent(this, opt.component[0], opt, state); optBox.appendLine(content[0].outerHTML); }); - // render user option - optBox.appendFormatLine('', 'userOption', 'User option'); - optBox.appendFormatLine('', - 'userOption', 'key=value, ...', this.state.userOption); + // show user option + if (config.code.includes('${etc}')) { + // render user option + optBox.appendFormatLine('', 'userOption', 'User option'); + optBox.appendFormatLine('', + 'userOption', 'key=value, ...', this.state.userOption); + } return optBox.toString(); } From f058b2992d0721b0a6159807848a9f0c30b85caa Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Fri, 11 Mar 2022 11:37:03 +0900 Subject: [PATCH 13/27] Add auto-sklearn to AutoML --- html/m_ml/model.html | 15 +++++++++------ js/com/com_Config.js | 4 ++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/html/m_ml/model.html b/html/m_ml/model.html index 630ed259..f33a2914 100644 --- a/html/m_ml/model.html +++ b/html/m_ml/model.html @@ -19,12 +19,6 @@ -
    - - - - -
    @@ -42,6 +36,15 @@
    +
    + +
    + \ No newline at end of file diff --git a/js/com/com_Config.js b/js/com/com_Config.js index 74987dba..eb8d41ec 100644 --- a/js/com/com_Config.js +++ b/js/com/com_Config.js @@ -483,13 +483,13 @@ define([ */ Config.ML_DATA_DICT = { 'Regression': [ - 'LinearRegression', 'SVR', 'DecisionTreeRegressor', 'RandomForestRegression', 'GradientBoostingRegressor', 'XGBRegressor', 'LGBMRegressor', 'CatBoostRegressor', + 'LinearRegression', 'SVR', 'DecisionTreeRegressor', 'RandomForestRegressor', 'GradientBoostingRegressor', 'XGBRegressor', 'LGBMRegressor', 'CatBoostRegressor', ], 'Classification': [ 'LogisticRegression', 'SVC', 'DecisionTreeClassifier', 'RandomForestClassifier', 'GradientBoostingClassifier', 'XGBClassifier', 'LGBMClassifier', 'CatBoostClassifier', ], 'Auto ML': [ - 'TPOTRegression', 'TPOTClassifier' + 'AutoSklearnRegressor', 'AutoSklearnClassifier', 'TPOTRegression', 'TPOTClassifier' ], 'Clustering': [ 'KMeans', 'AgglomerativeClustering', 'GaussianMixture', 'DBSCAN', From 34ee496a0ea6de053319c596e085779fb18b5927 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Fri, 11 Mar 2022 12:04:49 +0900 Subject: [PATCH 14/27] Add ML apps icon & color --- css/boardFrame.css | 4 ++-- css/menuFrame.css | 9 ++++++++ data/libraries.json | 38 ++++++++++++++++---------------- img/apps/apps_automl.svg | 9 ++++++++ img/apps/apps_classification.svg | 8 +++++++ img/apps/apps_clustering.svg | 6 +++++ img/apps/apps_dataprep.svg | 5 +++++ img/apps/apps_dataset.svg | 7 ++++++ img/apps/apps_dimension.svg | 6 +++++ img/apps/apps_regression.svg | 10 +++++++++ js/menu/MenuItem.js | 5 +---- 11 files changed, 82 insertions(+), 25 deletions(-) create mode 100644 img/apps/apps_automl.svg create mode 100644 img/apps/apps_classification.svg create mode 100644 img/apps/apps_clustering.svg create mode 100644 img/apps/apps_dataprep.svg create mode 100644 img/apps/apps_dataset.svg create mode 100644 img/apps/apps_dimension.svg create mode 100644 img/apps/apps_regression.svg diff --git a/css/boardFrame.css b/css/boardFrame.css index 57bf5ab6..1614a371 100644 --- a/css/boardFrame.css +++ b/css/boardFrame.css @@ -238,11 +238,11 @@ background-color: rgb(253, 177, 133); } .vp-block.machine_learning .vp-block-header { - background-color: rgb(249, 227, 214); + background-color: #E8ECD0; } .vp-block.machine_learning.vp-focus .vp-block-header, .vp-block.machine_learning.vp-focus-child .vp-block-header { - background-color: rgb(253, 177, 133); + background-color: #C6CE94; } .vp-block.logic-define .vp-block-header { background-color: rgb(213, 231, 222); diff --git a/css/menuFrame.css b/css/menuFrame.css index 68303d1e..2e3bec6f 100644 --- a/css/menuFrame.css +++ b/css/menuFrame.css @@ -229,6 +229,15 @@ .vp-menuitem.apps.vp-color-apps4 { background: #E56139; } +.vp-menuitem.apps.vp-color-apps5 { + background: #BEB727; +} +.vp-menuitem.apps.vp-color-apps6 { + background: #91A541; +} +.vp-menuitem.apps.vp-color-apps7 { + background: #718E41; +} .vp-menuitem.apps.vp-color-preparing { background: var(--gray-color); } diff --git a/data/libraries.json b/data/libraries.json index d2e0cad9..c04ad2a8 100644 --- a/data/libraries.json +++ b/data/libraries.json @@ -3111,8 +3111,8 @@ "desc" : "Data sets for machine learning", "file" : "m_ml/DataSets", "apps" : { - "color": 1, - "icon": "apps/apps_white.svg" + "color": 5, + "icon": "apps/apps_dataset.svg" } }, { @@ -3125,8 +3125,8 @@ "desc" : "Data preparation for machine learning", "file" : "m_ml/DataPrep", "apps" : { - "color": 1, - "icon": "apps/apps_white.svg" + "color": 5, + "icon": "apps/apps_dataprep.svg" } }, { @@ -3139,7 +3139,7 @@ "desc" : "Data split for machine learning", "file" : "m_ml/dataSplit", "apps" : { - "color": 1, + "color": 5, "icon": "apps/apps_datasplit.svg" } }, @@ -3147,28 +3147,28 @@ "id" : "ml_regression", "type" : "function", "level": 1, - "name" : "Regression", + "name" : "Regressor", "tag" : "REGRESSION,MODEL,MACHINE LEARNING,ML", "path" : "visualpython - machine_learning - regression", "desc" : "Regression model for machine learning", "file" : "m_ml/Regression", "apps" : { - "color": 1, - "icon": "apps/apps_model.svg" + "color": 5, + "icon": "apps/apps_regression.svg" } }, { "id" : "ml_classification", "type" : "function", "level": 1, - "name" : "Classification", + "name" : "Classifier", "tag" : "CLASSIFICATION,MODEL,MACHINE LEARNING,ML", "path" : "visualpython - machine_learning - classification", "desc" : "Classification model for machine learning", "file" : "m_ml/Classification", "apps" : { - "color": 1, - "icon": "apps/apps_model.svg" + "color": 6, + "icon": "apps/apps_classification.svg" } }, { @@ -3181,22 +3181,22 @@ "desc" : "Clustering model for machine learning", "file" : "m_ml/Clustering", "apps" : { - "color": 1, - "icon": "apps/apps_model.svg" + "color": 6, + "icon": "apps/apps_clustering.svg" } }, { "id" : "ml_dimensionReduction", "type" : "function", "level": 1, - "name" : "Dimension Reduction", + "name" : "Dimension", "tag" : "DIMENSION REDUCTION,MODEL,MACHINE LEARNING,ML", "path" : "visualpython - machine_learning - dimension_reduction", "desc" : "Dimension reduction model for machine learning", "file" : "m_ml/DimensionReduction", "apps" : { - "color": 1, - "icon": "apps/apps_model.svg" + "color": 6, + "icon": "apps/apps_dimension.svg" } }, { @@ -3209,8 +3209,8 @@ "desc" : "AutoML model for machine learning", "file" : "m_ml/AutoML", "apps" : { - "color": 1, - "icon": "apps/apps_model.svg" + "color": 6, + "icon": "apps/apps_automl.svg" } }, { @@ -3223,7 +3223,7 @@ "desc" : "Performance evaluation for machine learning", "file" : "m_ml/evaluation", "apps" : { - "color": 1, + "color": 7, "icon": "apps/apps_evaluate.svg" } } diff --git a/img/apps/apps_automl.svg b/img/apps/apps_automl.svg new file mode 100644 index 00000000..06a0ff7f --- /dev/null +++ b/img/apps/apps_automl.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/img/apps/apps_classification.svg b/img/apps/apps_classification.svg new file mode 100644 index 00000000..5e6d91ea --- /dev/null +++ b/img/apps/apps_classification.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/img/apps/apps_clustering.svg b/img/apps/apps_clustering.svg new file mode 100644 index 00000000..ae50c87c --- /dev/null +++ b/img/apps/apps_clustering.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/img/apps/apps_dataprep.svg b/img/apps/apps_dataprep.svg new file mode 100644 index 00000000..7219b79b --- /dev/null +++ b/img/apps/apps_dataprep.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/img/apps/apps_dataset.svg b/img/apps/apps_dataset.svg new file mode 100644 index 00000000..37028753 --- /dev/null +++ b/img/apps/apps_dataset.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/img/apps/apps_dimension.svg b/img/apps/apps_dimension.svg new file mode 100644 index 00000000..264f3902 --- /dev/null +++ b/img/apps/apps_dimension.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/img/apps/apps_regression.svg b/img/apps/apps_regression.svg new file mode 100644 index 00000000..cb67005f --- /dev/null +++ b/img/apps/apps_regression.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/js/menu/MenuItem.js b/js/menu/MenuItem.js index f57643bc..2d3d3d7c 100644 --- a/js/menu/MenuItem.js +++ b/js/menu/MenuItem.js @@ -55,10 +55,7 @@ define([ switch(color) { case 0: return 'vp-color-preparing'; - case 1: - case 2: - case 3: - case 4: + default: return 'vp-color-apps' + color; } } else { From d77e64573bdd431cdddf1c75498e62e61afc7fe8 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Fri, 11 Mar 2022 12:14:55 +0900 Subject: [PATCH 15/27] Fix DataSets code to create DataFrame --- js/m_ml/DataSets.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/js/m_ml/DataSets.js b/js/m_ml/DataSets.js index bdd2bd5f..479bdf02 100644 --- a/js/m_ml/DataSets.js +++ b/js/m_ml/DataSets.js @@ -133,20 +133,24 @@ define([ let modelCode = config.code; modelCode = com_generator.vp_codeGenerator(this, config, this.state, userOption); + let allocateToVar = allocateTo; if (this.loadTypeList['Load Data'].includes(loadType)) { code.appendFormatLine('{0} = {1}', allocateTo, modelCode); - // FIXME: decide between 2 codes - // code.appendFormat("df_{0} = pd.concat([pd.DataFrame({1}.data, columns={2}.feature_names), pd.DataFrame({3}.target, columns=['target'])], axis=1)", allocateTo, allocateTo, allocateTo, allocateTo); - code.appendFormat("df_{0} = pd.DataFrame(np.hstack(({1}.data, {2}.target.reshape(-1,1))), columns=np.hstack(({3}.feature_names, ['target'])))", allocateTo, allocateTo, allocateTo, allocateTo); + code.appendLine("# Create DataFrame"); + code.appendFormatLine("df_{0} = pd.DataFrame(data={1}.data, columns={2}.feature_names)", allocateTo, allocateTo, allocateTo); + code.appendFormat("df_{0}['target'] = {1}.target", allocateTo, allocateTo); + allocateToVar = 'df_' + allocateTo; } else { code.appendFormatLine("_X, _y = {0}", modelCode); - code.appendLine("_columns = np.hstack((['X{}'.format(i+1) for i in range(len(_X[0]))],['target']))"); - code.appendFormat("{0} = pd.DataFrame(np.hstack((_X, _y.reshape(-1,1))), columns=_columns)", allocateTo); + code.appendLine("# Create DataFrame"); + code.appendLine("_feature_names = ['X{}'.format(i+1) for i in range(len(_X[0]))]"); + code.appendFormatLine("{0} = pd.DataFrame(data=_X, columns=_feature_names)", allocateTo); + code.appendFormat("{0}['target'] = _y", allocateTo); } - if (allocateTo != '') { + if (allocateToVar != '') { code.appendLine(); - code.append(allocateTo); + code.append(allocateToVar); } From 4cbb72e705a55e6315fdf05e1aee5fada233de7e Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Fri, 11 Mar 2022 15:51:23 +0900 Subject: [PATCH 16/27] Add some models --- data/m_ml/mlLibrary.js | 72 +++++++++++++++++++++++++++++++++-- js/com/com_Config.js | 8 ++-- js/m_ml/Classification.js | 6 +-- js/m_ml/DataPrep.js | 8 +--- js/m_ml/DimensionReduction.js | 6 +-- js/m_ml/Regression.js | 6 +-- 6 files changed, 77 insertions(+), 29 deletions(-) diff --git a/data/m_ml/mlLibrary.js b/data/m_ml/mlLibrary.js index 9d72c776..ed6e2438 100644 --- a/data/m_ml/mlLibrary.js +++ b/data/m_ml/mlLibrary.js @@ -228,6 +228,14 @@ define([ ] }, + 'prep-poly-feat': { + name: 'Polynomial Features', + import: 'from sklearn.preprocessing import PolynomialFeatures', + code: 'PolynomialFeatures(${etc})', + options: [ + + ] + }, /** Regression */ 'ln-rgs': { name: 'LinearRegression', @@ -237,6 +245,30 @@ define([ { name: 'fit_intercept', component: ['bool_select'], default: 'True', usePair: true } ] }, + 'ridge': { + name: 'Ridge', + import: 'from sklearn.linear_model import Ridge', + code: 'Ridge(${etc})', + options: [ + //TODO: + ] + }, + 'lasso': { + name: 'Lasso', + import: 'from sklearn.linear_model import Lasso', + code: 'Lasso(${etc})', + options: [ + //TODO: + ] + }, + 'elasticnet': { + name: 'ElasticNet', + import: 'from sklearn.linear_model import ElasticNet', + code: 'ElasticNet(${etc})', + options: [ + //TODO: + ] + }, 'sv-rgs': { name: 'SVR', import: 'from sklearn.svm import SVR', @@ -344,6 +376,30 @@ define([ { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } ] }, + 'bern-nb': { + name: 'BernoulliNB', + import: 'from sklearn.naive_bayes import BernoulliNB', + code: 'BernoulliNB(${etc})', + options: [ + //TODO: + ] + }, + 'mulnom-nb': { + name: 'MultinomialNB', + import: 'from sklearn.naive_bayes import MultinomialNB', + code: 'MultinomialNB(${etc})', + options: [ + //TODO: + ] + }, + 'gaus-nb': { + name: 'GaussianNB', + import: 'from sklearn.naive_bayes import GaussianNB', + code: 'GaussianNB(${etc})', + options: [ + //TODO: + ] + }, 'sv-clf': { name: 'SupportVectorClassifier', import: 'from sklearn.svm import SVC', @@ -524,7 +580,7 @@ define([ }, /** Dimension Reduction */ 'pca': { - name: 'Principal Component Analysis', + name: 'PCA(Principal Component Analysis)', import: 'from sklearn.decomposition import PCA', code: 'PCA(${n_components}${random_state}${etc})', options: [ @@ -533,7 +589,7 @@ define([ ] }, 'lda': { - name: 'Linear Discriminant Analysis', + name: 'LDA(Linear Discriminant Analysis)', import: 'from sklearn.discriminant_analysis import LinearDiscriminantAnalysis', code: 'LinearDiscriminantAnalysis(${n_components}${etc})', options: [ @@ -550,13 +606,23 @@ define([ ] }, 'nmf': { - name: 'Non-Negative Matrix Factorization', + name: 'NMF(Non-Negative Matrix Factorization)', import: 'from sklearn.decomposition import NMF', code: 'NMF(${n_components}${random_state}${etc})', options: [ { name: 'n_components', component: ['input_number'], placeholder: 'None', usePair: true }, { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } ] + }, + 'tsne': { + name: 'TSNE(T-distributed Stochastic Neighbor Embedding)', + import: 'from sklearn.manifold import TSNE', + code: 'TSNE(${n_components}${learning_rate}${random_state}${etc})', + options: [ + { name: 'n_components', component: ['input_number'], placeholder: 'None', usePair: true }, + { name: 'learning_rate', component: ['input_number'], default: 200.0, usePair: true }, + { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } + ] } } diff --git a/js/com/com_Config.js b/js/com/com_Config.js index eb8d41ec..45921134 100644 --- a/js/com/com_Config.js +++ b/js/com/com_Config.js @@ -483,10 +483,10 @@ define([ */ Config.ML_DATA_DICT = { 'Regression': [ - 'LinearRegression', 'SVR', 'DecisionTreeRegressor', 'RandomForestRegressor', 'GradientBoostingRegressor', 'XGBRegressor', 'LGBMRegressor', 'CatBoostRegressor', + 'LinearRegression', 'Ridge', 'Lasso', 'ElasticNet', 'SVR', 'DecisionTreeRegressor', 'RandomForestRegressor', 'GradientBoostingRegressor', 'XGBRegressor', 'LGBMRegressor', 'CatBoostRegressor', ], 'Classification': [ - 'LogisticRegression', 'SVC', 'DecisionTreeClassifier', 'RandomForestClassifier', 'GradientBoostingClassifier', 'XGBClassifier', 'LGBMClassifier', 'CatBoostClassifier', + 'LogisticRegression', 'BernoulliNB', 'MultinomialNB', 'GaussianNB', 'SVC', 'DecisionTreeClassifier', 'RandomForestClassifier', 'GradientBoostingClassifier', 'XGBClassifier', 'LGBMClassifier', 'CatBoostClassifier', ], 'Auto ML': [ 'AutoSklearnRegressor', 'AutoSklearnClassifier', 'TPOTRegression', 'TPOTClassifier' @@ -495,13 +495,13 @@ define([ 'KMeans', 'AgglomerativeClustering', 'GaussianMixture', 'DBSCAN', ], 'Dimension Reduction': [ - 'PCA', 'LinearDiscriminantAnalysis', 'TruncatedSVD', 'NMF' + 'PCA', 'LinearDiscriminantAnalysis', 'TruncatedSVD', 'NMF', 'TSNE' ], 'Data Preparation': [ /** Encoding */ 'OneHotEncoder', 'LabelEncoder', 'OrdinalEncoder', 'TargetEncoder', 'SMOTE', /** Scaling */ - 'StandardScaler', 'RobustScaler', 'MinMaxScaler', 'Normalizer', 'FunctionTransformer' + 'StandardScaler', 'RobustScaler', 'MinMaxScaler', 'Normalizer', 'FunctionTransformer', 'PolynomialFeatures' ] }; diff --git a/js/m_ml/Classification.js b/js/m_ml/Classification.js index dc97f0e7..c6cb9bec 100644 --- a/js/m_ml/Classification.js +++ b/js/m_ml/Classification.js @@ -50,11 +50,7 @@ define([ this.modelConfig = ML_LIBRARIES; this.modelTypeList = { - // 'Regression': ['ln-rgs', 'sv-rgs', 'dt-rgs', 'rf-rgs', 'gbm-rgs', 'xgb-rgs', 'lgbm-rgs', 'cb-rgs'], - 'Classfication': ['lg-rgs', 'sv-clf', 'dt-clf', 'rf-clf', 'gbm-clf', 'xgb-clf', 'lgbm-clf', 'cb-clf'], - // 'Auto ML': ['tpot-rgs', 'tpot-clf'], - // 'Clustering': ['k-means', 'agg-cls', 'gaus-mix', 'dbscan'], - // 'Dimension Reduction': ['pca', 'lda', 'svd', 'nmf'] + 'Classfication': ['lg-rgs', 'bern-nb', 'mulnom-nb', 'gaus-nb', 'sv-clf', 'dt-clf', 'rf-clf', 'gbm-clf', 'xgb-clf', 'lgbm-clf', 'cb-clf'], } diff --git a/js/m_ml/DataPrep.js b/js/m_ml/DataPrep.js index 3639f595..54ce4cf3 100644 --- a/js/m_ml/DataPrep.js +++ b/js/m_ml/DataPrep.js @@ -52,13 +52,7 @@ define([ this.modelTypeList = { 'Encoding': ['prep-onehot', 'prep-label', 'prep-ordinal', 'prep-target', 'prep-smote'], - 'Scaling': ['prep-standard', 'prep-robust', 'prep-minmax', 'prep-normalizer', 'prep-func-trsfrm-log', 'prep-func-trsfrm-exp'] - - // 'Regression': ['ln-rgs', 'sv-rgs', 'dt-rgs', 'rf-rgs', 'gbm-rgs', 'xgb-rgs', 'lgbm-rgs', 'cb-rgs'], - // 'Classfication': ['lg-rgs', 'sv-clf', 'dt-clf', 'rf-clf', 'gbm-clf', 'xgb-clf', 'lgbm-clf', 'cb-clf'], - // 'Auto ML': ['tpot-rgs', 'tpot-clf'], - // 'Clustering': ['k-means', 'agg-cls', 'gaus-mix', 'dbscan'], - // 'Dimension Reduction': ['pca', 'lda', 'svd', 'nmf'] + 'Scaling': ['prep-standard', 'prep-robust', 'prep-minmax', 'prep-normalizer', 'prep-func-trsfrm-log', 'prep-func-trsfrm-exp', 'prep-poly-feat'] } diff --git a/js/m_ml/DimensionReduction.js b/js/m_ml/DimensionReduction.js index 93ba2686..bd6eb20a 100644 --- a/js/m_ml/DimensionReduction.js +++ b/js/m_ml/DimensionReduction.js @@ -50,11 +50,7 @@ define([ this.modelConfig = ML_LIBRARIES; this.modelTypeList = { - // 'Regression': ['ln-rgs', 'sv-rgs', 'dt-rgs', 'rf-rgs', 'gbm-rgs', 'xgb-rgs', 'lgbm-rgs', 'cb-rgs'], - // 'Classfication': ['lg-rgs', 'sv-clf', 'dt-clf', 'rf-clf', 'gbm-clf', 'xgb-clf', 'lgbm-clf', 'cb-clf'], - // 'Auto ML': ['tpot-rgs', 'tpot-clf'], - // 'Clustering': ['k-means', 'agg-cls', 'gaus-mix', 'dbscan'], - 'Dimension Reduction': ['pca', 'lda', 'svd', 'nmf'] + 'Dimension Reduction': ['pca', 'lda', 'svd', 'nmf', 'tsne'] } diff --git a/js/m_ml/Regression.js b/js/m_ml/Regression.js index 7a08dd68..97d3b7cb 100644 --- a/js/m_ml/Regression.js +++ b/js/m_ml/Regression.js @@ -50,11 +50,7 @@ define([ this.modelConfig = ML_LIBRARIES; this.modelTypeList = { - 'Regression': ['ln-rgs', 'sv-rgs', 'dt-rgs', 'rf-rgs', 'gbm-rgs', 'xgb-rgs', 'lgbm-rgs', 'cb-rgs'], - // 'Classfication': ['lg-rgs', 'sv-clf', 'dt-clf', 'rf-clf', 'gbm-clf', 'xgb-clf', 'lgbm-clf', 'cb-clf'], - // 'Auto ML': ['tpot-rgs', 'tpot-clf'], - // 'Clustering': ['k-means', 'agg-cls', 'gaus-mix', 'dbscan'], - // 'Dimension Reduction': ['pca', 'lda', 'svd', 'nmf'] + 'Regression': ['ln-rgs', 'ridge', 'lasso', 'elasticnet', 'sv-rgs', 'dt-rgs', 'rf-rgs', 'gbm-rgs', 'xgb-rgs', 'lgbm-rgs', 'cb-rgs'], } From 830484e6e5ea52928f54f171030cca65654fb0e1 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Fri, 11 Mar 2022 19:19:13 +0900 Subject: [PATCH 17/27] Fix ModelSelection page using ModelEditor --- css/component/instanceEditor.css | 4 +- html/m_ml/evaluation.html | 4 +- html/m_ml/model.html | 4 +- js/com/com_generatorV2.js | 5 +- js/com/component/InstanceEditor.js | 2 - js/com/component/ModelEditor.js | 324 +++++++++++++++++++++++++++++ js/m_ml/AutoML.js | 27 ++- js/m_ml/Classification.js | 27 ++- js/m_ml/Clustering.js | 27 ++- js/m_ml/DimensionReduction.js | 27 ++- js/m_ml/Regression.js | 27 ++- js/m_ml/evaluation.js | 2 +- 12 files changed, 418 insertions(+), 62 deletions(-) create mode 100644 js/com/component/ModelEditor.js diff --git a/css/component/instanceEditor.css b/css/component/instanceEditor.css index 922872b3..1df973c2 100644 --- a/css/component/instanceEditor.css +++ b/css/component/instanceEditor.css @@ -17,8 +17,8 @@ .vp-ins-select-container .vp-ins-search-icon { position: absolute; color: #C4C4C4; - right: 5px; - top: 5px; + right: 7px; + top: 7px; } .vp-ins-select-box { margin-top: 5px; diff --git a/html/m_ml/evaluation.html b/html/m_ml/evaluation.html index b263afc7..8079b5d9 100644 --- a/html/m_ml/evaluation.html +++ b/html/m_ml/evaluation.html @@ -7,11 +7,9 @@
    diff --git a/html/m_ml/model.html b/html/m_ml/model.html index f33a2914..9a94fc9c 100644 --- a/html/m_ml/model.html +++ b/html/m_ml/model.html @@ -20,8 +20,8 @@
    - - + +
    diff --git a/js/com/com_generatorV2.js b/js/com/com_generatorV2.js index 76544590..c7c86b73 100644 --- a/js/com/com_generatorV2.js +++ b/js/com/com_generatorV2.js @@ -11,8 +11,9 @@ define([ 'vp_base/js/com/com_util', 'vp_base/js/com/com_makeDom', - 'vp_base/js/com/component/SuggestInput' -], function (com_util, com_makeDom, SuggestInput) { + 'vp_base/js/com/component/SuggestInput', + 'vp_base/js/com/component/VarSelector2' +], function (com_util, com_makeDom, SuggestInput, VarSelector2) { /** * show result after code executed */ diff --git a/js/com/component/InstanceEditor.js b/js/com/component/InstanceEditor.js index c3d78f35..ee3daf02 100644 --- a/js/com/component/InstanceEditor.js +++ b/js/com/component/InstanceEditor.js @@ -1,5 +1,3 @@ -const { param } = require("jquery"); - define([ 'css!vp_base/css/component/instanceEditor.css', 'vp_base/js/com/com_String', diff --git a/js/com/component/ModelEditor.js b/js/com/component/ModelEditor.js new file mode 100644 index 00000000..b6a3d218 --- /dev/null +++ b/js/com/component/ModelEditor.js @@ -0,0 +1,324 @@ +define([ + 'css!vp_base/css/component/instanceEditor.css', + 'vp_base/js/com/com_String', + 'vp_base/js/com/com_util', + 'vp_base/js/com/com_generatorV2', + 'vp_base/js/com/component/Component', + 'vp_base/js/com/component/SuggestInput' +], function(insCss, com_String, com_util, com_generator, Component, SuggestInput) { + + // temporary const + const VP_INS_BOX = 'vp-ins-box'; + const VP_INS_SELECT_CONTAINER = 'vp-ins-select-container'; + const VP_INS_SELECT_TITLE = 'vp-ins-select-title'; + const VP_INS_SEARCH = 'vp-ins-search'; + const VP_INS_TYPE = 'vp-ins-type'; + const VP_INS_SELECT_BOX = 'vp-ins-select-box'; + const VP_INS_SELECT_LIST = 'vp-ins-select-list'; + const VP_INS_SELECT_ITEM = 'vp-ins-select-item'; + + const VP_INS_PARAMETER_BOX = 'vp-ins-parameter-box'; + const VP_INS_PARAMETER = 'vp-ins-parameter'; + + const VP_CREATE_VAR_BOX = 'vp-create-var-box'; + const VP_CREATE_VAR = 'vp-create-var'; + const VP_CREATE_VAR_BTN = 'vp-create-var-btn'; + + class ModelEditor extends Component { + constructor(pageThis, targetId, containerId='vp_wrapper') { + super(null, { pageThis: pageThis, targetId: targetId, containerId: containerId }); + } + + _init() { + super._init(); + + this.pageThis = this.state.pageThis; + this.targetId = this.state.targetId; + this.containerId = this.state.containerId; + + this.state = { + action: {}, + info: {}, + config: {}, + ...this.state + } + } + + render() { + ; + } + + getModelCategory(modelType) { + let mlDict = vpConfig.getMLDataDict(); + let keys = Object.keys(mlDict); + let modelCategory = ''; + for (let i = 0; i < keys.length; i++) { + let key = keys[i]; + if (mlDict[key].includes(modelType)) { + modelCategory = key; + break; + } + } + return modelCategory; + } + + getAction(modelType) { + let category = this.getModelCategory(modelType); + let defaultActions = { + 'fit': { + name: 'fit', + code: '${model}.fit(${featureData}, ${targetData})', + options: [ + { name: 'featureData', component: ['var_select'], var_type: ['DataFrame'], default: 'X_train' }, + { name: 'targetData', component: ['var_select'], var_type: ['DataFrame'], default: 'y_train' } + ] + }, + 'predict': { + name: 'predict', + code: '${model}.predict(${featureData})', + options: [ + { name: 'featureData', component: ['var_select'], var_type: ['DataFrame'], default: 'X_train' } + ] + }, + 'predict_proba': { + name: 'predict_proba', + code: '${model}.predict_proba(${featureData})', + options: [ + { name: 'featureData', component: ['var_select'], var_type: ['DataFrame'], default: 'X_train' } + ] + }, + 'transform': { + name: 'transform', + code: '${model}.transform(${featureData})', + options: [ + { name: 'featureData', component: ['var_select'], var_type: ['DataFrame'], default: 'X_train' } + ] + } + }; + let actions = {}; + switch (category) { + case 'Regression': + actions = { + 'fit': defaultActions['fit'], + 'predict': defaultActions['predict'], + } + break; + case 'Classification': + actions = { + 'fit': defaultActions['fit'], + 'predict': defaultActions['predict'], + 'predict_proba': defaultActions['predict_proba'], + } + break; + case 'Auto ML': + actions = { + 'fit': defaultActions['fit'], + 'predict': defaultActions['predict'], + } + break; + case 'Clustering': + actions = { + 'fit': defaultActions['fit'], + 'predict': defaultActions['predict'], + } + break; + case 'Dimension Reduction': + actions = { + 'fit': defaultActions['fit'], + 'transform': defaultActions['transform'], + } + break; + } + return actions; + } + + getInfo(modelType) { + let category = this.getModelCategory(modelType); + let infos = {}; + let defaultInfos = { + 'score': { + name: 'score', + code: '${model}.score()', + options: [ + + ] + } + } + switch (category) { + case 'Regression': + infos = { + 'score': defaultInfos['score'] + } + break; + case 'Classification': + break; + case 'Auto ML': + break; + case 'Clustering': + break; + case 'Dimension Reduction': + break; + } + return infos; + } + + renderPage() { + var tag = new com_String(); + tag.appendFormatLine('
    ', VP_INS_BOX, this.uuid); // vp-select-base + + tag.appendFormatLine('
    ', VP_INS_SELECT_CONTAINER, 'action'); + tag.appendFormatLine('
    Action
    ', VP_INS_SELECT_TITLE); + + tag.appendFormatLine('
    ', 'position: relative;'); + tag.appendFormatLine('', VP_INS_SEARCH, 'attr'); + tag.appendFormatLine('', VP_INS_TYPE, 'action'); + tag.appendFormatLine('', 'fa fa-search', 'vp-ins-search-icon'); + tag.appendLine('
    '); + + tag.appendFormatLine('
    ', VP_INS_SELECT_BOX, 'action'); + tag.appendFormatLine('
      ', VP_INS_SELECT_LIST, 'action'); + tag.appendLine('
    '); + tag.appendLine('
    '); // VP_INS_SELECT_BOX + tag.appendLine('
    '); // VP_INS_SELECT_CONTAINER + + tag.appendFormatLine('
    ', VP_INS_SELECT_CONTAINER, 'info'); + tag.appendFormatLine('
    Info
    ', VP_INS_SELECT_TITLE); + + tag.appendFormatLine('
    ', 'position: relative;'); + tag.appendFormatLine('', VP_INS_SEARCH, 'method'); + tag.appendFormatLine('', VP_INS_TYPE, 'info'); + tag.appendFormatLine('', 'fa fa-search', 'vp-ins-search-icon'); + tag.appendLine('
    '); + + tag.appendFormatLine('
    ', VP_INS_SELECT_BOX, 'info'); + tag.appendFormatLine('
      ', VP_INS_SELECT_LIST, 'info'); + tag.appendLine('
    '); + tag.appendLine('
    '); // VP_INS_SELECT_BOX + tag.appendLine('
    '); // VP_INS_SELECT_CONTAINER + + tag.appendFormatLine('
    Options
    ', VP_INS_SELECT_TITLE); + tag.appendFormatLine('
    ', VP_INS_PARAMETER_BOX); + // TODO: option box + + tag.appendLine('
    '); // VP_INS_PARAMETER + + tag.appendLine('
    '); // VP_INS_BOX END + + $(this.pageThis.wrapSelector('#' + this.containerId)).html(tag.toString()); + + return tag.toString(); + } + + reload() { + this.renderPage(); + + let targetTag = $(this.pageThis.wrapSelector('#' + this.targetId)); + let model = $(targetTag).val(); + let modelType = $(targetTag).find('option:selected').data('type'); + + let actions = this.getAction(modelType); + let infos = this.getInfo(modelType); + this.state.action = { ...actions }; + this.state.info = { ...infos }; + + var actListTag = new com_String(); + var infoListTag = new com_String(); + + Object.keys(actions).forEach(actKey => { + actListTag.appendFormatLine('
  • {4}
  • ', + VP_INS_SELECT_ITEM, actKey, 'action', actKey, actKey); + }); + Object.keys(infos).forEach(infoKey => { + infoListTag.appendFormatLine('
  • {4}
  • ', + VP_INS_SELECT_ITEM, infoKey, 'info', infoKey, infoKey); + }); + + $(this.wrapSelector('.' + VP_INS_SELECT_LIST + '.action')).html(actListTag.toString()); + $(this.wrapSelector('.' + VP_INS_SELECT_LIST + '.info')).html(infoListTag.toString()); + + let that = this; + // action search suggest + var suggestInput = new SuggestInput(); + suggestInput.addClass('vp-input action'); + suggestInput.addClass(VP_INS_SEARCH); + suggestInput.setPlaceholder("Search Action"); + suggestInput.setSuggestList(function () { return Object.keys(actions); }); + suggestInput.setSelectEvent(function (value, item) { + $(this.wrapSelector()).val(value); + $(that.wrapSelector('.' + VP_INS_TYPE + '.action')).val(item.type); + + $(that.pageThis.wrapSelector('#' + that.targetId)).trigger({ + type: "model_editor_selected", + varName: value, + varOptions: actions[value], + isMethod: false + }); + }); + $(that.wrapSelector('.' + VP_INS_SEARCH + '.action')).replaceWith(function () { + return suggestInput.toTagString(); + }); + + // info search suggest + suggestInput = new SuggestInput(); + suggestInput.addClass('vp-input info'); + suggestInput.addClass(VP_INS_SEARCH); + suggestInput.setPlaceholder("Search info"); + suggestInput.setSuggestList(function () { return Object.keys(infos); }); + suggestInput.setSelectEvent(function (value, item) { + $(this.wrapSelector()).val(value); + $(that.wrapSelector('.' + VP_INS_TYPE + '.info')).val(item.type); + + $(that.pageThis.wrapSelector('#' + that.targetId)).trigger({ + type: "model_editor_selected", + varName: value, + varOptions: infos[value], + isMethod: true + }); + }); + $(that.wrapSelector('.' + VP_INS_SEARCH + '.info')).replaceWith(function () { + return suggestInput.toTagString(); + }); + + // bind event + this._bindEvent(); + } + + _bindEvent() { + super._bindEvent(); + let that = this; + + $(this.wrapSelector('.' + VP_INS_SELECT_ITEM)).on('click', function() { + let name = $(this).data('var-name'); + let type = $(this).data('var-type'); + let config = that.state[type][name]; + let optBox = new com_String(); + // render tag + config.options.forEach(opt => { + optBox.appendFormatLine('' + , opt.name, opt.name, opt.name); + let content = com_generator.renderContent(that, opt.component[0], opt, that.pageThis.state); + optBox.appendLine(content[0].outerHTML); + }); + // replace option box + $(that.wrapSelector('.' + VP_INS_PARAMETER_BOX)).html(optBox.toString()); + + that.state.config = config; + }); + } + + show() { + $(this.wrapSelector()).show(); + this.reload(); + } + + hide() { + $(this.wrapSelector()).hide(); + } + + getCode() { + return com_generator.vp_codeGenerator(this.pageThis, this.state.config, this.pageThis.state); + } + } + + return ModelEditor; +}); \ No newline at end of file diff --git a/js/m_ml/AutoML.js b/js/m_ml/AutoML.js index 873d9be6..9886c24d 100644 --- a/js/m_ml/AutoML.js +++ b/js/m_ml/AutoML.js @@ -21,8 +21,8 @@ define([ 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', - 'vp_base/js/com/component/InstanceEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, InstanceEditor) { + 'vp_base/js/com/component/ModelEditor' +], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { /** * AutoML @@ -40,7 +40,7 @@ define([ userOption: '', featureData: 'X_train', targetData: 'y_train', - allocateTo: 'model', + allocateToCreation: 'model', // model selection model: '', method: '', @@ -91,6 +91,11 @@ define([ com_interface.insertCell('code', config.install); } }); + + // change model + $(this.wrapSelector('#model')).on('change', function() { + that.modelEditor.show(); + }) } templateForBody() { @@ -168,7 +173,7 @@ define([ that.state.model = $(that.wrapSelector('#model')).val(); } - that.insEditor.show(); + that.modelEditor.show(); }); //================================================================ @@ -226,13 +231,13 @@ define([ render() { super.render(); - // Instance Editor - this.insEditor = new InstanceEditor(this, "model", "instanceEditor"); - this.insEditor.show(); + // Model Editor + this.modelEditor = new ModelEditor(this, "model", "instanceEditor"); + this.modelEditor.show(); } generateCode() { - let { modelControlType, modelType, userOption, featureData, targetData, allocateTo } = this.state; + let { modelControlType, modelType, userOption, featureData, targetData, allocateToCreation } = this.state; let code = new com_String(); if (modelControlType == 'creation') { /** @@ -248,14 +253,16 @@ define([ // model code let modelCode = config.code; modelCode = com_generator.vp_codeGenerator(this, config, this.state, userOption); - code.appendFormat('{0} = {1}', allocateTo, modelCode); + code.appendFormat('{0} = {1}', allocateToCreation, modelCode); } else { /** * Model Selection * --- * ... */ - + let modelCode = this.modelEditor.getCode(); + modelCode = modelCode.replace('${model}', model); + code.append(modelCode); } diff --git a/js/m_ml/Classification.js b/js/m_ml/Classification.js index c6cb9bec..c50c86f3 100644 --- a/js/m_ml/Classification.js +++ b/js/m_ml/Classification.js @@ -21,8 +21,8 @@ define([ 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', - 'vp_base/js/com/component/InstanceEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, InstanceEditor) { + 'vp_base/js/com/component/ModelEditor' +], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { /** * Classification @@ -40,7 +40,7 @@ define([ userOption: '', featureData: 'X_train', targetData: 'y_train', - allocateTo: 'model', + allocateToCreation: 'model', // model selection model: '', method: '', @@ -90,6 +90,11 @@ define([ com_interface.insertCell('code', config.install); } }); + + // change model + $(this.wrapSelector('#model')).on('change', function() { + that.modelEditor.show(); + }) } templateForBody() { @@ -167,7 +172,7 @@ define([ that.state.model = $(that.wrapSelector('#model')).val(); } - that.insEditor.show(); + that.modelEditor.show(); }); //================================================================ @@ -225,13 +230,13 @@ define([ render() { super.render(); - // Instance Editor - this.insEditor = new InstanceEditor(this, "model", "instanceEditor"); - this.insEditor.show(); + // Model Editor + this.modelEditor = new ModelEditor(this, "model", "instanceEditor"); + this.modelEditor.show(); } generateCode() { - let { modelControlType, modelType, userOption, featureData, targetData, allocateTo } = this.state; + let { modelControlType, modelType, userOption, featureData, targetData, allocateToCreation } = this.state; let code = new com_String(); if (modelControlType == 'creation') { /** @@ -247,14 +252,16 @@ define([ // model code let modelCode = config.code; modelCode = com_generator.vp_codeGenerator(this, config, this.state, userOption); - code.appendFormat('{0} = {1}', allocateTo, modelCode); + code.appendFormat('{0} = {1}', allocateToCreation, modelCode); } else { /** * Model Selection * --- * ... */ - + let modelCode = this.modelEditor.getCode(); + modelCode = modelCode.replace('${model}', model); + code.append(modelCode); } diff --git a/js/m_ml/Clustering.js b/js/m_ml/Clustering.js index 9d609a88..1d94c308 100644 --- a/js/m_ml/Clustering.js +++ b/js/m_ml/Clustering.js @@ -21,8 +21,8 @@ define([ 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', - 'vp_base/js/com/component/InstanceEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, InstanceEditor) { + 'vp_base/js/com/component/ModelEditor' +], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { /** * Clustering @@ -40,7 +40,7 @@ define([ userOption: '', featureData: 'X_train', targetData: 'y_train', - allocateTo: 'model', + allocateToCreation: 'model', // model selection model: '', method: '', @@ -94,6 +94,11 @@ define([ com_interface.insertCell('code', config.install); } }); + + // change model + $(this.wrapSelector('#model')).on('change', function() { + that.modelEditor.show(); + }) } templateForBody() { @@ -171,7 +176,7 @@ define([ that.state.model = $(that.wrapSelector('#model')).val(); } - that.insEditor.show(); + that.modelEditor.show(); }); //================================================================ @@ -229,13 +234,13 @@ define([ render() { super.render(); - // Instance Editor - this.insEditor = new InstanceEditor(this, "model", "instanceEditor"); - this.insEditor.show(); + // Model Editor + this.modelEditor = new ModelEditor(this, "model", "instanceEditor"); + this.modelEditor.show(); } generateCode() { - let { modelControlType, modelType, userOption, featureData, targetData, allocateTo } = this.state; + let { modelControlType, modelType, userOption, featureData, targetData, allocateToCreation } = this.state; let code = new com_String(); if (modelControlType == 'creation') { /** @@ -251,14 +256,16 @@ define([ // model code let modelCode = config.code; modelCode = com_generator.vp_codeGenerator(this, config, this.state, userOption); - code.appendFormat('{0} = {1}', allocateTo, modelCode); + code.appendFormat('{0} = {1}', allocateToCreation, modelCode); } else { /** * Model Selection * --- * ... */ - + let modelCode = this.modelEditor.getCode(); + modelCode = modelCode.replace('${model}', model); + code.append(modelCode); } diff --git a/js/m_ml/DimensionReduction.js b/js/m_ml/DimensionReduction.js index bd6eb20a..b0fa25d2 100644 --- a/js/m_ml/DimensionReduction.js +++ b/js/m_ml/DimensionReduction.js @@ -21,8 +21,8 @@ define([ 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', - 'vp_base/js/com/component/InstanceEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, InstanceEditor) { + 'vp_base/js/com/component/ModelEditor' +], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { /** * DimensionReduction @@ -40,7 +40,7 @@ define([ userOption: '', featureData: 'X_train', targetData: 'y_train', - allocateTo: 'model', + allocateToCreation: 'model', // model selection model: '', method: '', @@ -90,6 +90,11 @@ define([ com_interface.insertCell('code', config.install); } }); + + // change model + $(this.wrapSelector('#model')).on('change', function() { + that.modelEditor.show(); + }) } templateForBody() { @@ -167,7 +172,7 @@ define([ that.state.model = $(that.wrapSelector('#model')).val(); } - that.insEditor.show(); + that.modelEditor.show(); }); //================================================================ @@ -225,13 +230,13 @@ define([ render() { super.render(); - // Instance Editor - this.insEditor = new InstanceEditor(this, "model", "instanceEditor"); - this.insEditor.show(); + // Model Editor + this.modelEditor = new ModelEditor(this, "model", "instanceEditor"); + this.modelEditor.show(); } generateCode() { - let { modelControlType, modelType, userOption, featureData, targetData, allocateTo } = this.state; + let { modelControlType, modelType, userOption, featureData, targetData, allocateToCreation } = this.state; let code = new com_String(); if (modelControlType == 'creation') { /** @@ -247,14 +252,16 @@ define([ // model code let modelCode = config.code; modelCode = com_generator.vp_codeGenerator(this, config, this.state, userOption); - code.appendFormat('{0} = {1}', allocateTo, modelCode); + code.appendFormat('{0} = {1}', allocateToCreation, modelCode); } else { /** * Model Selection * --- * ... */ - + let modelCode = this.modelEditor.getCode(); + modelCode = modelCode.replace('${model}', model); + code.append(modelCode); } diff --git a/js/m_ml/Regression.js b/js/m_ml/Regression.js index 97d3b7cb..2503b96a 100644 --- a/js/m_ml/Regression.js +++ b/js/m_ml/Regression.js @@ -21,8 +21,8 @@ define([ 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', - 'vp_base/js/com/component/InstanceEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, InstanceEditor) { + 'vp_base/js/com/component/ModelEditor' +], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { /** * Regression @@ -40,7 +40,7 @@ define([ userOption: '', featureData: 'X_train', targetData: 'y_train', - allocateTo: 'model', + allocateToCreation: 'model', // model selection model: '', method: '', @@ -90,6 +90,11 @@ define([ com_interface.insertCell('code', config.install); } }); + + // change model + $(this.wrapSelector('#model')).on('change', function() { + that.modelEditor.show(); + }) } templateForBody() { @@ -167,7 +172,7 @@ define([ that.state.model = $(that.wrapSelector('#model')).val(); } - that.insEditor.show(); + that.modelEditor.show(); }); //================================================================ @@ -225,13 +230,13 @@ define([ render() { super.render(); - // Instance Editor - this.insEditor = new InstanceEditor(this, "model", "instanceEditor"); - this.insEditor.show(); + // Model Editor + this.modelEditor = new ModelEditor(this, "model", "instanceEditor"); + this.modelEditor.show(); } generateCode() { - let { modelControlType, modelType, userOption, featureData, targetData, allocateTo } = this.state; + let { modelControlType, modelType, userOption, allocateToCreation, model } = this.state; let code = new com_String(); if (modelControlType == 'creation') { /** @@ -247,14 +252,16 @@ define([ // model code let modelCode = config.code; modelCode = com_generator.vp_codeGenerator(this, config, this.state, userOption); - code.appendFormat('{0} = {1}', allocateTo, modelCode); + code.appendFormat('{0} = {1}', allocateToCreation, modelCode); } else { /** * Model Selection * --- * ... */ - + let modelCode = this.modelEditor.getCode(); + modelCode = modelCode.replace('${model}', model); + code.append(modelCode); } diff --git a/js/m_ml/evaluation.js b/js/m_ml/evaluation.js index 432e8f31..75bf3484 100644 --- a/js/m_ml/evaluation.js +++ b/js/m_ml/evaluation.js @@ -31,7 +31,7 @@ define([ this.config.dataview = false; this.state = { - modelType: 'clf', + modelType: 'rgs', predictData: 'pred', targetData: 'y_test', // classification From 3c5b2a2d5b13732156dc52f6c8741e3ff1360925 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Fri, 11 Mar 2022 19:47:28 +0900 Subject: [PATCH 18/27] Fix Model editor #1 --- css/component/instanceEditor.css | 4 ++ js/com/component/ModelEditor.js | 68 ++++++++++++++++++++++---------- js/m_ml/AutoML.js | 5 +-- js/m_ml/Classification.js | 5 +-- js/m_ml/Clustering.js | 5 +-- js/m_ml/DimensionReduction.js | 5 +-- js/m_ml/Regression.js | 5 +-- 7 files changed, 57 insertions(+), 40 deletions(-) diff --git a/css/component/instanceEditor.css b/css/component/instanceEditor.css index 1df973c2..4f321f65 100644 --- a/css/component/instanceEditor.css +++ b/css/component/instanceEditor.css @@ -74,6 +74,10 @@ .vp-ins-parameter-box { grid-column: 1/3; } +.vp-ins-parameter-box:empty::after { + content: '(Empty)'; + color: var(--gray-color); +} .vp-ins-parameter { width: 100% !important; } diff --git a/js/com/component/ModelEditor.js b/js/com/component/ModelEditor.js index b6a3d218..d29b6f09 100644 --- a/js/com/component/ModelEditor.js +++ b/js/com/component/ModelEditor.js @@ -20,10 +20,6 @@ define([ const VP_INS_PARAMETER_BOX = 'vp-ins-parameter-box'; const VP_INS_PARAMETER = 'vp-ins-parameter'; - const VP_CREATE_VAR_BOX = 'vp-create-var-box'; - const VP_CREATE_VAR = 'vp-create-var'; - const VP_CREATE_VAR_BTN = 'vp-create-var-btn'; - class ModelEditor extends Component { constructor(pageThis, targetId, containerId='vp_wrapper') { super(null, { pageThis: pageThis, targetId: targetId, containerId: containerId }); @@ -69,29 +65,29 @@ define([ name: 'fit', code: '${model}.fit(${featureData}, ${targetData})', options: [ - { name: 'featureData', component: ['var_select'], var_type: ['DataFrame'], default: 'X_train' }, - { name: 'targetData', component: ['var_select'], var_type: ['DataFrame'], default: 'y_train' } + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' }, + { name: 'targetData', label: 'Target Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'y_train' } ] }, 'predict': { name: 'predict', code: '${model}.predict(${featureData})', options: [ - { name: 'featureData', component: ['var_select'], var_type: ['DataFrame'], default: 'X_train' } + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' } ] }, 'predict_proba': { name: 'predict_proba', code: '${model}.predict_proba(${featureData})', options: [ - { name: 'featureData', component: ['var_select'], var_type: ['DataFrame'], default: 'X_train' } + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' } ] }, 'transform': { name: 'transform', code: '${model}.transform(${featureData})', options: [ - { name: 'featureData', component: ['var_select'], var_type: ['DataFrame'], default: 'X_train' } + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' } ] } }; @@ -138,19 +134,37 @@ define([ let defaultInfos = { 'score': { name: 'score', - code: '${model}.score()', + code: '${model}.score(${featureData}, {targetData})', options: [ - + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X' }, + { name: 'targetData', label: 'Target Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'y' } + ] + }, + 'cross_val_score': { + name: 'cross_val_score', + import: 'from sklearn.model_selection import cross_val_score', + code: '${allocateScore} = cross_val_score(${model}, ${featureData}, ${targetData}${scoring}${cv})', + options: [ + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X' }, + { name: 'targetData', label: 'Target Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'y' }, + { name: 'scoring', component: ['input'], usePair: true }, + { name: 'cv', component: ['input'], usePair: true }, + { name: 'allocateScore', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } ] } } switch (category) { case 'Regression': infos = { - 'score': defaultInfos['score'] + 'score': defaultInfos['score'], + 'cross_val_score': defaultInfos['cross_val_score'] } break; case 'Classification': + infos = { + 'score': defaultInfos['score'], + 'cross_val_score': defaultInfos['cross_val_score'] + } break; case 'Auto ML': break; @@ -197,11 +211,7 @@ define([ tag.appendLine('
    '); // VP_INS_SELECT_CONTAINER tag.appendFormatLine('
    Options
    ', VP_INS_SELECT_TITLE); - tag.appendFormatLine('
    ', VP_INS_PARAMETER_BOX); - // TODO: option box - - tag.appendLine('
    '); // VP_INS_PARAMETER - + tag.appendFormatLine('
    ', VP_INS_PARAMETER_BOX); tag.appendLine(''); // VP_INS_BOX END $(this.pageThis.wrapSelector('#' + this.containerId)).html(tag.toString()); @@ -294,8 +304,12 @@ define([ let optBox = new com_String(); // render tag config.options.forEach(opt => { + let label = opt.name; + if (opt.label != undefined) { + label = opt.label; + } optBox.appendFormatLine('' - , opt.name, opt.name, opt.name); + , opt.name, opt.name, label); let content = com_generator.renderContent(that, opt.component[0], opt, that.pageThis.state); optBox.appendLine(content[0].outerHTML); }); @@ -303,6 +317,10 @@ define([ $(that.wrapSelector('.' + VP_INS_PARAMETER_BOX)).html(optBox.toString()); that.state.config = config; + + // add selection + $(that.wrapSelector('.' + VP_INS_SELECT_ITEM)).removeClass('selected'); + $(this).addClass('selected'); }); } @@ -315,8 +333,18 @@ define([ $(this.wrapSelector()).hide(); } - getCode() { - return com_generator.vp_codeGenerator(this.pageThis, this.state.config, this.pageThis.state); + getCode(replaceDict={}) { + let code = new com_String(); + if (this.state.config.import != undefined) { + code.appendLine(this.state.config.import); + code.appendLine(); + } + let modelCode = com_generator.vp_codeGenerator(this.pageThis, this.state.config, this.pageThis.state); + Object.keys(replaceDict).forEach(key => { + modelCode = modelCode.replace(key, replaceDict[key]); + }); + code.append(modelCode); + return code.toString(); } } diff --git a/js/m_ml/AutoML.js b/js/m_ml/AutoML.js index 9886c24d..4a4b2939 100644 --- a/js/m_ml/AutoML.js +++ b/js/m_ml/AutoML.js @@ -260,10 +260,7 @@ define([ * --- * ... */ - let modelCode = this.modelEditor.getCode(); - modelCode = modelCode.replace('${model}', model); - code.append(modelCode); - + code.append(this.modelEditor.getCode({'${model}': model})); } return code.toString(); diff --git a/js/m_ml/Classification.js b/js/m_ml/Classification.js index c50c86f3..bcf5b134 100644 --- a/js/m_ml/Classification.js +++ b/js/m_ml/Classification.js @@ -259,10 +259,7 @@ define([ * --- * ... */ - let modelCode = this.modelEditor.getCode(); - modelCode = modelCode.replace('${model}', model); - code.append(modelCode); - + code.append(this.modelEditor.getCode({'${model}': model})); } return code.toString(); diff --git a/js/m_ml/Clustering.js b/js/m_ml/Clustering.js index 1d94c308..b3a48b04 100644 --- a/js/m_ml/Clustering.js +++ b/js/m_ml/Clustering.js @@ -263,10 +263,7 @@ define([ * --- * ... */ - let modelCode = this.modelEditor.getCode(); - modelCode = modelCode.replace('${model}', model); - code.append(modelCode); - + code.append(this.modelEditor.getCode({'${model}': model})); } return code.toString(); diff --git a/js/m_ml/DimensionReduction.js b/js/m_ml/DimensionReduction.js index b0fa25d2..c96b241f 100644 --- a/js/m_ml/DimensionReduction.js +++ b/js/m_ml/DimensionReduction.js @@ -259,10 +259,7 @@ define([ * --- * ... */ - let modelCode = this.modelEditor.getCode(); - modelCode = modelCode.replace('${model}', model); - code.append(modelCode); - + code.append(this.modelEditor.getCode({'${model}': model})); } return code.toString(); diff --git a/js/m_ml/Regression.js b/js/m_ml/Regression.js index 2503b96a..f9339b50 100644 --- a/js/m_ml/Regression.js +++ b/js/m_ml/Regression.js @@ -259,10 +259,7 @@ define([ * --- * ... */ - let modelCode = this.modelEditor.getCode(); - modelCode = modelCode.replace('${model}', model); - code.append(modelCode); - + code.append(this.modelEditor.getCode({'${model}': model})); } return code.toString(); From 54f862d91b20557cb4c1831b4b5794a3bc428945 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Mon, 14 Mar 2022 16:34:19 +0900 Subject: [PATCH 19/27] Fix ML apps - add more options, fix load/save --- data/m_ml/mlLibrary.js | 34 ++-- html/m_ml/evaluation.html | 24 +-- js/com/com_Config.js | 2 +- js/com/com_generatorV2.js | 47 +++-- js/com/component/LibraryComponent.js | 4 +- js/com/component/ModelEditor.js | 249 ++++++++++++++++++++++++--- js/com/component/NumpyComponent.js | 4 +- js/com/component/PopupComponent.js | 4 +- js/m_apps/Chart.js | 2 +- js/m_ml/AutoML.js | 11 +- js/m_ml/Classification.js | 11 +- js/m_ml/Clustering.js | 11 +- js/m_ml/DataPrep.js | 28 +-- js/m_ml/DimensionReduction.js | 11 +- js/m_ml/Regression.js | 11 +- js/m_ml/dataSplit.js | 2 +- js/m_ml/evaluation.js | 48 ++++-- js/m_ml/fitting.js | 2 +- js/m_ml/modelSelection.js | 2 +- js/m_ml/prediction.js | 2 +- js/m_ml/transformation.js | 2 +- 21 files changed, 362 insertions(+), 149 deletions(-) diff --git a/data/m_ml/mlLibrary.js b/data/m_ml/mlLibrary.js index ed6e2438..38c44534 100644 --- a/data/m_ml/mlLibrary.js +++ b/data/m_ml/mlLibrary.js @@ -275,7 +275,7 @@ define([ code: 'SVR(${C}${kernel}${gamma}${random_state}${etc})', options: [ { name: 'C', component: ['input_number'], placeholder: '1.0', usePair: true }, - { name: 'kernel', component: ['option_select'], default: 'rbf', type:'text', usePair: true, + { name: 'kernel', component: ['option_select'], type: 'text', default: 'rbf', type:'text', usePair: true, options: ['linear', 'poly', 'rbf', 'sigmoid', 'precomputed'] }, { name: 'gamma', component: ['option_suggest'], default: 'scale', type:'text', usePair: true, options: ['scale', 'auto'] }, @@ -287,7 +287,7 @@ define([ import: 'from sklearn.tree import DecisionTreeRegressor', code: 'DecisionTreeRegressor(${criterion}${max_depth}${min_samples_split}${random_state}${etc})', options: [ - { name: 'criterion', component: ['option_select'], default: 'squared_error', type:'text', + { name: 'criterion', component: ['option_select'], type: 'text', default: 'squared_error', type:'text', options: ['squared_error', 'friedman_mse', 'absolute_error', 'poisson'] }, { name: 'max_depth', component: ['input_number'], placeholder: 'None', usePair: true }, { name: 'min_samples_split', component: ['input_number'], default: 2, usePair: true }, @@ -300,7 +300,7 @@ define([ code: 'RandomForestRegressor(${n_estimators}${criterion}${max_depth}${min_samples_split}${n_jobs}${random_state}${etc})', options: [ { name: 'n_estimators', component: ['input_number'], default: 100, usePair: true }, - { name: 'criterion', component: ['option_select'], default: 'squared_error', type:'text', usePair: true, + { name: 'criterion', component: ['option_select'], type: 'text', default: 'squared_error', type:'text', usePair: true, options: ['squared_error', 'absolute_error', 'poisson'] }, { name: 'max_depth', component: ['input_number'], placeholder: 'None', usePair: true }, { name: 'min_samples_split', component: ['input_number'], default: 2, usePair: true }, @@ -313,11 +313,11 @@ define([ import: 'from sklearn.ensemble import GradientBoostingRegressor', code: 'GradientBoostingRegressor(${loss}${learning_rate}${n_estimators}${criterion}${random_state}${etc})', options: [ - { name: 'loss', component: ['option_select'], default: 'squared_error', type:'text', usePair: true, + { name: 'loss', component: ['option_select'], type: 'text', default: 'squared_error', type:'text', usePair: true, options: ['squared_error', 'absolute_error', 'huber', 'quantile'] }, { name: 'learning_rate', component: ['input_number'], default: 0.1, usePair: true }, { name: 'n_estimators', component: ['input_number'], default: 100, usePair: true }, - { name: 'criterion', component: ['option_select'], default: 'friedman_mse', type:'text', usePair: true, + { name: 'criterion', component: ['option_select'], type: 'text', default: 'friedman_mse', type:'text', usePair: true, options: ['friedman_mse', 'squared_error', 'mse', 'mae'] }, { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } ] @@ -341,7 +341,7 @@ define([ import: 'from lightgbm import LGBMRegressor', code: 'LGBMRegressor(${boosting_type}${max_depth}${learning_rate}${n_estimators}${random_state}${etc})', options: [ - { name: 'boosting_type', component: ['option_select'], default: 'gbdt', type: 'text', usePair: true, + { name: 'boosting_type', component: ['option_select'], type: 'text', default: 'gbdt', type: 'text', usePair: true, options: ['gbdt', 'dart', 'goss', 'rf']}, { name: 'max_depth', component: ['input_number'], placeholder: '-1', usePair: true }, { name: 'learning_rate', component: ['input_number'], default: 0.1, usePair: true }, @@ -356,9 +356,9 @@ define([ code: 'CatBoostRegressor(${learning_rate}${loss_function}${task_type}${max_depth}${n_estimators}${random_state}${etc})', options: [ { name: 'learning_rate', component: ['input_number'], placeholder: 'None', usePair: true }, - { name: 'loss_function', component: ['option_select'], default: 'RMSE', type:'text', usePair: true, + { name: 'loss_function', component: ['option_select'], type: 'text', default: 'RMSE', type:'text', usePair: true, options: ['RMSE', 'absolute_error', 'huber', 'quantile'] }, - { name: 'task_type', component: ['option_select'], default: 'CPU', usePair: true, + { name: 'task_type', component: ['option_select'], type: 'text', default: 'CPU', usePair: true, options: ['CPU', 'GPU'] }, { name: 'max_depth', component: ['input_number'], placeholder: 'None', usePair: true }, { name: 'n_estimators', component: ['input_number'], placeholder: 'None', usePair: true }, @@ -371,7 +371,7 @@ define([ import: 'from sklearn.linear_model import LogisticRegression', code: 'LogisticRegression(${penalty}${C}${random_state}${etc})', options: [ - { name: 'penalty', component: ['option_select'], default: 'l2', usePair: true, options: ['l1', 'l2', 'elasticnet', 'none']}, + { name: 'penalty', component: ['option_select'], type: 'text', default: 'l2', usePair: true, options: ['l1', 'l2', 'elasticnet', 'none']}, { name: 'C', component: ['input_number'], placeholder: '1.0', usePair: true }, { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } ] @@ -406,7 +406,7 @@ define([ code: 'SVC(${C}${kernel}${gamma}${random_state}${etc})', options: [ { name: 'C', component: ['input_number'], placeholder: '1.0', usePair: true }, - { name: 'kernel', component: ['option_select'], usePair: true, + { name: 'kernel', component: ['option_select'], type: 'text', usePair: true, options: ['linear', 'poly', 'rbf', 'sigmoid', 'precomputed'], default: 'rbf' }, { name: 'gamma', component: ['option_suggest'], usePair: true, options: ['scale', 'auto'], default: 'scale' }, @@ -418,7 +418,7 @@ define([ import: 'from sklearn.tree import DecisionTreeClassifier', code: 'DecisionTreeClassifier(${criterion}${max_depth}${min_samples_split}${random_state}${etc})', options: [ - { name: 'criterion', component: ['option_select'], default: 'squared_error', type:'text', + { name: 'criterion', component: ['option_select'], type: 'text', default: 'squared_error', type:'text', options: ['squared_error', 'friedman_mse', 'absolute_error', 'poisson'], usePair: true }, { name: 'max_depth', component: ['input_number'], placeholder: 'None', usePair: true }, { name: 'min_samples_split', component: ['input_number'], default: 2, usePair: true }, @@ -431,7 +431,7 @@ define([ code: 'RandomForestClassifier(${n_estimators}${criterion}${max_depth}${min_samples_split}${n_jobs}${random_state}${etc})', options: [ { name: 'n_estimators', component: ['input_number'], default: 100, usePair: true }, - { name: 'criterion', component: ['option_select'], default: 'gini', type:'text', usePair: true, + { name: 'criterion', component: ['option_select'], type: 'text', default: 'gini', type:'text', usePair: true, options: ['gini', 'entropy'] }, { name: 'max_depth', component: ['input_number'], placeholder: 'None', usePair: true }, { name: 'min_samples_split', component: ['input_number'], default: 2, usePair: true }, @@ -444,11 +444,11 @@ define([ import: 'from sklearn.ensemble import GradientBoostingClassifier', code: 'GradientBoostingClassifier(${loss}${learning_rate}${n_estimators}${criterion}${random_state}${etc})', options: [ - { name: 'loss', component: ['option_select'], default: 'deviance', type: 'text', usePair: true, + { name: 'loss', component: ['option_select'], type: 'text', default: 'deviance', type: 'text', usePair: true, options: ['deviance', 'exponential'] }, { name: 'learning_rate', component: ['input_number'], default: 0.1, usePair: true }, { name: 'n_estimators', component: ['input_number'], default: 100, usePair: true }, - { name: 'criterion', component: ['option_select'], default: 'friedman_mse', type:'text', usePair: true, + { name: 'criterion', component: ['option_select'], type: 'text', default: 'friedman_mse', type:'text', usePair: true, options: ['friedman_mse', 'squared_error', 'mse', 'mae'] }, { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true } ] @@ -472,7 +472,7 @@ define([ import: 'from lightgbm import LGBMClassifier', code: 'LGBMClassifier(${boosting_type}${max_depth}${learning_rate}${n_estimators}${random_state}${etc})', options: [ - { name: 'boosting_type', component: ['option_select'], default: 'gbdt', type: 'text', usePair: true, + { name: 'boosting_type', component: ['option_select'], type: 'text', default: 'gbdt', type: 'text', usePair: true, options: ['gbdt', 'dart', 'goss', 'rf']}, { name: 'max_depth', component: ['input_number'], placeholder: '-1', usePair: true }, { name: 'learning_rate', component: ['input_number'], default: 0.1, usePair: true }, @@ -487,9 +487,9 @@ define([ code: 'CatBoostClassifier(${learning_rate}${loss_function}${task_type}${max_depth}${n_estimators}${random_state}${etc})', options: [ { name: 'learning_rate', component: ['input_number'], placeholder: 'None', usePair: true }, - { name: 'loss_function', component: ['option_select'], default: 'RMSE', type:'text', usePair: true, + { name: 'loss_function', component: ['option_select'], type: 'text', default: 'RMSE', type:'text', usePair: true, options: ['RMSE', 'absolute_error', 'huber', 'quantile'] }, - { name: 'task_type', component: ['option_select'], default: 'CPU', usePair: true, + { name: 'task_type', component: ['option_select'], type: 'text', default: 'CPU', usePair: true, options: ['CPU', 'GPU'] }, { name: 'max_depth', component: ['input_number'], placeholder: 'None', usePair: true }, { name: 'n_estimators', component: ['input_number'], placeholder: 'None', usePair: true }, diff --git a/html/m_ml/evaluation.html b/html/m_ml/evaluation.html index 8079b5d9..ab85032f 100644 --- a/html/m_ml/evaluation.html +++ b/html/m_ml/evaluation.html @@ -18,6 +18,15 @@
    +
    + + + + + + + +
    @@ -26,19 +35,14 @@ -
    -
    - - - - - - - + +
    - + + +
    diff --git a/js/com/com_Config.js b/js/com/com_Config.js index 45921134..ada98e73 100644 --- a/js/com/com_Config.js +++ b/js/com/com_Config.js @@ -489,7 +489,7 @@ define([ 'LogisticRegression', 'BernoulliNB', 'MultinomialNB', 'GaussianNB', 'SVC', 'DecisionTreeClassifier', 'RandomForestClassifier', 'GradientBoostingClassifier', 'XGBClassifier', 'LGBMClassifier', 'CatBoostClassifier', ], 'Auto ML': [ - 'AutoSklearnRegressor', 'AutoSklearnClassifier', 'TPOTRegression', 'TPOTClassifier' + 'AutoSklearnRegressor', 'AutoSklearnClassifier', 'TPOTRegressor', 'TPOTClassifier' ], 'Clustering': [ 'KMeans', 'AgglomerativeClustering', 'GaussianMixture', 'DBSCAN', diff --git a/js/com/com_generatorV2.js b/js/com/com_generatorV2.js index c7c86b73..d699e1f0 100644 --- a/js/com/com_generatorV2.js +++ b/js/com/com_generatorV2.js @@ -43,7 +43,6 @@ define([ } const _VP_BOOL_OPTIONS = [ - { label: 'Default', value: '' }, { label: 'True', value: 'True' }, { label: 'False', value: 'False' } ] @@ -216,6 +215,8 @@ define([ let value = state[obj.name]; if (value == undefined) { value = ''; + } else { + obj.value = value; } // create as component type switch (componentType) { @@ -250,23 +251,15 @@ define([ content = renderTabBlock(pageThis, obj, state); break; case 'bool_checkbox': - // True False select box - var select = $(``); - select.append($('')) - .append($('')); - content = select; - break; case 'bool_select': - var optSlct = $('').attr({ - 'class':'vp-select option-select vp-state', - 'id':obj.name - }); + // True False select box + var optSlct = $(``); _VP_BOOL_OPTIONS.forEach((opt, idx) => { - var option = $(``).attr({ + var option = $(``).attr({ // 'id':opt, 'index':obj.index, 'name':obj.name, - 'value':opt.value + 'value':(obj.default==opt.value?'':opt.value) }); // cell metadata test if (value != undefined) { @@ -286,26 +279,26 @@ define([ 'class':'vp-select option-select vp-state', 'id':obj.name }); - // if required, no default option - if (obj.required != true) { - $(optSlct).append($('')); - } obj.options.forEach((opt, idx, arr) => { var label = (obj.options_label != undefined? obj.options_label[idx]:opt); + let isDefault = false; + if (obj.required != true && obj.default != undefined && obj.default == opt) { + isDefault = true; + label += ' (default)'; + } var option = $(``).attr({ // 'id':opt, 'index':obj.index, 'name':obj.name, - 'value':opt + 'value':(isDefault? '': opt) }); - // cell metadata test - if (value != undefined) { + // saved data + if ((value == opt) + || ((value == undefined || value == '') && isDefault)) { // set as saved value - if (value == opt) { - $(option).attr({ - 'selected':'selected' - }); - } + $(option).attr({ + 'selected':'selected' + }); } optSlct.append(option); }); @@ -324,7 +317,7 @@ define([ suggestInput.addClass('vp-input vp-state'); suggestInput.setSuggestList(function() { return obj.options; }); suggestInput.setNormalFilter(false); - suggestInput.setValue($(pageThis.wrapSelector('#' + obj.name)).val()); + suggestInput.setValue(value); suggestInput.setSelectEvent(function(selectedValue) { // trigger change $(pageThis.wrapSelector('#' + obj.name)).val(selectedValue); @@ -454,7 +447,7 @@ define([ suggestInput.addClass('vp-input vp-state'); suggestInput.setSuggestList(function() { return varList; }); suggestInput.setNormalFilter(false); - suggestInput.setValue($(divTag + ' #' + obj.name).val()); + suggestInput.setValue(defaultValue); suggestInput.setSelectEvent(function(selectedValue) { // trigger change $(divTag + ' #' + obj.name).val(selectedValue); diff --git a/js/com/component/LibraryComponent.js b/js/com/component/LibraryComponent.js index 97b66247..fce95286 100644 --- a/js/com/component/LibraryComponent.js +++ b/js/com/component/LibraryComponent.js @@ -72,7 +72,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { $(tag).val(savedValue); break; } @@ -100,7 +100,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { newValue = $(tag).val(); break; } diff --git a/js/com/component/ModelEditor.js b/js/com/component/ModelEditor.js index d29b6f09..dc2d5a18 100644 --- a/js/com/component/ModelEditor.js +++ b/js/com/component/ModelEditor.js @@ -21,7 +21,7 @@ define([ const VP_INS_PARAMETER = 'vp-ins-parameter'; class ModelEditor extends Component { - constructor(pageThis, targetId, containerId='vp_wrapper') { + constructor(pageThis, targetId, containerId) { super(null, { pageThis: pageThis, targetId: targetId, containerId: containerId }); } @@ -32,12 +32,25 @@ define([ this.targetId = this.state.targetId; this.containerId = this.state.containerId; + let modelEditorType = ''; + let modelEditorName = ''; + if (this.pageThis.state['modelEditorType'] == undefined) { + modelEditorType = ''; + } + if (this.pageThis.state['modelEditorName'] == undefined) { + modelEditorName = ''; + } + this.state = { + modelEditorType: modelEditorType, + modelEditorName: modelEditorName, action: {}, info: {}, config: {}, ...this.state } + + this.loaded = false; } render() { @@ -64,6 +77,7 @@ define([ 'fit': { name: 'fit', code: '${model}.fit(${featureData}, ${targetData})', + description: 'Perform modeling from features, or distance matrix.', options: [ { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' }, { name: 'targetData', label: 'Target Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'y_train' } @@ -72,6 +86,7 @@ define([ 'predict': { name: 'predict', code: '${model}.predict(${featureData})', + description: 'Predict the closest target data X belongs to.', options: [ { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' } ] @@ -79,20 +94,41 @@ define([ 'predict_proba': { name: 'predict_proba', code: '${model}.predict_proba(${featureData})', + description: 'Predict class probabilities for X.', options: [ { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' } ] }, 'transform': { name: 'transform', - code: '${model}.transform(${featureData})', + code: '${allocateTransform} = ${model}.transform(${featureData})', + description: 'Apply dimensionality reduction to X.', options: [ - { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' } + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' }, + { name: 'allocateTransform', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } ] } }; let actions = {}; switch (category) { + case 'Data Preparation': + actions = { + 'fit': defaultActions['fit'], + 'transform': { + ...defaultActions['transform'], + description: 'Transform labels to normalized encoding.' + }, + 'inverse_transform': { + name: 'inverse_transform', + code: '${allocateInverse} = ${model}.inverse_transform(${featureData})', + description: 'Transform binary labels back to multi-class labels.', + options: [ + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' }, + { name: 'allocateInverse', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } + ] + } + } + break; case 'Regression': actions = { 'fit': defaultActions['fit'], @@ -113,12 +149,41 @@ define([ } break; case 'Clustering': + if (modelType == 'AgglomerativeClustering' + || modelType == 'DBSCAN') { + actions = { + 'fit': defaultActions['fit'], + 'fit_predict': { + name: 'fit_predict', + code: '${model}.fit_predict(${featureData})', + description: 'Compute clusters from a data or distance matrix and predict labels.', + options: [ + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' } + ] + } + } + break; + } actions = { 'fit': defaultActions['fit'], 'predict': defaultActions['predict'], } break; case 'Dimension Reduction': + if (modelType == 'TSNE') { + actions = { + 'fit': defaultActions['fit'], + 'fit_transform': { + name: 'fit_transform', + code: '${model}.fit_transform(${featureData})', + description: 'Fit X into an embedded space and return that transformed output.', + options: [ + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' } + ] + } + } + break; + } actions = { 'fit': defaultActions['fit'], 'transform': defaultActions['transform'], @@ -135,6 +200,7 @@ define([ 'score': { name: 'score', code: '${model}.score(${featureData}, {targetData})', + description: '', options: [ { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X' }, { name: 'targetData', label: 'Target Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'y' } @@ -144,6 +210,7 @@ define([ name: 'cross_val_score', import: 'from sklearn.model_selection import cross_val_score', code: '${allocateScore} = cross_val_score(${model}, ${featureData}, ${targetData}${scoring}${cv})', + description: 'Evaluate a score by cross-validation.', options: [ { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X' }, { name: 'targetData', label: 'Target Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'y' }, @@ -151,26 +218,131 @@ define([ { name: 'cv', component: ['input'], usePair: true }, { name: 'allocateScore', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } ] + }, + 'get_params': { + name: 'get_params', + code: '${allocateParam} = ${model}.get_params(${deep})', + description: 'Get parameters for this estimator.', + options: [ + { name: 'deep', component: ['bool_select'], default: 'True', usePair: true }, + { name: 'allocateParam', component: ['input'] } + ] + }, + 'permutation_importance': { + name: 'permutation_importance', + import: 'from sklearn.inspection import permutation_importance', + code: '${allocateImportance} = permutation_importance(${model}, ${featureData}, ${targetData}${scoring}${random_state}${etc})', + description: 'Permutation importance for feature evaluation.', + options: [ + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' }, + { name: 'targetData', label: 'Target Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'y_train' }, + { name: 'scoring', component: ['input'], usePair: true }, + { name: 'random_state', component: ['input_number'], placeholder: '123', usePair: true }, + { name: 'allocateImportance', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } + ] } } switch (category) { + case 'Data Preparation': + infos = { + 'get_params': defaultInfos['get_params'] + } + break; case 'Regression': infos = { - 'score': defaultInfos['score'], - 'cross_val_score': defaultInfos['cross_val_score'] + 'score': { + ...defaultInfos['score'], + description: 'Return the coefficient of determination of the prediction.' + }, + 'cross_val_score': defaultInfos['cross_val_score'], + 'permutation_importance': defaultInfos['permutation_importance'], + 'Coefficient': { + name: 'Coefficient', + code: '${allocateCoef} = ${model}.coef_', + options: [ + { name: 'allocateCoef', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } + ] + }, + 'Intercept': { + name: 'Intercept', + code: '${allocateIntercept} = ${model}.intercept_', + options: [ + { name: 'allocateIntercept', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } + ] + } } break; case 'Classification': infos = { - 'score': defaultInfos['score'], - 'cross_val_score': defaultInfos['cross_val_score'] + 'score': { + ...defaultInfos['score'], + description: 'Return the mean accuracy on the given test data and labels.' + }, + 'cross_val_score': defaultInfos['cross_val_score'], + 'permutation_importance': defaultInfos['permutation_importance'] } break; case 'Auto ML': break; case 'Clustering': + infos = { + // 'Size of clusters': { + // name: 'Size of clusters', + // code: "print(f'Size of clusters: {np.bincount(pred)}')", // FIXME: model.cluster_centers_ / use model info or hide it + // options: [] + // } + } + + if (modelType == 'KMeans') { + infos = { + ...infos, + 'cluster_centers_': { + name: 'cluster_centers', + code: '${allocateCenters} = ${model}.cluster_centers_', + description: 'Coordinates of cluster centers.', + options: [ + { name: 'allocateCenters', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } + ] + }, + 'transform': { + name: 'transform', + code: '${allocateTransform} = ${model}.transform(${featureData})', + description: 'Transform X to a cluster-distance space.', + options: [ + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X' }, + { name: 'allocateTransform', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } + ] + } + } + } + + if (modelType == 'AgglomerativeClustering') { + infos = { + ...infos, + 'Dendrogram': { // FIXME: + name: 'Dendrogram', + code: "# import\nfrom scipy.cluster.hierarchy import dendrogram, ward\n\nlinkage_array = ward(${data})\ndendrogram(linkage_array, p=3, truncate_mode='level', no_labels=True)\nplt.show()", + description: 'Draw a dendrogram', + options: [ + { name: 'data', label: 'Data', component: ['var_select'], var_type: ['DataFrame']} + ] + } + } + } break; case 'Dimension Reduction': + if (modelType == 'PCA') { + infos = { + 'explained_variance_ratio_': { + name: 'explained_variance_ratio_', + code: '${allocateRatio} = ${model}.explained_variance_ratio_', + description: 'Percentage of variance explained by each of the selected components.', + options: [ + { name: 'allocateRatio', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } + ] + } + } + } break; } return infos; @@ -180,6 +352,10 @@ define([ var tag = new com_String(); tag.appendFormatLine('
    ', VP_INS_BOX, this.uuid); // vp-select-base + // Model Editor State (Saved state) + tag.appendFormatLine('', 'modelEditorType', this.state.modelEditorType); + tag.appendFormatLine('', 'modelEditorName', this.state.modelEditorName); + tag.appendFormatLine('
    ', VP_INS_SELECT_CONTAINER, 'action'); tag.appendFormatLine('
    Action
    ', VP_INS_SELECT_TITLE); @@ -236,11 +412,11 @@ define([ Object.keys(actions).forEach(actKey => { actListTag.appendFormatLine('
  • {4}
  • ', - VP_INS_SELECT_ITEM, actKey, 'action', actKey, actKey); + VP_INS_SELECT_ITEM, actKey, 'action', actions[actKey].description, actKey); }); Object.keys(infos).forEach(infoKey => { infoListTag.appendFormatLine('
  • {4}
  • ', - VP_INS_SELECT_ITEM, infoKey, 'info', infoKey, infoKey); + VP_INS_SELECT_ITEM, infoKey, 'info', infos[infoKey].description, infoKey); }); $(this.wrapSelector('.' + VP_INS_SELECT_LIST + '.action')).html(actListTag.toString()); @@ -291,36 +467,61 @@ define([ // bind event this._bindEvent(); - } - _bindEvent() { - super._bindEvent(); - let that = this; + // load once on initializing page + if (this.loaded == false) { + let { modelEditorType, modelEditorName } = this.pageThis.state; + if (modelEditorType != '' && modelEditorName != '') { + // render option page for saved state + that.renderOptionPage(modelEditorType, modelEditorName); + } + // set loaded true + this.loaded = true; + } + } - $(this.wrapSelector('.' + VP_INS_SELECT_ITEM)).on('click', function() { - let name = $(this).data('var-name'); - let type = $(this).data('var-type'); - let config = that.state[type][name]; + renderOptionPage(type, name) { + if (this.state[type] != undefined && this.state[type][name] != undefined) { + let config = this.state[type][name]; let optBox = new com_String(); // render tag - config.options.forEach(opt => { + config && config.options && config.options.forEach(opt => { let label = opt.name; if (opt.label != undefined) { label = opt.label; } optBox.appendFormatLine('' , opt.name, opt.name, label); - let content = com_generator.renderContent(that, opt.component[0], opt, that.pageThis.state); + let content = com_generator.renderContent(this, opt.component[0], opt, this.pageThis.state); optBox.appendLine(content[0].outerHTML); }); // replace option box - $(that.wrapSelector('.' + VP_INS_PARAMETER_BOX)).html(optBox.toString()); + $(this.wrapSelector('.' + VP_INS_PARAMETER_BOX)).html(optBox.toString()); + + this.state.config = config; + + // add selection + $(this.wrapSelector('.' + VP_INS_SELECT_ITEM)).removeClass('selected'); + let typeClass = '.' + VP_INS_SELECT_LIST + '.' + type; + let nameClass = '.' + VP_INS_SELECT_ITEM + '[data-var-name="' + name + '"]'; + $(this.wrapSelector(typeClass + ' ' + nameClass)).addClass('selected'); + // set state + $(this.wrapSelector('#modelEditorType')).val(type); + $(this.wrapSelector('#modelEditorName')).val(name); + this.pageThis.state.modelEditorType = type; + this.pageThis.state.modelEditorName = name; + } + } - that.state.config = config; + _bindEvent() { + super._bindEvent(); + let that = this; - // add selection - $(that.wrapSelector('.' + VP_INS_SELECT_ITEM)).removeClass('selected'); - $(this).addClass('selected'); + $(this.wrapSelector('.' + VP_INS_SELECT_ITEM)).on('click', function() { + let name = $(this).data('var-name'); + let type = $(this).data('var-type'); + + that.renderOptionPage(type, name); }); } diff --git a/js/com/component/NumpyComponent.js b/js/com/component/NumpyComponent.js index fab327db..09d50026 100644 --- a/js/com/component/NumpyComponent.js +++ b/js/com/component/NumpyComponent.js @@ -79,7 +79,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { $(tag).val(savedValue); break; } @@ -107,7 +107,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { newValue = $(tag).val(); break; } diff --git a/js/com/component/PopupComponent.js b/js/com/component/PopupComponent.js index af8c8431..5bb2062b 100644 --- a/js/com/component/PopupComponent.js +++ b/js/com/component/PopupComponent.js @@ -269,7 +269,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(this).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { newValue = $(this).val(); break; } @@ -541,7 +541,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { newValue = $(tag).val(); break; } diff --git a/js/m_apps/Chart.js b/js/m_apps/Chart.js index 7658bab9..76ed858e 100644 --- a/js/m_apps/Chart.js +++ b/js/m_apps/Chart.js @@ -173,7 +173,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { $(tag).val(savedValue); break; } diff --git a/js/m_ml/AutoML.js b/js/m_ml/AutoML.js index 4a4b2939..b08923d9 100644 --- a/js/m_ml/AutoML.js +++ b/js/m_ml/AutoML.js @@ -15,14 +15,14 @@ define([ 'text!vp_base/html/m_ml/model.html!strip', 'vp_base/js/com/com_util', - 'vp_base/js/com/com_Const', + 'vp_base/js/com/com_interface', 'vp_base/js/com/com_String', 'vp_base/js/com/com_generatorV2', 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', 'vp_base/js/com/component/ModelEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { +], function(msHtml, com_util, com_interface, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { /** * AutoML @@ -94,7 +94,7 @@ define([ // change model $(this.wrapSelector('#model')).on('change', function() { - that.modelEditor.show(); + that.modelEditor.reload(); }) } @@ -189,7 +189,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { $(tag).val(value); break; } @@ -233,11 +233,10 @@ define([ // Model Editor this.modelEditor = new ModelEditor(this, "model", "instanceEditor"); - this.modelEditor.show(); } generateCode() { - let { modelControlType, modelType, userOption, featureData, targetData, allocateToCreation } = this.state; + let { modelControlType, modelType, userOption, allocateToCreation, model } = this.state; let code = new com_String(); if (modelControlType == 'creation') { /** diff --git a/js/m_ml/Classification.js b/js/m_ml/Classification.js index bcf5b134..ebbf9c57 100644 --- a/js/m_ml/Classification.js +++ b/js/m_ml/Classification.js @@ -15,14 +15,14 @@ define([ 'text!vp_base/html/m_ml/model.html!strip', 'vp_base/js/com/com_util', - 'vp_base/js/com/com_Const', + 'vp_base/js/com/com_interface', 'vp_base/js/com/com_String', 'vp_base/js/com/com_generatorV2', 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', 'vp_base/js/com/component/ModelEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { +], function(msHtml, com_util, com_interface, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { /** * Classification @@ -93,7 +93,7 @@ define([ // change model $(this.wrapSelector('#model')).on('change', function() { - that.modelEditor.show(); + that.modelEditor.reload(); }) } @@ -188,7 +188,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { $(tag).val(value); break; } @@ -232,11 +232,10 @@ define([ // Model Editor this.modelEditor = new ModelEditor(this, "model", "instanceEditor"); - this.modelEditor.show(); } generateCode() { - let { modelControlType, modelType, userOption, featureData, targetData, allocateToCreation } = this.state; + let { modelControlType, modelType, userOption, allocateToCreation, model } = this.state; let code = new com_String(); if (modelControlType == 'creation') { /** diff --git a/js/m_ml/Clustering.js b/js/m_ml/Clustering.js index b3a48b04..70012515 100644 --- a/js/m_ml/Clustering.js +++ b/js/m_ml/Clustering.js @@ -15,14 +15,14 @@ define([ 'text!vp_base/html/m_ml/model.html!strip', 'vp_base/js/com/com_util', - 'vp_base/js/com/com_Const', + 'vp_base/js/com/com_interface', 'vp_base/js/com/com_String', 'vp_base/js/com/com_generatorV2', 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', 'vp_base/js/com/component/ModelEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { +], function(msHtml, com_util, com_interface, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { /** * Clustering @@ -97,7 +97,7 @@ define([ // change model $(this.wrapSelector('#model')).on('change', function() { - that.modelEditor.show(); + that.modelEditor.reload(); }) } @@ -192,7 +192,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { $(tag).val(value); break; } @@ -236,11 +236,10 @@ define([ // Model Editor this.modelEditor = new ModelEditor(this, "model", "instanceEditor"); - this.modelEditor.show(); } generateCode() { - let { modelControlType, modelType, userOption, featureData, targetData, allocateToCreation } = this.state; + let { modelControlType, modelType, userOption, allocateToCreation, model } = this.state; let code = new com_String(); if (modelControlType == 'creation') { /** diff --git a/js/m_ml/DataPrep.js b/js/m_ml/DataPrep.js index 54ce4cf3..e31f727f 100644 --- a/js/m_ml/DataPrep.js +++ b/js/m_ml/DataPrep.js @@ -15,15 +15,14 @@ define([ 'text!vp_base/html/m_ml/model.html!strip', 'vp_base/js/com/com_util', - 'vp_base/js/com/com_Const', - 'vp_base/js/com/com_String', 'vp_base/js/com/com_interface', + 'vp_base/js/com/com_String', 'vp_base/js/com/com_generatorV2', 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', - 'vp_base/js/com/component/InstanceEditor' -], function(msHtml, com_util, com_Const, com_String, com_interface, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, InstanceEditor) { + 'vp_base/js/com/component/ModelEditor' +], function(msHtml, com_util, com_interface, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { /** * DataPrep @@ -41,7 +40,7 @@ define([ userOption: '', featureData: 'X_train', targetData: 'y_train', - allocateTo: 'model', + allocateToCreation: 'model', // model selection model: '', method: '', @@ -92,6 +91,11 @@ define([ com_interface.insertCell('code', config.install); } }); + + // change model + $(this.wrapSelector('#model')).on('change', function() { + that.modelEditor.reload(); + }); } templateForBody() { @@ -169,7 +173,7 @@ define([ that.state.model = $(that.wrapSelector('#model')).val(); } - that.insEditor.show(); + that.modelEditor.show(); }); //================================================================ @@ -185,7 +189,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { $(tag).val(value); break; } @@ -231,12 +235,11 @@ define([ super.render(); // Instance Editor - this.insEditor = new InstanceEditor(this, "model", "instanceEditor"); - this.insEditor.show(); + this.modelEditor = new ModelEditor(this, "model", "instanceEditor"); } generateCode() { - let { modelControlType, modelType, userOption, featureData, targetData, allocateTo } = this.state; + let { modelControlType, modelType, userOption, allocateToCreation, model } = this.state; let code = new com_String(); if (modelControlType == 'creation') { /** @@ -252,15 +255,14 @@ define([ // model code let modelCode = config.code; modelCode = com_generator.vp_codeGenerator(this, config, this.state, userOption); - code.appendFormat('{0} = {1}', allocateTo, modelCode); + code.appendFormat('{0} = {1}', allocateToCreation, modelCode); } else { /** * Model Selection * --- * ... */ - - + code.append(this.modelEditor.getCode({'${model}': model})); } return code.toString(); diff --git a/js/m_ml/DimensionReduction.js b/js/m_ml/DimensionReduction.js index c96b241f..6f33e31f 100644 --- a/js/m_ml/DimensionReduction.js +++ b/js/m_ml/DimensionReduction.js @@ -15,14 +15,14 @@ define([ 'text!vp_base/html/m_ml/model.html!strip', 'vp_base/js/com/com_util', - 'vp_base/js/com/com_Const', + 'vp_base/js/com/com_interface', 'vp_base/js/com/com_String', 'vp_base/js/com/com_generatorV2', 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', 'vp_base/js/com/component/ModelEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { +], function(msHtml, com_util, com_interface, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { /** * DimensionReduction @@ -93,7 +93,7 @@ define([ // change model $(this.wrapSelector('#model')).on('change', function() { - that.modelEditor.show(); + that.modelEditor.reload(); }) } @@ -188,7 +188,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { $(tag).val(value); break; } @@ -232,11 +232,10 @@ define([ // Model Editor this.modelEditor = new ModelEditor(this, "model", "instanceEditor"); - this.modelEditor.show(); } generateCode() { - let { modelControlType, modelType, userOption, featureData, targetData, allocateToCreation } = this.state; + let { modelControlType, modelType, userOption, allocateToCreation, model } = this.state; let code = new com_String(); if (modelControlType == 'creation') { /** diff --git a/js/m_ml/Regression.js b/js/m_ml/Regression.js index f9339b50..dba1055c 100644 --- a/js/m_ml/Regression.js +++ b/js/m_ml/Regression.js @@ -15,14 +15,14 @@ define([ 'text!vp_base/html/m_ml/model.html!strip', 'vp_base/js/com/com_util', - 'vp_base/js/com/com_Const', + 'vp_base/js/com/com_interface', 'vp_base/js/com/com_String', 'vp_base/js/com/com_generatorV2', 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/VarSelector2', 'vp_base/js/com/component/ModelEditor' -], function(msHtml, com_util, com_Const, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { +], function(msHtml, com_util, com_interface, com_String, com_generator, ML_LIBRARIES, PopupComponent, VarSelector2, ModelEditor) { /** * Regression @@ -93,7 +93,7 @@ define([ // change model $(this.wrapSelector('#model')).on('change', function() { - that.modelEditor.show(); + that.modelEditor.reload(); }) } @@ -172,7 +172,7 @@ define([ that.state.model = $(that.wrapSelector('#model')).val(); } - that.modelEditor.show(); + that.modelEditor.reload(); }); //================================================================ @@ -188,7 +188,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { $(tag).val(value); break; } @@ -232,7 +232,6 @@ define([ // Model Editor this.modelEditor = new ModelEditor(this, "model", "instanceEditor"); - this.modelEditor.show(); } generateCode() { diff --git a/js/m_ml/dataSplit.js b/js/m_ml/dataSplit.js index bdf7bcd9..0361f213 100644 --- a/js/m_ml/dataSplit.js +++ b/js/m_ml/dataSplit.js @@ -135,7 +135,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { $(tag).val(value); break; } diff --git a/js/m_ml/evaluation.js b/js/m_ml/evaluation.js index 75bf3484..e84b4337 100644 --- a/js/m_ml/evaluation.js +++ b/js/m_ml/evaluation.js @@ -97,7 +97,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { $(tag).val(value); break; } @@ -122,11 +122,11 @@ define([ let { modelType, predictData, targetData, // classification - confusion_matrix, report, accuracy, precision, recall, f1_score, + confusion_matrix, report, accuracy, precision, recall, f1_score, roc_curve, auc, // regression coefficient, intercept, r_squared, mae, mape, rmse, scatter_plot, // clustering - sizeOfClusters, silhouetteScore + sizeOfClusters, silhouetteScore, ari, nm } = this.state; //==================================================================== @@ -157,20 +157,30 @@ define([ code.appendLine("# F1-score"); code.appendFormatLine("metrics.f1_score({0}, {1}, average='weighted')", targetData, predictData); } + if (roc_curve) { + code.appendLine("# ROC Curve"); + code.appendFormatLine("fpr, tpr, thresholds = roc_curve({0}, svc.decision_function({1}}))", predictData, targetData); + code.appendLine("plt.plot(fpr, tpr, label='ROC Curve')"); + code.appendLine("plt. xlabel('Sensitivity') "); + code.appendLine("plt. ylabel('Specificity') ") + } + if (auc) { + // FIXME: + } } //==================================================================== // Regression //==================================================================== if (modelType == 'rgs') { - if (coefficient) { - code.appendLine("# Coefficient (scikit-learn only)"); - code.appendFormatLine('model.coef_'); - } - if (intercept) { - code.appendLine("# Intercept (scikit-learn only)"); - code.appendFormatLine('model.intercept_'); - } + // if (coefficient) { + // code.appendLine("# Coefficient (scikit-learn only)"); + // code.appendFormatLine('model.coef_'); + // } + // if (intercept) { + // code.appendLine("# Intercept (scikit-learn only)"); + // code.appendFormatLine('model.intercept_'); + // } if (r_squared) { code.appendLine("# R square"); code.appendFormatLine('metrics.r2_score({0}, {1})', targetData, predictData); @@ -202,14 +212,22 @@ define([ // Clustering //==================================================================== if (modelType == 'cls') { - if (sizeOfClusters) { - code.appendLine("# Size of clusters"); - code.appendFormatLine("print(f'Size of clusters: {np.bincount({0})}')", predictData); - } + // if (sizeOfClusters) { + // code.appendLine("# Size of clusters"); + // code.appendFormatLine("print(f'Size of clusters: {np.bincount({0})}')", predictData); + // } if (silhouetteScore) { code.appendLine("# Silhouette score"); code.appendFormatLine("print(f'Silhouette score: {metrics.cluster.silhouette_score({0}, {1})}')", targetData, predictData); } + if (ari) { + code.appendLine("# ARI"); // FIXME: + code.appendFormatLine("print(f'ARI: {metrics.cluster.adjusted_rand_score({0}, {1})}')", targetData, predictData); + } + if (nm) { + code.appendLine("# NM"); // FIXME: + code.appendFormatLine("print(f'NM: {metrics.cluster.normalized_mutual_info_score({0}, {1})}')", targetData, predictData); + } } // FIXME: as seperated cells return code.toString(); diff --git a/js/m_ml/fitting.js b/js/m_ml/fitting.js index 0440bb28..937cdc7b 100644 --- a/js/m_ml/fitting.js +++ b/js/m_ml/fitting.js @@ -95,7 +95,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { $(tag).val(value); break; } diff --git a/js/m_ml/modelSelection.js b/js/m_ml/modelSelection.js index fc1e8dfd..a0873b2b 100644 --- a/js/m_ml/modelSelection.js +++ b/js/m_ml/modelSelection.js @@ -135,7 +135,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { $(tag).val(value); break; } diff --git a/js/m_ml/prediction.js b/js/m_ml/prediction.js index a5fe1485..1d62ec03 100644 --- a/js/m_ml/prediction.js +++ b/js/m_ml/prediction.js @@ -87,7 +87,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { $(tag).val(value); break; } diff --git a/js/m_ml/transformation.js b/js/m_ml/transformation.js index b2fcaa9f..5f4b1801 100644 --- a/js/m_ml/transformation.js +++ b/js/m_ml/transformation.js @@ -87,7 +87,7 @@ define([ switch(tagName) { case 'INPUT': let inputType = $(tag).prop('type'); - if (inputType == 'text' || inputType == 'number') { + if (inputType == 'text' || inputType == 'number' || inputType == 'hidden') { $(tag).val(value); break; } From 2e369e7d1a8d1456167cabbf4a4df3a53ab88378 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Mon, 14 Mar 2022 16:45:42 +0900 Subject: [PATCH 20/27] merge conflict --- js/m_ml/DataPrep.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/m_ml/DataPrep.js b/js/m_ml/DataPrep.js index 61c0f937..e31f727f 100644 --- a/js/m_ml/DataPrep.js +++ b/js/m_ml/DataPrep.js @@ -17,7 +17,6 @@ define([ 'vp_base/js/com/com_util', 'vp_base/js/com/com_interface', 'vp_base/js/com/com_String', - 'vp_base/js/com/com_interface', 'vp_base/js/com/com_generatorV2', 'vp_base/data/m_ml/mlLibrary', 'vp_base/js/com/component/PopupComponent', From 12755c684a23837a090dffb2ed48ca0178555ecb Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Mon, 14 Mar 2022 17:29:43 +0900 Subject: [PATCH 21/27] Fix Model options --- js/com/component/ModelEditor.js | 97 +++++++++++++++++++++++++++------ js/m_ml/evaluation.js | 12 ++-- 2 files changed, 86 insertions(+), 23 deletions(-) diff --git a/js/com/component/ModelEditor.js b/js/com/component/ModelEditor.js index dc2d5a18..6c22e297 100644 --- a/js/com/component/ModelEditor.js +++ b/js/com/component/ModelEditor.js @@ -85,18 +85,20 @@ define([ }, 'predict': { name: 'predict', - code: '${model}.predict(${featureData})', + code: '${allocatePredict} = ${model}.predict(${featureData})', description: 'Predict the closest target data X belongs to.', options: [ - { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' } + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_test' }, + { name: 'allocatePredict', label: 'Allocate to', component: ['input'], placeholder: 'New variable', default: 'pred' } ] }, 'predict_proba': { name: 'predict_proba', - code: '${model}.predict_proba(${featureData})', + code: '${allocatePredict} = ${model}.predict_proba(${featureData})', description: 'Predict class probabilities for X.', options: [ - { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' } + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_test' }, + { name: 'allocatePredict', label: 'Allocate to', component: ['input'], placeholder: 'New variable', default: 'pred' } ] }, 'transform': { @@ -104,7 +106,7 @@ define([ code: '${allocateTransform} = ${model}.transform(${featureData})', description: 'Apply dimensionality reduction to X.', options: [ - { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' }, + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X' }, { name: 'allocateTransform', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } ] } @@ -113,7 +115,23 @@ define([ switch (category) { case 'Data Preparation': actions = { - 'fit': defaultActions['fit'], + 'fit': { + name: 'fit', + code: '${model}.fit(${featureData})', + description: 'Fit Encoder/Scaler to X.', + options: [ + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X' } + ] + }, + 'fit_transform': { + name: 'fit_transform', + code: '${allocateTransform} = ${model}.fit_transform(${featureData})', + description: 'Fit Encoder/Scaler to X, then transform X.', + options: [ + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X' }, + { name: 'allocateTransform', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } + ] + }, 'transform': { ...defaultActions['transform'], description: 'Transform labels to normalized encoding.' @@ -141,11 +159,31 @@ define([ 'predict': defaultActions['predict'], 'predict_proba': defaultActions['predict_proba'], } + if (['LogisticRegression', 'SVC', 'GradientBoostingClassifier'].includes(modelType)) { + actions = { + ...actions, + 'decision_function': { + name: 'decision_function', + code: '${allocateScore} = ${model}.decision_function(${featureData})', + description: 'Compute the decision function of X.', + options: [ + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X' }, + { name: 'allocateScore', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } + ] + } + } + } break; case 'Auto ML': actions = { 'fit': defaultActions['fit'], - 'predict': defaultActions['predict'], + 'predict': defaultActions['predict'] + } + if (modelType == 'TPOTClassifier') { + actions = { + ...actions, + 'predict_proba': defaultActions['predict_proba'] + } } break; case 'Clustering': @@ -155,10 +193,11 @@ define([ 'fit': defaultActions['fit'], 'fit_predict': { name: 'fit_predict', - code: '${model}.fit_predict(${featureData})', + code: '${allocatePredict} = ${model}.fit_predict(${featureData})', description: 'Compute clusters from a data or distance matrix and predict labels.', options: [ - { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' } + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X' }, + { name: 'allocatePredict', label: 'Allocate to', component: ['input'], placeholder: 'New variable', default: 'pred' } ] } } @@ -167,6 +206,37 @@ define([ actions = { 'fit': defaultActions['fit'], 'predict': defaultActions['predict'], + 'fit_predict': { + name: 'fit_predict', + code: '${allocatePredict} = ${model}.fit_predict(${featureData})', + description: 'Compute cluster centers and predict cluster index for each sample.', + options: [ + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X' }, + { name: 'allocatePredict', label: 'Allocate to', component: ['input'], placeholder: 'New variable', default: 'pred' } + ] + } + } + if (modelType == 'KMeans') { + actions = { + ...actions, + 'fit_transform': { + name: 'fit_transform', + code: '${model}.fit_transform(${featureData})', + description: 'Compute clustering and transform X to cluster-distance space.', + options: [ + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X_train' } + ] + }, + 'transform': { + name: 'transform', + code: '${allocateTransform} = ${model}.transform(${featureData})', + description: 'Transform X to a cluster-distance space.', + options: [ + { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X' }, + { name: 'allocateTransform', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } + ] + } + } } break; case 'Dimension Reduction': @@ -303,15 +373,6 @@ define([ options: [ { name: 'allocateCenters', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } ] - }, - 'transform': { - name: 'transform', - code: '${allocateTransform} = ${model}.transform(${featureData})', - description: 'Transform X to a cluster-distance space.', - options: [ - { name: 'featureData', label: 'Feature Data', component: ['var_select'], var_type: ['DataFrame', 'Series'], default: 'X' }, - { name: 'allocateTransform', label: 'Allocate to', component: ['input'], placeholder: 'New variable' } - ] } } } diff --git a/js/m_ml/evaluation.js b/js/m_ml/evaluation.js index e84b4337..cc5361a8 100644 --- a/js/m_ml/evaluation.js +++ b/js/m_ml/evaluation.js @@ -161,11 +161,13 @@ define([ code.appendLine("# ROC Curve"); code.appendFormatLine("fpr, tpr, thresholds = roc_curve({0}, svc.decision_function({1}}))", predictData, targetData); code.appendLine("plt.plot(fpr, tpr, label='ROC Curve')"); - code.appendLine("plt. xlabel('Sensitivity') "); - code.appendLine("plt. ylabel('Specificity') ") + code.appendLine("plt.xlabel('Sensitivity') "); + code.appendLine("plt.ylabel('Specificity') ") } if (auc) { - // FIXME: + code.appendLine("# AUC"); + code.appendFormatLine("fpr, tpr, thresholds = roc_curve({0}, svc.decision_function({1}}))", predictData, targetData); + code.appendLine("metrics.auc(fpr, tpr)"); } } @@ -221,11 +223,11 @@ define([ code.appendFormatLine("print(f'Silhouette score: {metrics.cluster.silhouette_score({0}, {1})}')", targetData, predictData); } if (ari) { - code.appendLine("# ARI"); // FIXME: + code.appendLine("# ARI"); code.appendFormatLine("print(f'ARI: {metrics.cluster.adjusted_rand_score({0}, {1})}')", targetData, predictData); } if (nm) { - code.appendLine("# NM"); // FIXME: + code.appendLine("# NM"); code.appendFormatLine("print(f'NM: {metrics.cluster.normalized_mutual_info_score({0}, {1})}')", targetData, predictData); } } From bb536511a68521264fe64a752f5bd1156b56d151 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Mon, 14 Mar 2022 17:31:49 +0900 Subject: [PATCH 22/27] style fix --- html/m_ml/model.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/m_ml/model.html b/html/m_ml/model.html index 9a94fc9c..4c26c1c4 100644 --- a/html/m_ml/model.html +++ b/html/m_ml/model.html @@ -27,7 +27,7 @@
    -
    From 94baf25594046051ee72271d8a549ed707c4802d Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Mon, 14 Mar 2022 17:44:57 +0900 Subject: [PATCH 23/27] fix small bugs --- data/m_ml/mlLibrary.js | 12 ++++++------ js/com/com_util.js | 7 +++++++ js/com/component/ModelEditor.js | 2 ++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/data/m_ml/mlLibrary.js b/data/m_ml/mlLibrary.js index 38c44534..df44f019 100644 --- a/data/m_ml/mlLibrary.js +++ b/data/m_ml/mlLibrary.js @@ -499,8 +499,8 @@ define([ /** Auto ML */ 'auto-sklearn-rgs': { name: 'AutoSklearnRegressor (Linux only)', - install: 'pip install auto-sklearn', - import: 'from autosklearn import AutoSklearnRegressor', + install: '!pip install auto-sklearn', + import: 'from autosklearn.regression import AutoSklearnRegressor', link: 'https://automl.github.io/auto-sklearn/master/api.html#regression', code: 'AutoSklearnRegressor(${etc})', options: [ @@ -509,7 +509,7 @@ define([ }, 'tpot-rgs': { name: 'TPOTRegressor', - install: 'pip install tpot', + install: '!pip install tpot', import: 'from tpot import TPOTRegressor', code: 'TPOTRegressor(${generation}${population_size}${cv}${random_state}${etc})', options: [ @@ -521,8 +521,8 @@ define([ }, 'auto-sklearn-clf': { name: 'AutoSklearnClassifier (Linux only)', - install: 'pip install auto-sklearn', - import: 'from autosklearn import AutoSklearnClassifier', + install: '!pip install auto-sklearn', + import: 'from autosklearn.classification import AutoSklearnClassifier', link: 'https://automl.github.io/auto-sklearn/master/api.html#classification', code: 'AutoSklearnClassifier(${etc})', options: [ @@ -531,7 +531,7 @@ define([ }, 'tpot-clf': { name: 'TPOTClassifier', - install: 'pip install tpot', + install: '!pip install tpot', import: 'from tpot import TPOTClassifier', code: 'TPOTClassifier(${generation}${population_size}${cv}${random_state}${etc})', options: [ diff --git a/js/com/com_util.js b/js/com/com_util.js index 8533d38b..d63e5c7f 100644 --- a/js/com/com_util.js +++ b/js/com/com_util.js @@ -230,6 +230,12 @@ define([ return String(text).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } + var optionToLabel = function(label) { + label = label.replaceAll('_', ' '); + label = label.charAt(0).toUpperCase() + label.slice(1); + return label; + } + return { getUUID: getUUID, loadCss: loadCss, @@ -238,6 +244,7 @@ define([ addVariable: addVariable, formatString: formatString, convertToStr: convertToStr, + optionToLabel: optionToLabel, removeHeadScript: removeHeadScript, renderModal: renderModal, diff --git a/js/com/component/ModelEditor.js b/js/com/component/ModelEditor.js index 6c22e297..a147bdb2 100644 --- a/js/com/component/ModelEditor.js +++ b/js/com/component/ModelEditor.js @@ -551,6 +551,8 @@ define([ if (opt.label != undefined) { label = opt.label; } + // fix label + label = com_util.optionToLabel(label); optBox.appendFormatLine('' , opt.name, opt.name, label); let content = com_generator.renderContent(this, opt.component[0], opt, this.pageThis.state); From 7dd767994f5a4fe684ec05fb141a36bdc3f8cad4 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Mon, 14 Mar 2022 17:53:33 +0900 Subject: [PATCH 24/27] ML - option pages' label fixed (no underbar and add upper case --- js/m_ml/AutoML.js | 2 +- js/m_ml/Classification.js | 2 +- js/m_ml/Clustering.js | 2 +- js/m_ml/DataPrep.js | 2 +- js/m_ml/DimensionReduction.js | 2 +- js/m_ml/Regression.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/js/m_ml/AutoML.js b/js/m_ml/AutoML.js index b08923d9..24934a30 100644 --- a/js/m_ml/AutoML.js +++ b/js/m_ml/AutoML.js @@ -217,7 +217,7 @@ define([ // render tag config.options.forEach(opt => { optBox.appendFormatLine('' - , opt.name, opt.name, opt.name); + , opt.name, opt.name, com_util.optionToLabel(opt.name)); let content = com_generator.renderContent(this, opt.component[0], opt, state); optBox.appendLine(content[0].outerHTML); }); diff --git a/js/m_ml/Classification.js b/js/m_ml/Classification.js index ebbf9c57..d45cf083 100644 --- a/js/m_ml/Classification.js +++ b/js/m_ml/Classification.js @@ -216,7 +216,7 @@ define([ // render tag config.options.forEach(opt => { optBox.appendFormatLine('' - , opt.name, opt.name, opt.name); + , opt.name, opt.name, com_util.optionToLabel(opt.name)); let content = com_generator.renderContent(this, opt.component[0], opt, state); optBox.appendLine(content[0].outerHTML); }); diff --git a/js/m_ml/Clustering.js b/js/m_ml/Clustering.js index 70012515..f7f65976 100644 --- a/js/m_ml/Clustering.js +++ b/js/m_ml/Clustering.js @@ -220,7 +220,7 @@ define([ // render tag config.options.forEach(opt => { optBox.appendFormatLine('' - , opt.name, opt.name, opt.name); + , opt.name, opt.name, com_util.optionToLabel(opt.name)); let content = com_generator.renderContent(this, opt.component[0], opt, state); optBox.appendLine(content[0].outerHTML); }); diff --git a/js/m_ml/DataPrep.js b/js/m_ml/DataPrep.js index e31f727f..46455668 100644 --- a/js/m_ml/DataPrep.js +++ b/js/m_ml/DataPrep.js @@ -217,7 +217,7 @@ define([ // render tag config.options.forEach(opt => { optBox.appendFormatLine('' - , opt.name, opt.name, opt.name); + , opt.name, opt.name, com_util.optionToLabel(opt.name)); let content = com_generator.renderContent(this, opt.component[0], opt, state); optBox.appendLine(content[0].outerHTML); }); diff --git a/js/m_ml/DimensionReduction.js b/js/m_ml/DimensionReduction.js index 6f33e31f..9f976a3d 100644 --- a/js/m_ml/DimensionReduction.js +++ b/js/m_ml/DimensionReduction.js @@ -216,7 +216,7 @@ define([ // render tag config.options.forEach(opt => { optBox.appendFormatLine('' - , opt.name, opt.name, opt.name); + , opt.name, opt.name, com_util.optionToLabel(opt.name)); let content = com_generator.renderContent(this, opt.component[0], opt, state); optBox.appendLine(content[0].outerHTML); }); diff --git a/js/m_ml/Regression.js b/js/m_ml/Regression.js index dba1055c..b1e8d6c1 100644 --- a/js/m_ml/Regression.js +++ b/js/m_ml/Regression.js @@ -216,7 +216,7 @@ define([ // render tag config.options.forEach(opt => { optBox.appendFormatLine('' - , opt.name, opt.name, opt.name); + , opt.name, opt.name, com_util.optionToLabel(opt.name)); let content = com_generator.renderContent(this, opt.component[0], opt, state); optBox.appendLine(content[0].outerHTML); }); From beae73d55157148ee5934a16bc28578d3c78dfe2 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Mon, 14 Mar 2022 18:16:31 +0900 Subject: [PATCH 25/27] Confirm to save changes before clear note --- js/board/BoardFrame.js | 89 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 5 deletions(-) diff --git a/js/board/BoardFrame.js b/js/board/BoardFrame.js index 0a764153..7de1683d 100644 --- a/js/board/BoardFrame.js +++ b/js/board/BoardFrame.js @@ -90,7 +90,7 @@ define([ let menu = $(this).data('menu'); switch (menu) { case 'new': - that.createNewNote(); + that.createNewNoteWithChecking(); break; case 'open': that.openNote(); @@ -111,7 +111,7 @@ define([ that.exportCode(); break; case 'clear': - that.clearBoard(); + that.clearBoardWithChecking(); break; } }); @@ -429,9 +429,51 @@ define([ //======================================================================== // Note control //======================================================================== - createNewNote() { - // TODO: alert before closing + /** + * Check if note has changes to save + */ + checkNote() { + if (this.blockList.length > 0) { + return true; + } + return false; + } + createNewNoteWithChecking() { + // alert before closing + let that = this; + if (this.checkNote()) { + // render update modal + com_util.renderModal({ + title: 'Save changes', + message: 'Do you want to save changes?', + buttons: ['Cancel', "No", 'Save'], + defaultButtonIdx: 0, + buttonClass: ['cancel', '', 'activated'], + finish: function(clickedBtnIdx) { + switch (clickedBtnIdx) { + case 0: + // cancel - do nothing + return; + case 1: + // don't save + that.createNewNote(); + break; + case 2: + // save + that.saveAsNote(function() { + that.createNewNote(); + }); + break; + } + } + }); + return; + } + + this.createNewNote(); + } + createNewNote() { // clear board before create new note this.clearBoard(); @@ -502,7 +544,7 @@ define([ this.saveAsNote(); } - saveAsNote() { + saveAsNote(callback) { let that = this; // save file navigation let fileNavi = new FileNavigation({ @@ -525,6 +567,8 @@ define([ that.tmpState.boardTitle = boardTitle; that.tmpState.boardPath = boardPath; $('#vp_boardTitle').val(boardTitle); + + callback(); } }); fileNavi.open(); @@ -625,6 +669,41 @@ define([ // // reloadBlockList // this.reloadBlockList(); // } + clearBoardWithChecking() { + // alert before closing + let that = this; + if (this.checkNote()) { + // render update modal + com_util.renderModal({ + title: 'Save changes', + message: 'Do you want to save changes?', + buttons: ['Cancel', "No", 'Save'], + defaultButtonIdx: 0, + buttonClass: ['cancel', '', 'activated'], + finish: function(clickedBtnIdx) { + switch (clickedBtnIdx) { + case 0: + // cancel - do nothing + return; + case 1: + // don't save + that.clearBoard(); + break; + case 2: + // save + that.saveAsNote(function() { + that.clearBoard(); + }); + break; + } + } + }); + + return; + } + + this.clearBoard(); + } clearBoard() { // TODO: alert before clearing let that = this; From 2bd8b01239b941331d645d2257698a4ae4e824a4 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Mon, 14 Mar 2022 19:03:46 +0900 Subject: [PATCH 26/27] Add function able to insert multiple code cells - for ML evaluation --- js/board/BoardFrame.js | 19 ++++++-- js/com/com_interface.js | 40 +++++++++++++++++ js/com/component/PopupComponent.js | 15 ++++++- js/m_ml/evaluation.js | 69 ++++++++++++++++++++++-------- 4 files changed, 120 insertions(+), 23 deletions(-) diff --git a/js/board/BoardFrame.js b/js/board/BoardFrame.js index 7de1683d..caf61fb6 100644 --- a/js/board/BoardFrame.js +++ b/js/board/BoardFrame.js @@ -586,9 +586,22 @@ define([ let prevNewLine = idx > 0?'\n':''; let indent = ' '.repeat((groupBlock.depth - rootBlockDepth) * indentCount); let thisBlockCode = groupBlock.popup.generateCode(); - // set indent to every line of thisblockcode - thisBlockCode = thisBlockCode.replaceAll('\n', '\n' + indent); - code.appendFormat('{0}{1}{2}', prevNewLine, indent, thisBlockCode); + if (Array.isArray(thisBlockCode)) { + for (let i = 0; i < thisBlockCode.length; i++) { + thisBlockCode[i] = thisBlockCode[i].replaceAll('\n', '\n' + indent); + } + if (addcell) { + // insert single cell using prev code + com_interface.insertCell('code', code.toString(), execute, block.blockNumber); + code = new com_String(); + // insert cells using this block code list + com_interface.insertCells('code', thisBlockCode, execute, block.blockNumber); + } + } else { + // set indent to every line of thisblockcode + thisBlockCode = thisBlockCode.replaceAll('\n', '\n' + indent); + code.appendFormat('{0}{1}{2}', prevNewLine, indent, thisBlockCode); + } }); if (addcell) { com_interface.insertCell('code', code.toString(), execute, block.blockNumber); diff --git a/js/com/com_interface.js b/js/com/com_interface.js index e19e6167..e5f05e13 100644 --- a/js/com/com_interface.js +++ b/js/com/com_interface.js @@ -49,6 +49,45 @@ define([ com_util.renderSuccessMessage('Your code has been executed'); } + + /** + * Insert multiple cells + * @param {String} type + * @param {Array} commands + * @param {boolean} exec + * @param {int} sigNum + */ + var insertCells = function(type, commands, exec=true, sigNum=-1) { + var selectedIndex = getSelectedCell(); + var targetCell = Jupyter.notebook.insert_cell_below(type, selectedIndex); + + commands && commands.forEach((command, idx) => { + // Add signature + if (type == 'code' && sigNum >= 0) { + command = com_util.formatString('# VisualPython [{0}] - {1}\n', sigNum, idx + 1) + command + } + targetCell.set_text(command); + Jupyter.notebook.select_next(); + if (exec) { + switch (type) { + case "markdown": + targetCell.render(); + break; + case "code": + default: + targetCell.execute(); + } + } + + selectedIndex = getSelectedCell(); + targetCell = Jupyter.notebook.insert_cell_below(type, selectedIndex); + }); + + // move to executed cell + Jupyter.notebook.scroll_to_cell(Jupyter.notebook.get_selected_index()); + + com_util.renderSuccessMessage('Your code has been executed'); + } var enableOtherShortcut = function() { vpLog.display(VP_LOG_TYPE.DEVELOP, 'enable short cut'); @@ -62,6 +101,7 @@ define([ return { insertCell: insertCell, + insertCells: insertCells, enableOtherShortcut: enableOtherShortcut, disableOtherShortcut: disableOtherShortcut, diff --git a/js/com/component/PopupComponent.js b/js/com/component/PopupComponent.js index 5bb2062b..64275051 100644 --- a/js/com/component/PopupComponent.js +++ b/js/com/component/PopupComponent.js @@ -586,7 +586,12 @@ define([ blockNumber = block.blockNumber; } if (addcell) { - com_interface.insertCell(mode, code, execute, blockNumber); + if (Array.isArray(code)) { + // insert cells if it's array of codes + com_interface.insertCells(mode, code, execute, blockNumber); + } else { + com_interface.insertCell(mode, code, execute, blockNumber); + } } return code; } @@ -693,7 +698,13 @@ define([ openView(viewType) { if (viewType == 'code') { var code = this.generateCode(); - this.cmCodeview.setValue(code); + let codeText = ''; + if (Array.isArray(code)) { + codeText = code.join('\n'); + } else { + codeText = code; + } + this.cmCodeview.setValue(codeText); this.cmCodeview.save(); var that = this; diff --git a/js/m_ml/evaluation.js b/js/m_ml/evaluation.js index cc5361a8..53d74a02 100644 --- a/js/m_ml/evaluation.js +++ b/js/m_ml/evaluation.js @@ -118,6 +118,7 @@ define([ } generateCode() { + let codeCells = []; let code = new com_String(); let { modelType, predictData, targetData, @@ -134,40 +135,56 @@ define([ //==================================================================== if (modelType == 'clf') { if (confusion_matrix) { + code = new com_String(); code.appendLine("# Confusion Matrix"); - code.appendFormatLine('pd.crosstab({0}, {1}, margins=True)', targetData, predictData); + code.appendFormat('pd.crosstab({0}, {1}, margins=True)', targetData, predictData); + codeCells.push(code.toString()); } if (report) { + code = new com_String(); code.appendLine("# Classification report"); - code.appendFormatLine('print(metrics.classification_report({0}, {1}))', targetData, predictData); + code.appendFormat('print(metrics.classification_report({0}, {1}))', targetData, predictData); + codeCells.push(code.toString()); } if (accuracy) { + code = new com_String(); code.appendLine("# Accuracy"); - code.appendFormatLine('metrics.accuracy_score({0}, {1})', targetData, predictData); + code.appendFormat('metrics.accuracy_score({0}, {1})', targetData, predictData); + codeCells.push(code.toString()); } if (precision) { + code = new com_String(); code.appendLine("# Precision"); - code.appendFormatLine("metrics.precision_score({0}, {1}, average='weighted')", targetData, predictData); + code.appendFormat("metrics.precision_score({0}, {1}, average='weighted')", targetData, predictData); + codeCells.push(code.toString()); } if (recall) { + code = new com_String(); code.appendLine("# Recall"); - code.appendFormatLine("metrics.recall_score({0}, {1}, average='weighted')", targetData, predictData); + code.appendFormat("metrics.recall_score({0}, {1}, average='weighted')", targetData, predictData); + codeCells.push(code.toString()); } if (f1_score) { + code = new com_String(); code.appendLine("# F1-score"); - code.appendFormatLine("metrics.f1_score({0}, {1}, average='weighted')", targetData, predictData); + code.appendFormat("metrics.f1_score({0}, {1}, average='weighted')", targetData, predictData); + codeCells.push(code.toString()); } if (roc_curve) { + code = new com_String(); code.appendLine("# ROC Curve"); code.appendFormatLine("fpr, tpr, thresholds = roc_curve({0}, svc.decision_function({1}}))", predictData, targetData); code.appendLine("plt.plot(fpr, tpr, label='ROC Curve')"); code.appendLine("plt.xlabel('Sensitivity') "); - code.appendLine("plt.ylabel('Specificity') ") + code.append("plt.ylabel('Specificity') ") + codeCells.push(code.toString()); } if (auc) { + code = new com_String(); code.appendLine("# AUC"); code.appendFormatLine("fpr, tpr, thresholds = roc_curve({0}, svc.decision_function({1}}))", predictData, targetData); - code.appendLine("metrics.auc(fpr, tpr)"); + code.append("metrics.auc(fpr, tpr)"); + codeCells.push(code.toString()); } } @@ -184,30 +201,40 @@ define([ // code.appendFormatLine('model.intercept_'); // } if (r_squared) { + code = new com_String(); code.appendLine("# R square"); - code.appendFormatLine('metrics.r2_score({0}, {1})', targetData, predictData); + code.appendFormat('metrics.r2_score({0}, {1})', targetData, predictData); + codeCells.push(code.toString()); } if (mae) { + code = new com_String(); code.appendLine("# MAE(Mean Absolute Error)"); - code.appendFormatLine('metrics.mean_absolute_error({0}, {1})', targetData, predictData); + code.appendFormat('metrics.mean_absolute_error({0}, {1})', targetData, predictData); + codeCells.push(code.toString()); } if (mape) { + code = new com_String(); code.appendLine("# MAPE(Mean Absolute Percentage Error)"); code.appendLine('def MAPE(y_test, y_pred):'); code.appendLine(' return np.mean(np.abs((y_test - pred) / y_test)) * 100'); code.appendLine(); - code.appendFormatLine('MAPE({0}, {1})', targetData, predictData); + code.appendFormat('MAPE({0}, {1})', targetData, predictData); + codeCells.push(code.toString()); } if (rmse) { + code = new com_String(); code.appendLine("# RMSE(Root Mean Squared Error)"); - code.appendFormatLine('metrics.mean_squared_error({0}, {1})**0.5', targetData, predictData); + code.appendFormat('metrics.mean_squared_error({0}, {1})**0.5', targetData, predictData); + codeCells.push(code.toString()); } if (scatter_plot) { + code = new com_String(); code.appendLine('# Regression plot'); code.appendFormatLine('plt.scatter({0}, {1})', targetData, predictData); code.appendFormatLine("plt.xlabel('{0}')", targetData); code.appendFormatLine("plt.ylabel('{1}')", predictData); - code.appendLine('plt.show()'); + code.append('plt.show()'); + codeCells.push(code.toString()); } } //==================================================================== @@ -219,20 +246,26 @@ define([ // code.appendFormatLine("print(f'Size of clusters: {np.bincount({0})}')", predictData); // } if (silhouetteScore) { + code = new com_String(); code.appendLine("# Silhouette score"); - code.appendFormatLine("print(f'Silhouette score: {metrics.cluster.silhouette_score({0}, {1})}')", targetData, predictData); + code.appendFormat("print(f'Silhouette score: {metrics.cluster.silhouette_score({0}, {1})}')", targetData, predictData); + codeCells.push(code.toString()); } if (ari) { + code = new com_String(); code.appendLine("# ARI"); - code.appendFormatLine("print(f'ARI: {metrics.cluster.adjusted_rand_score({0}, {1})}')", targetData, predictData); + code.appendFormat("print(f'ARI: {metrics.cluster.adjusted_rand_score({0}, {1})}')", targetData, predictData); + codeCells.push(code.toString()); } if (nm) { + code = new com_String(); code.appendLine("# NM"); - code.appendFormatLine("print(f'NM: {metrics.cluster.normalized_mutual_info_score({0}, {1})}')", targetData, predictData); + code.appendFormat("print(f'NM: {metrics.cluster.normalized_mutual_info_score({0}, {1})}')", targetData, predictData); + codeCells.push(code.toString()); } } - // FIXME: as seperated cells - return code.toString(); + // return as seperated cells + return codeCells; } } From 43fed25a2d7dc39b3472c4b43ba21448ea35dc69 Mon Sep 17 00:00:00 2001 From: minjk-bl Date: Mon, 14 Mar 2022 19:03:55 +0900 Subject: [PATCH 27/27] small changes --- html/m_ml/evaluation.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/html/m_ml/evaluation.html b/html/m_ml/evaluation.html index ab85032f..2c23bf1c 100644 --- a/html/m_ml/evaluation.html +++ b/html/m_ml/evaluation.html @@ -35,14 +35,14 @@ - - + +
    - - + +