Created
May 30, 2020 15:23
-
-
Save pilifjed/ae12c3c8f47e36a1121acb166dcc6037 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"execution_count": 269, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"from pymoo.algorithms.nsga3 import NSGA3\n", | |
"from pymoo.factory import get_problem, get_reference_directions\n", | |
"from pymoo.optimize import minimize\n", | |
"from pymoo.visualization.scatter import Scatter\n", | |
"from pymoo.model.crossover import Crossover\n", | |
"from pymoo.model.mutation import Mutation\n", | |
"from pymoo.operators.repair.out_of_bounds_repair import repair_out_of_bounds" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 270, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"from pymoo.operators.crossover.simulated_binary_crossover import SimulatedBinaryCrossover\n", | |
"from pymoo.operators.mutation.polynomial_mutation import PolynomialMutation\n", | |
"from pymoo.operators.sampling.random_sampling import BinaryRandomSampling, FloatRandomSampling" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 295, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"class BNSGAMutation(Mutation):\n", | |
" def __init__(self, eta, prob=None):\n", | |
" super().__init__()\n", | |
" self.eta = float(eta)\n", | |
"\n", | |
" if prob is not None:\n", | |
" self.prob = float(prob)\n", | |
" else:\n", | |
" self.prob = None\n", | |
"\n", | |
" def _do(self, problem, X, **kwargs):\n", | |
"\n", | |
" X = X.astype(np.float)\n", | |
" Y = np.full(X.shape, np.inf)\n", | |
"\n", | |
" if self.prob is None:\n", | |
" self.prob = 1.0 / 4 #problem.n_var\n", | |
"\n", | |
" Y = np.zeros(X.shape).astype(np.bool)\n", | |
" Y[:, :] = X\n", | |
" N = int(np.round(X.shape[0]*self.prob))\n", | |
" to_mutate = np.random.choice(range(X.shape[0]), N, replace=False)\n", | |
" mutated_samples = np.zeros(shape=X.shape[0]).astype(np.bool)\n", | |
" mutated_samples[to_mutate] = True\n", | |
" mutation_mask = (np.random.random(size=X[mutated_samples, :].shape) < problem.n_var*self.eta).astype(np.bool)\n", | |
"\n", | |
" Y[mutated_samples] ^= mutation_mask\n", | |
" return Y\n", | |
"\n", | |
"\n", | |
"class BNSGACrossover(Crossover):\n", | |
" def __init__(self, eta, n_offsprings=2, prob_per_variable=0.5, **kwargs):\n", | |
" super().__init__(2, n_offsprings, **kwargs)\n", | |
" self.eta = float(eta)\n", | |
" self.prob_per_variable = prob_per_variable\n", | |
"\n", | |
" def _do(self, problem, X, **kwargs):\n", | |
"\n", | |
" X = X.astype(np.float)\n", | |
" _, n_matings, n_var = X.shape\n", | |
" \n", | |
" \n", | |
" # take the parents as _template\n", | |
" c = np.copy(X)\n", | |
" c = c.astype(np.bool)\n", | |
"\n", | |
" \n", | |
" # copy the positions where the crossover was done\n", | |
" c[0] = c[0] & c[1]\n", | |
" c[1] = c[0] | c[1]\n", | |
"\n", | |
" return c" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 308, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import numpy as np\n", | |
"from pymoo.util.misc import stack\n", | |
"from pymoo.model.problem import Problem\n", | |
"\n", | |
"class MockFeatureSelectionProblem(Problem):\n", | |
"\n", | |
" def __init__(self):\n", | |
" super().__init__(n_var=5,\n", | |
" n_obj=1,\n", | |
" n_constr=0,\n", | |
" xl=np.zeros(5),\n", | |
" xu=np.ones(5))\n", | |
"\n", | |
" def _evaluate(self, x, out, *args, **kwargs):\n", | |
" # out of n inputs only 2 are used for fun result\n", | |
" real_feature_importances = np.array([-1,-1,1,-1,1])\n", | |
" f = np.sum(x*real_feature_importances*(-1), axis=1)\n", | |
" out[\"F\"] = f\n", | |
" #out[\"G\"] = np.column_stack([g1, g2])\n", | |
"\n", | |
"problem = MyProblem()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 309, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"image/png": "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\n", | |
"text/plain": [ | |
"<Figure size 576x432 with 1 Axes>" | |
] | |
}, | |
"metadata": { | |
"needs_background": "light" | |
}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"# create the reference directions to be used for the optimization\n", | |
"ref_dirs = get_reference_directions(\"das-dennis\", 1, n_partitions=10)\n", | |
"\n", | |
"# create the algorithm object\n", | |
"algorithm = NSGA3(pop_size=100,\n", | |
" ref_dirs=ref_dirs,\n", | |
" sampling=BinaryRandomSampling(),\n", | |
" crossover=BNSGACrossover(eta=30, prob=1.0),\n", | |
" mutation=BNSGAMutation(eta=1./10, prob=None))\n", | |
"\n", | |
"# execute the optimization\n", | |
"res = minimize(MockFeatureSelectionProblem(),\n", | |
" algorithm,\n", | |
" seed=1,\n", | |
" termination=('n_gen', 600))\n", | |
"\n", | |
"Scatter().add(res.F).show()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 310, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"array([False, False, True, False, True])" | |
] | |
}, | |
"execution_count": 310, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"res.X" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 311, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"array([-2])" | |
] | |
}, | |
"execution_count": 311, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"res.F" | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.6.9" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 4 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment