From f9002b5e589bb5650ff99ffa82ba4076043c7a75 Mon Sep 17 00:00:00 2001 From: Angelos Chatzimparmpas Date: Thu, 10 Dec 2020 12:22:16 +0100 Subject: [PATCH] new --- __pycache__/run.cpython-38.pyc | Bin 21191 -> 22503 bytes frontend/src/components/DataSpace.vue | 5 + .../src/components/FeatureSpaceDetail.vue | 25 ++- .../src/components/FeatureSpaceOverview.vue | 1 - frontend/src/components/Heatmap.vue | 197 +++++++++--------- frontend/src/components/Main.vue | 108 +++++++--- frontend/src/components/Results.vue | 2 +- run.py | 178 ++++++++-------- 8 files changed, 288 insertions(+), 228 deletions(-) diff --git a/__pycache__/run.cpython-38.pyc b/__pycache__/run.cpython-38.pyc index 1cc717511710f172abc28eb05676d0f04101492c..9a309e07a8ccae625926dfc6d08a9a08f47db23d 100644 GIT binary patch delta 7532 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 diff --git a/frontend/src/components/DataSpace.vue b/frontend/src/components/DataSpace.vue index 639b7d5..84598a5 100644 --- a/frontend/src/components/DataSpace.vue +++ b/frontend/src/components/DataSpace.vue @@ -24,6 +24,11 @@ export default { }, methods: { initializeBeeSwarm () { + var svg = d3.select("#BeeSwarm"); + svg.selectAll("*").remove(); + var svg = d3.select("#tooltip"); + svg.selectAll("*").remove(); + var tooltip = d3.select("#tooltip") var width = 2500 diff --git a/frontend/src/components/FeatureSpaceDetail.vue b/frontend/src/components/FeatureSpaceDetail.vue index cbf8d58..1b2e31b 100644 --- a/frontend/src/components/FeatureSpaceDetail.vue +++ b/frontend/src/components/FeatureSpaceDetail.vue @@ -7,9 +7,9 @@ - - - + + +
@@ -39,7 +39,8 @@ export default { corrMatrixCombTotal: [], VIFRemaining: [], MIRemaining: [], - computeNodes: 0 + computeNodes: 0, + featureAddRemCount: [], } }, methods: { @@ -163,7 +164,7 @@ export default { var quadrantNumberLocal = this.quadrantNumber var listofNodes = this.dataFS[0] var dataLoc = JSON.parse(this.dataFS[3+quadrantNumberLocal]) - + var pushEachFinal = [] var pushEach var oldVal @@ -285,7 +286,6 @@ export default { }) var links = [] - Object.entries(dataLoc).forEach( function ([feature, value]) { Object.entries(value).forEach( function ([featureInside, value]) { @@ -308,18 +308,20 @@ export default { ) }) + var lengthFeatureAddRem = this.featureAddRemCount.length + Object.entries(pushEachFinal).forEach( function ([index, feature]) { feature.value.forEach(function (element, indexIns) { if (element.valueIns > 0) { - links.push({"source": index, "target": index*feature.value.length+feature.value.length+indexIns, "value": Math.abs(element.valueIns) * 30, "lin_color": "#33a02c"}) + links.push({"source": index, "target": (index*feature.value.length+feature.value.length+indexIns)-lengthFeatureAddRem, "value": Math.abs(element.valueIns) * 30, "lin_color": "#33a02c"}) } else { - links.push({"source": index, "target": index*feature.value.length+feature.value.length+indexIns, "value": Math.abs(element.valueIns) * 30, "lin_color": "#e31a1c"}) + links.push({"source": index, "target": (index*feature.value.length+feature.value.length+indexIns)-lengthFeatureAddRem, "value": Math.abs(element.valueIns) * 30, "lin_color": "#e31a1c"}) } }) }) - + this.jsonData = {"nodes": nodes, "links": links}; this.graphVizualization() @@ -329,6 +331,7 @@ export default { var computeNodesVar = this.computeNodes var listofNodes = this.dataFS[0] + var corrTarget = JSON.parse(this.dataFS[8+this.quadrantNumber]) var corrGlob = JSON.parse(this.dataFS[13+this.quadrantNumber]) var uniqueTarget = JSON.parse(this.dataFS[18+this.quadrantNumber]) @@ -684,7 +687,7 @@ export default { it.style.visibility = "hidden"; }) } - console.log(d3.zoom()) + //Zoom functions function zoom_actions(){ svg.attr("transform", d3.event.transform) @@ -819,6 +822,8 @@ export default { EventBus.$on('quad', this.initializeNetwork) EventBus.$on('countNodes1', data => { this.computeNodes = data }) + EventBus.$on('removeFeatures', data => { this.featureAddRemCount = data }) + EventBus.$on('reset', this.reset) } } diff --git a/frontend/src/components/FeatureSpaceOverview.vue b/frontend/src/components/FeatureSpaceOverview.vue index 8c838b0..a4913df 100644 --- a/frontend/src/components/FeatureSpaceOverview.vue +++ b/frontend/src/components/FeatureSpaceOverview.vue @@ -259,7 +259,6 @@ export default { var root = treeData; root.x0 = curY; root.y0 = 0; - console.log(treeData.children) selectNode(treeData.children[this.keepRoot]); // current selected node // Collapse all children of root's children before rendering diff --git a/frontend/src/components/Heatmap.vue b/frontend/src/components/Heatmap.vue index 9010d88..f500fac 100644 --- a/frontend/src/components/Heatmap.vue +++ b/frontend/src/components/Heatmap.vue @@ -36,7 +36,9 @@ export default { keyLocal: 0, activeModels: 0, flagLocal: false, - smallScreenMode: '0px' + smallScreenMode: '0px', + dataFI: [], + featureData: [], } }, methods: { @@ -65,12 +67,69 @@ export default { // Clear Heatmap first var svg = d3.select("#Heatmap"); svg.selectAll("*").remove(); + var featureUni = JSON.parse(this.dataFI[0]) - var dataAll = {"columns":[["R","F1"],["R","F2"],["R","F2"],["R","F1&F2"],["R","F2&F3"],["R","F1&F3"],["R","F1&F2&F3"],["R","F1+F2"],["R","F2+F3"],["R","F1+F3"],["R","F1+F2+F3"],["R","F1-F2"],["R","F2-F3"],["R","F1-F3"],["R","F1-F2-F3"],["R","F1*F2"],["R","F2*F3"],["R","F1*F3"],["R","F1*F2*F3"],["R","F1/F2"],["R","F2/F3"],["R","F1/F3"],["R","F1/F2/F3"]],"index":[["Information Gain"],["Fisher-Score"],["Relative Risk"],["Odds Ratio"]],"data":[[0.1178,0.4834,0.1647,0.1633,0.3355,0.1353,0.0556,0.9388,0.9354,0.8548,0.7037,0.6092,0.3835,0.7285,0.6405,0.424,0.6935,0.5766,0.2275,0.8309,0.972,0.9439,0.9366],[0.0372,-0.09,0.5015,0.5663,0.5126,-0.0274,0.4304,0.9518,0.9499,0.9216,-0.0278,0.6516,0.3019,-0.0936,0.6597,0.2323,-0.0833,0.4921,0.122,0.9275,0.96095,0.955,0.9501],[0.378,0.5514,0.378,0.3929,0.3271,0.3816,0.3647,0.9303,0.9372,0.8356,0.5314,0.4069,0.4288,0.5496,0.4156,0.427,0.5299,0.3454,0.4511,0.88235,0.9705,0.9468,0.9405],[0.4988,0.4149,0.5952,0.0628,-0.1015,0.497,0.58,0.9531,0.9572,0.8494,0.6262,0.3854,0.6904,0.5711,0.346,0.5132,0.583,0.3917,0.5305,0.7074,0.9763,0.9632,0.9582]]} + var algorithms = [] + algorithms.push("Univariate FS") + algorithms.push("Permutation FI") + algorithms.push("Accuracy-based FI") + algorithms.push("Average") + algorithms.push("# Action #") + + var PermImpEli = JSON.parse(this.dataFI[1]) + var FeaturesAccuracy = JSON.parse(this.dataFI[2]) + var Features = this.featureData[0] + + var len2 = Features.length + + let arr = Object.values(featureUni.Score); + let minUni = Math.min(...arr); + let maxUni = Math.max(...arr); + + let len = algorithms.length + let indicesYAxis = [] + for (let i = 0; i < len+1; i++) { + indicesYAxis[i] = [algorithms[i]] + } + let indicesXAxis = [] + var temp = [] + for (let i = 0; i < len2; i++) { + temp = [] + temp.push("R") + var loop = i+1 + temp.push(Features[i].toString()+" (F"+loop+")") + indicesXAxis[i] = temp + } + + var values = [] + var modelData = [] + for (let j = 0; j < len2; j++) { + var data = [] + for (let i = 0; i modelData.map(row => row[i])) + + var dataAll = {"columns":indicesXAxis,"index":indicesYAxis,"data":transposedArray} this.heatmap_display(dataAll, "#Heatmap"); }, heatmap_display(data, heatmapId) { + var featuresAddRem = [] var cellSize = this.cellSize //########################################################################## // Patrick.Brockmann@lsce.ipsl.fr @@ -226,8 +285,8 @@ export default { return d.idx; }) .attr("class", "row"); - svg.append("text").attr("x", 150).attr("y", -40).text("Feature combination").style("font-size", "16px").attr("alignment-baseline","top") - svg.append("text").attr("transform", "rotate(-90)").attr("x", -42).attr("y", -90).style("text-anchor", "middle").style("font-size", "16px").text("Algorithm"); // -130 before for HeartC + svg.append("text").attr("x", 15).attr("y", -60).text("Feature").style("font-size", "16px").attr("alignment-baseline","top") + svg.append("text").attr("transform", "rotate(-90)").attr("x", -52).attr("y", -90).style("text-anchor", "middle").style("font-size", "16px").text("Technique"); // -130 before for HeartC var heatMap = row.selectAll(".cell") .data(function(d) { return d; @@ -260,61 +319,43 @@ export default { .attr("width", cellSize) .attr("height", cellSize) .style("fill", function(d) { - if (d != null) return colorScale(d); - else return "url(#diagonalHatch)"; + if (d == -1) return "url(#diagonalHatch)" + else if (d == -2) return "yellow" + else return colorScale(d) }) .on('mouseover', function(d, i, j) { - var k = Array.prototype.indexOf.call(j[i].parentNode.parentNode.childNodes,j[i].parentNode) - 3; - d3.select('#colLabel_' + i).classed("hover", true); - d3.select('#rowLabel_' + k).classed("hover", true); - if (d != null) { - tooltip.style("visibility", "visible"); - tooltip.html('
' + d.toFixed(2) + '
'); - } else - tooltip.style("visibility", "hidden"); + }) .on('mouseout', function(d, i, j) { - var k = Array.prototype.indexOf.call(j[i].parentNode.parentNode.childNodes,j[i].parentNode) - 3; - d3.select('#colLabel_' + i).classed("hover", false); - d3.select('#rowLabel_' + k).classed("hover", false); - tooltip.style("visibility", "hidden"); + }) .on("mousemove", function(d, i) { - tooltip.style("top", (d3.mouse(this)[1] + 55) + "px").style("left", (d3.mouse(this)[0]) + "px"); }) .on('click', function(d, i, j) { var rowsExtracted = svg.selectAll(".row")._groups[0] var k = Array.prototype.indexOf.call(j[i].parentNode.parentNode.childNodes,j[i].parentNode) - 3; d3.select(this).style("fill", function(d) { - if (d3.select(this).style("fill") === "url(\"#diagonalHatch\")"){ - return colorScale(d) - } else { - return "url(#diagonalHatch)" - } - }) - if (i+1 === j.length) { - if(d3.select(this).style("fill") === "url(\"#diagonalHatch\")") { - row.selectAll(".cr"+k).style("fill", "url(#diagonalHatch)") - } else { - row.selectAll(".cr"+k).style("fill", function(d) { - return colorScale(d) - }) - } - } - var finalresults = [] - for (let i = 0; i < rowsExtracted[0].childNodes.length - 1; i++) { - var results = [] - for (let j = 0; j < rowsExtracted.length; j++) { - if (rowsExtracted[j].childNodes[i].style.fill === "url(\"#diagonalHatch\")") { - } else { - results.push(j) + if (d3.select(this).style("fill") === "yellow" || d3.select(this).style("fill") === "url(\"#diagonalHatch\")") { + if (d3.select(this).style("fill") === "url(\"#diagonalHatch\")"){ + if (d == -2) { + const index = featuresAddRem.indexOf(i); + if (index > -1) { + featuresAddRem.splice(index, 1); } + EventBus.$emit('addFeature', featuresAddRem) + return 'yellow' + } else { + return colorScale(d) + } + } else { + featuresAddRem.push(i) + EventBus.$emit('removeFeatures', featuresAddRem) + return "url(#diagonalHatch)" } - finalresults.push(results) - } - EventBus.$emit('flagLocal', true) - EventBus.$emit('sendSelectedFeaturestoPickle', finalresults) - EventBus.$emit('SendSelectedFeaturesEvent', finalresults) + } else { + return colorScale(d) + } + }) }); var svgLeg = d3.select("#LegendHeat"); @@ -354,7 +395,7 @@ export default { }) .attr("y", viewerPosTop + cellSize); - svgLeg.append("text").attr("x", 200).attr("y", 50).text("Normalized feature importance").style("font-size", "16px").attr("alignment-baseline","top") + svgLeg.append("text").attr("x", 200).attr("y", 50).text("Normalized feature importance (FI)").style("font-size", "16px").attr("alignment-baseline","top") //================================================== // Change ordering of cells @@ -509,7 +550,11 @@ export default { } }, mounted () { - this.Heatmap() + EventBus.$on('HeatmapCall', data => { this.dataFI = data }) + EventBus.$on('HeatmapCall', this.Heatmap) + + EventBus.$on('quad', data => { this.featureData = data }) + EventBus.$on('reset', this.reset) } } @@ -537,59 +582,5 @@ text.hover { fill: #66F; font-background: #000; } -.heatmap_tooltip { - text-align: center; - font-family: monospace; - font-size: 14pt; - color: #000; - position: relative; - background: rgba(255, 255, 255, 0.8); - border: 4px solid #66F; - padding: 5px; - border-radius: 8px ; - -webkit-border-top-left-radius: 8px; - -webkit-border-top-right-radius: 8px; - -webkit-border-bottom-right-radius: 8px; - -webkit-border-bottom-left-radius: 8px; - -khtml-border-top-left-radius: 8px; - -khtml-border-top-right-radius: 8px; - -khtml-border-bottom-right-radius: 8px; - -khtml-border-bottom-left-radius: 8px; - -moz-border-radius-topleft: 8px; - -moz-border-radius-topright: 8px; - -moz-border-radius-bottomright: 8px; - -moz-border-radius-bottomleft: 8px; - border-top-left-radius: 8px; - border-top-right-radius: 8px; - border-bottom-right-radius: 8px; - border-bottom-left-radius: 8px; - width: 100px; - z-index:10000; - -webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.8); - -moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.8); - box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.8); -} -.heatmap_tooltip:after, .heatmap_tooltip:before { - top: 100%; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; -} -.heatmap_tooltip:after { - border-color: rgba(236, 240, 241, 0); - border-top-color: #FFFFF; - border-width: 10px; - left: 50%; - margin-left: -10px; -} -.heatmap_tooltip:before { - border-color: rgba(44, 62, 80, 0); - border-top-color: #66F; - border-width: 16px; - left: 50%; - margin-left: -16px; -} + \ No newline at end of file diff --git a/frontend/src/components/Main.vue b/frontend/src/components/Main.vue index 54b97b3..b521420 100755 --- a/frontend/src/components/Main.vue +++ b/frontend/src/components/Main.vue @@ -54,7 +54,7 @@ - Feature Selection Algorithms + Feature Selection (FS) Techniques @@ -107,6 +107,7 @@ export default Vue.extend({ }, data () { return { + featureAddRem: [], ValidResults: [], correlResulTranformed: [], PositiveValue: 75, @@ -153,8 +154,7 @@ export default Vue.extend({ provenanceData: '', localFile: '', toggleDeepMain: 1, - keyLoc: 0, - keyData: true, + keyImp: true, ClassifierIDsListRemaining: [], PredictSel: [] } @@ -383,28 +383,6 @@ export default Vue.extend({ console.log(error) }) }, - returnCorrel () { - const path = `http://127.0.0.1:5000/data/returnCorrelations` - - const axiosConfig = { - headers: { - 'Content-Type': 'application/json', - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Headers': 'Origin, Content-Type, X-Auth-Token', - 'Access-Control-Allow-Methods': 'GET, PUT, POST, DELETE, OPTIONS' - } - } - axios.get(path, axiosConfig) - .then(response => { - console.log('Server successfully send the correlation matrices!') - this.correlResul = response.data.correlResul - EventBus.$emit('quad', this.correlResul) - this.returnResults() - }) - .catch(error => { - console.log(error) - }) - }, returnCorrelTranformed () { const path = `http://127.0.0.1:5000/data/returnCorrelationsTransformed` @@ -427,6 +405,55 @@ export default Vue.extend({ console.log(error) }) }, + returnCorrel () { + const path = `http://127.0.0.1:5000/data/returnCorrelations` + + const axiosConfig = { + headers: { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'Origin, Content-Type, X-Auth-Token', + 'Access-Control-Allow-Methods': 'GET, PUT, POST, DELETE, OPTIONS' + } + } + axios.get(path, axiosConfig) + .then(response => { + console.log('Server successfully send the correlation matrices!') + this.correlResul = response.data.correlResul + EventBus.$emit('quad', this.correlResul) + if (this.keyImp) { + this.returnImportance() + this.keyImp = false + } else { + this.returnResults() + } + }) + .catch(error => { + console.log(error) + }) + }, + returnImportance () { + const path = `http://127.0.0.1:5000/data/sendFeatImp` + + const axiosConfig = { + headers: { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'Origin, Content-Type, X-Auth-Token', + 'Access-Control-Allow-Methods': 'GET, PUT, POST, DELETE, OPTIONS' + } + } + axios.get(path, axiosConfig) + .then(response => { + console.log('Server successfully send the predictive results!') + this.Importance = response.data.Importance + EventBus.$emit('HeatmapCall', this.Importance) + this.returnResults() + }) + .catch(error => { + console.log(error) + }) + }, returnResults () { const path = `http://127.0.0.1:5000/data/sendResults` @@ -447,7 +474,29 @@ export default Vue.extend({ .catch(error => { console.log(error) }) - } + }, + ManipulFeature () { + const path = `http://127.0.0.1:5000/data/AddRemFun` + const postData = { + featureAddRem: this.featureAddRem, + } + const axiosConfig = { + headers: { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'Origin, Content-Type, X-Auth-Token', + 'Access-Control-Allow-Methods': 'GET, PUT, POST, DELETE, OPTIONS' + } + } + axios.post(path, postData, axiosConfig) + .then(response => { + console.log('Sent an order to add or remove features!') + this.threshold() + }) + .catch(error => { + console.log(error) + }) + }, }, created () { // does the browser support the Navigation Timing API? @@ -480,9 +529,6 @@ export default Vue.extend({ }) - - EventBus.$on('sendKeyNow', data => { this.keyLoc = data }) - EventBus.$on('ReturningBrushedPointsIDs', data => { this.modelsUpdate = data }) //EventBus.$on('ReturningBrushedPointsIDs', this.UpdateBarChartFeatures ) EventBus.$on('ConfirmDataSet', this.fileNameSend) @@ -531,6 +577,10 @@ export default Vue.extend({ EventBus.$on('SendtheChangeinRangePos', this.threshold) EventBus.$on('SendtheChangeinRangeNeg', this.threshold) + EventBus.$on('addFeature', data => { this.featureAddRem = data }) + EventBus.$on('removeFeatures', data => { this.featureAddRem = data }) + EventBus.$on('addFeature', this.ManipulFeature) + EventBus.$on('removeFeatures', this.ManipulFeature) //Prevent double click to search for a word. document.addEventListener('mousedown', function (event) { diff --git a/frontend/src/components/Results.vue b/frontend/src/components/Results.vue index e6b7730..d47f637 100644 --- a/frontend/src/components/Results.vue +++ b/frontend/src/components/Results.vue @@ -152,7 +152,7 @@ export default { gridcolor: "rgb(230,230,230)", title: 'Step of the feature engineering', tickformat: '.0f', - range: [0, this.scoresMean.length + 10], + range: [0, this.scoresMean.length + 5], showgrid: true, showline: false, showticklabels: true, diff --git a/run.py b/run.py index 3a52fda..54e4978 100644 --- a/run.py +++ b/run.py @@ -20,7 +20,14 @@ from bayes_opt import BayesianOptimization from sklearn.model_selection import cross_validate from sklearn.model_selection import cross_val_predict from sklearn.preprocessing import OneHotEncoder +from sklearn.metrics import classification_report from sklearn.feature_selection import mutual_info_classif +from sklearn.feature_selection import SelectKBest +from sklearn.feature_selection import chi2 +from sklearn.feature_selection import RFE + +import eli5 +from eli5.sklearn import PermutationImportance from joblib import Parallel, delayed import multiprocessing @@ -52,24 +59,12 @@ def reset(): global keySpecInternal keySpecInternal = 1 - global dataSpacePointsIDs - dataSpacePointsIDs = [] - - global previousStateActive - previousStateActive = [] - global RANDOM_SEED RANDOM_SEED = 42 - global KNNModelsCount - global LRModelsCount - global keyData keyData = 0 - KNNModelsCount = 0 - LRModelsCount = 100 - global XData XData = [] global yData @@ -89,38 +84,18 @@ def reset(): global ClassifierIDsList ClassifierIDsList = '' - # Initializing models - - global resultsList - resultsList = [] - global RetrieveModelsList RetrieveModelsList = [] - global allParametersPerformancePerModel - allParametersPerformancePerModel = [] - global allParametersPerfCrossMutr allParametersPerfCrossMutr = [] - global HistoryPreservation - HistoryPreservation = [] - global all_classifiers all_classifiers = [] global crossValidation crossValidation = 5 - # models - global KNNModels - KNNModels = [] - global RFModels - RFModels = [] - - global results - results = [] - global resultsMetrics resultsMetrics = [] @@ -130,6 +105,9 @@ def reset(): global target_names target_names = [] + global keyFirstTime + keyFirstTime = True + global target_namesLoc target_namesLoc = [] return 'The reset was done!' @@ -198,9 +176,6 @@ def retrieveFileName(): global resultsList resultsList = [] - global allParametersPerformancePerModel - allParametersPerformancePerModel = [] - global allParametersPerfCrossMutr allParametersPerfCrossMutr = [] @@ -213,43 +188,6 @@ def retrieveFileName(): global crossValidation crossValidation = 5 - global scoring - scoring = {'accuracy': 'accuracy', 'precision_weighted': 'precision_weighted', 'recall_weighted': 'recall_weighted', 'f1_weighted': 'f1_weighted', 'roc_auc_ovo_weighted': 'roc_auc_ovo_weighted'} - - global loopFeatures - loopFeatures = 2 - - # models - global KNNModels - global SVCModels - global GausNBModels - global MLPModels - global LRModels - global LDAModels - global QDAModels - global RFModels - global ExtraTModels - global AdaBModels - global GradBModels - - KNNModels = [] - SVCModels = [] - GausNBModels = [] - MLPModels = [] - LRModels = [] - LDAModels = [] - QDAModels = [] - RFModels = [] - ExtraTModels = [] - AdaBModels = [] - GradBModels = [] - - global results - results = [] - - global resultsMetrics - resultsMetrics = [] - global parametersSelData parametersSelData = [] @@ -260,6 +198,9 @@ def retrieveFileName(): target_names = [] + global keyFirstTime + keyFirstTime = True + global target_namesLoc target_namesLoc = [] @@ -440,7 +381,7 @@ def dataSetSelection(): warnings.simplefilter('ignore') - executeModel() + executeModel([]) return 'Everything is okay' @@ -455,30 +396,90 @@ def create_global_function(): return np.mean(result['test_score']) # check this issue later because we are not getting the same results -def executeModel(): +def executeModel(exeCall): - create_global_function() + global keyFirstTime global estimator global yPredictProb global scores + global featureImportanceData + global XData + global XDataStored + + if (keyFirstTime): + create_global_function() + params = {"C": (0.0001, 10000), "gamma": (0.0001, 10000)} + svc_bayesopt = BayesianOptimization(estimator, params, random_state=RANDOM_SEED) + svc_bayesopt.maximize(init_points=120, n_iter=20, acq='ucb') + bestParams = svc_bayesopt.max['params'] + estimator = SVC(C=bestParams.get('C'), gamma=bestParams.get('gamma'), probability=True, random_state=RANDOM_SEED) + featureImportanceData = estimatorFeatureSelection(estimator) + keyFirstTime = False + XData = XDataStored.copy() + if (len(exeCall) != 0): + XData = XData.drop(XData.columns[exeCall], axis=1) - params = {"C": (0.0001, 10000), "gamma": (0.0001, 10000)} - svc_bayesopt = BayesianOptimization(estimator, params, random_state=RANDOM_SEED) - svc_bayesopt.maximize(init_points=120, n_iter=20, acq='ucb') - bestParams = svc_bayesopt.max['params'] - estimator = SVC(C=bestParams.get('C'), gamma=bestParams.get('gamma'), probability=True, random_state=RANDOM_SEED) estimator.fit(XData, yData) yPredict = estimator.predict(XData) yPredictProb = cross_val_predict(estimator, XData, yData, cv=crossValidation, method='predict_proba') - num_cores = 1 + num_cores = multiprocessing.cpu_count() inputsSc = ['accuracy','precision_macro','recall_macro'] flat_results = Parallel(n_jobs=num_cores)(delayed(solve)(estimator,XData,yData,crossValidation,item,index) for index, item in enumerate(inputsSc)) scores = [item for sublist in flat_results for item in sublist] - + return 'Everything Okay' +def estimatorFeatureSelection(clf): + + resultsFS = [] + permList = [] + PerFeatureAccuracy = [] + PerFeatureAccuracyAll = [] + + perm = PermutationImportance(clf, cv = None, refit = True, n_iter = 25).fit(XData, yData) + permList.append(perm.feature_importances_) + n_feats = XData.shape[1] + PerFeatureAccuracy = [] + for i in range(n_feats): + scores = model_selection.cross_val_score(clf, XData.values[:, i].reshape(-1, 1), yData, cv=crossValidation) + PerFeatureAccuracy.append(scores.mean()) + PerFeatureAccuracyAll.append(PerFeatureAccuracy) + + clf.fit(XData, yData) + yPredict = clf.predict(XData) + yPredict = np.nan_to_num(yPredict) + + perm_imp_eli5PD = pd.DataFrame(permList) + perm_imp_eli5PD = perm_imp_eli5PD.to_json() + + PerFeatureAccuracyPandas = pd.DataFrame(PerFeatureAccuracyAll) + PerFeatureAccuracyPandas = PerFeatureAccuracyPandas.to_json() + + bestfeatures = SelectKBest(score_func=chi2, k='all') + fit = bestfeatures.fit(XData,yData) + dfscores = pd.DataFrame(fit.scores_) + dfcolumns = pd.DataFrame(XData.columns) + featureScores = pd.concat([dfcolumns,dfscores],axis=1) + featureScores.columns = ['Specs','Score'] #naming the dataframe columns + featureScores = featureScores.to_json() + + resultsFS.append(featureScores) + resultsFS.append(perm_imp_eli5PD) + resultsFS.append(PerFeatureAccuracyPandas) + + return resultsFS + +@app.route('/data/sendFeatImp', methods=["GET", "POST"]) +def sendFeatureImportance(): + global featureImportanceData + + response = { + 'Importance': featureImportanceData + } + return jsonify(response) + def solve(sclf,XData,yData,crossValidation,scoringIn,loop): scoresLoc = [] temp = model_selection.cross_val_score(sclf, XData, yData, cv=crossValidation, scoring=scoringIn, n_jobs=-1) @@ -500,13 +501,13 @@ def sendFinalResults(): def Transformation(quadrant1, quadrant2, quadrant3, quadrant4, quadrant5): XDataNumeric = XData.select_dtypes(include='number') + columns = list(XDataNumeric) global packCorrTransformed packCorrTransformed = [] for count, i in enumerate(columns): - dicTransf = {} d={} @@ -1095,4 +1096,13 @@ def unique(list1): # check if exists in unique_list or not if x not in unique_list: unique_list.append(x) - return unique_list \ No newline at end of file + return unique_list + +@cross_origin(origin='localhost',headers=['Content-Type','Authorization']) +@app.route('/data/AddRemFun', methods=["GET", "POST"]) +def ManipulFeat(): + featureProcess = request.get_data().decode('utf8').replace("'", '"') + featureProcess = json.loads(featureProcess) + featureProcessExtract = featureProcess['featureAddRem'] + executeModel(featureProcessExtract) + return 'Okay' \ No newline at end of file