{ "cells": [ { "cell_type": "markdown", "id": "cell-0", "metadata": {}, "source": [ "# Example of a D-efficient RUM design using the RSC algorithm\n", "\n", "This notebook illustrates how to use **ChoiceDesign** with the **RSC (Relabelling, Swapping, Cycling)** optimisation algorithm. RSC extends the basic random swapping approach with two additional move types:\n", "\n", "- **Relabelling (R):** swaps all occurrences of two level values in a column.\n", "- **Swapping (S):** swaps the values of two individual rows in a column (same as the default algorithm).\n", "- **Cycling (C):** rotates all values in a column by one position.\n", "\n", "Each iteration, a column and a move type are chosen at random. The move is kept if it improves the D-error.\n", "\n", "The design setup \u2014 attributes, utility functions, and stopping criteria \u2014 is identical to the `d_efficient_rum_simple` example. The only difference is the `algorithm='rsc'` argument passed to `optimise()`.\n", "\n", "## Step 1: Load modules, define design parameters and set attributes" ] }, { "cell_type": "code", "execution_count": 1, "id": "cell-1", "metadata": {}, "outputs": [], "source": [ "from choicedesign.design import EffDesign\n", "from choicedesign.expressions import Attribute, Parameter" ] }, { "cell_type": "markdown", "id": "cell-2", "metadata": {}, "source": [ "The following lines define 2 alternatives with 4 attributes each, named $A$ to $D$:" ] }, { "cell_type": "code", "execution_count": 2, "id": "cell-3", "metadata": {}, "outputs": [], "source": [ "alt1_A = Attribute('alt1_A', [1, 2, 3])\n", "alt1_B = Attribute('alt1_B', [10, 15, 15.5])\n", "alt1_C = Attribute('alt1_C', [0, 3, 5])\n", "alt1_D = Attribute('alt1_D', [0, 1, 2])\n", "\n", "alt2_A = Attribute('alt2_A', [1, 2, 3])\n", "alt2_B = Attribute('alt2_B', [10, 15, 15.5])\n", "alt2_C = Attribute('alt2_C', [0, 3, 5])\n", "alt2_D = Attribute('alt2_D', [0, 1, 2])" ] }, { "cell_type": "markdown", "id": "cell-4", "metadata": {}, "source": [ "## Step 2: Construct the design object and generate the initial design matrix" ] }, { "cell_type": "code", "execution_count": 3, "id": "cell-5", "metadata": {}, "outputs": [], "source": [ "design = EffDesign(\n", " X=[alt1_A, alt1_B, alt1_C, alt1_D,\n", " alt2_A, alt2_B, alt2_C, alt2_D],\n", " ncs=18)" ] }, { "cell_type": "code", "execution_count": 4, "id": "cell-6", "metadata": {}, "outputs": [ { "data": { "application/vnd.microsoft.datawrangler.viewer.v0+json": { "columns": [ { "name": "index", "rawType": "int64", "type": "integer" }, { "name": "alt1_A", "rawType": "float64", "type": "float" }, { "name": "alt1_B", "rawType": "float64", "type": "float" }, { "name": "alt1_C", "rawType": "float64", "type": "float" }, { "name": "alt1_D", "rawType": "float64", "type": "float" }, { "name": "alt2_A", "rawType": "float64", "type": "float" }, { "name": "alt2_B", "rawType": "float64", "type": "float" }, { "name": "alt2_C", "rawType": "float64", "type": "float" }, { "name": "alt2_D", "rawType": "float64", "type": "float" } ], "ref": "fb2612e7-d6bb-45a0-b0df-98299b40ed06", "rows": [ [ "0", "1.0", "10.0", "5.0", "1.0", "2.0", "15.5", "5.0", "2.0" ], [ "1", "2.0", "15.0", "3.0", "2.0", "3.0", "15.0", "5.0", "0.0" ], [ "2", "3.0", "10.0", "5.0", "1.0", "2.0", "15.5", "5.0", "1.0" ], [ "3", "3.0", "15.5", "0.0", "1.0", "1.0", "10.0", "3.0", "2.0" ], [ "4", "1.0", "15.5", "3.0", "0.0", "1.0", "15.5", "5.0", "0.0" ], [ "5", "2.0", "15.0", "3.0", "2.0", "3.0", "15.0", "3.0", "0.0" ], [ "6", "2.0", "10.0", "3.0", "2.0", "2.0", "10.0", "0.0", "1.0" ], [ "7", "1.0", "10.0", "0.0", "0.0", "3.0", "15.5", "0.0", "0.0" ], [ "8", "3.0", "15.5", "5.0", "0.0", "1.0", "10.0", "5.0", "2.0" ], [ "9", "3.0", "10.0", "0.0", "2.0", "2.0", "15.0", "0.0", "0.0" ], [ "10", "1.0", "10.0", "0.0", "0.0", "1.0", "15.5", "0.0", "0.0" ], [ "11", "3.0", "15.0", "5.0", "1.0", "3.0", "10.0", "3.0", "1.0" ], [ "12", "2.0", "15.0", "5.0", "2.0", "1.0", "15.0", "3.0", "1.0" ], [ "13", "1.0", "15.5", "3.0", "2.0", "3.0", "15.0", "0.0", "2.0" ], [ "14", "2.0", "15.5", "3.0", "0.0", "3.0", "15.5", "0.0", "1.0" ], [ "15", "2.0", "15.0", "5.0", "1.0", "2.0", "15.0", "5.0", "2.0" ], [ "16", "3.0", "15.5", "0.0", "1.0", "2.0", "10.0", "3.0", "2.0" ], [ "17", "1.0", "15.0", "0.0", "0.0", "1.0", "10.0", "3.0", "1.0" ] ], "shape": { "columns": 8, "rows": 18 } }, "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
alt1_Aalt1_Balt1_Calt1_Dalt2_Aalt2_Balt2_Calt2_D
01.010.05.01.02.015.55.02.0
12.015.03.02.03.015.05.00.0
23.010.05.01.02.015.55.01.0
33.015.50.01.01.010.03.02.0
41.015.53.00.01.015.55.00.0
52.015.03.02.03.015.03.00.0
62.010.03.02.02.010.00.01.0
71.010.00.00.03.015.50.00.0
83.015.55.00.01.010.05.02.0
93.010.00.02.02.015.00.00.0
101.010.00.00.01.015.50.00.0
113.015.05.01.03.010.03.01.0
122.015.05.02.01.015.03.01.0
131.015.53.02.03.015.00.02.0
142.015.53.00.03.015.50.01.0
152.015.05.01.02.015.05.02.0
163.015.50.01.02.010.03.02.0
171.015.00.00.01.010.03.01.0
\n", "
" ], "text/plain": [ " alt1_A alt1_B alt1_C alt1_D alt2_A alt2_B alt2_C alt2_D\n", "0 1.0 10.0 5.0 1.0 2.0 15.5 5.0 2.0\n", "1 2.0 15.0 3.0 2.0 3.0 15.0 5.0 0.0\n", "2 3.0 10.0 5.0 1.0 2.0 15.5 5.0 1.0\n", "3 3.0 15.5 0.0 1.0 1.0 10.0 3.0 2.0\n", "4 1.0 15.5 3.0 0.0 1.0 15.5 5.0 0.0\n", "5 2.0 15.0 3.0 2.0 3.0 15.0 3.0 0.0\n", "6 2.0 10.0 3.0 2.0 2.0 10.0 0.0 1.0\n", "7 1.0 10.0 0.0 0.0 3.0 15.5 0.0 0.0\n", "8 3.0 15.5 5.0 0.0 1.0 10.0 5.0 2.0\n", "9 3.0 10.0 0.0 2.0 2.0 15.0 0.0 0.0\n", "10 1.0 10.0 0.0 0.0 1.0 15.5 0.0 0.0\n", "11 3.0 15.0 5.0 1.0 3.0 10.0 3.0 1.0\n", "12 2.0 15.0 5.0 2.0 1.0 15.0 3.0 1.0\n", "13 1.0 15.5 3.0 2.0 3.0 15.0 0.0 2.0\n", "14 2.0 15.5 3.0 0.0 3.0 15.5 0.0 1.0\n", "15 2.0 15.0 5.0 1.0 2.0 15.0 5.0 2.0\n", "16 3.0 15.5 0.0 1.0 2.0 10.0 3.0 2.0\n", "17 1.0 15.0 0.0 0.0 1.0 10.0 3.0 1.0" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "init_design = design.gen_initdesign(seed=42)\n", "init_design" ] }, { "cell_type": "markdown", "id": "cell-7", "metadata": {}, "source": [ "## Step 3: Define the utility functions" ] }, { "cell_type": "code", "execution_count": 5, "id": "cell-8", "metadata": {}, "outputs": [], "source": [ "beta_A = Parameter('beta_A', -0.1)\n", "beta_B = Parameter('beta_B', -0.02)\n", "beta_C = Parameter('beta_C', 0.1)\n", "beta_D = Parameter('beta_D', 0.15)" ] }, { "cell_type": "code", "execution_count": 6, "id": "cell-9", "metadata": {}, "outputs": [], "source": [ "V1 = beta_A * alt1_A + beta_B * alt1_B + beta_C * alt1_C + beta_D * alt1_D\n", "V2 = beta_A * alt2_A + beta_B * alt2_B + beta_C * alt2_C + beta_D * alt2_D\n", "\n", "V = {1: V1, 2: V2}" ] }, { "cell_type": "markdown", "id": "cell-10", "metadata": {}, "source": [ "## Step 4: Optimise using the RSC algorithm\n", "\n", "The `algorithm='rsc'` argument selects the RSC algorithm. All other arguments are identical to the default `'swap'` algorithm. The optimisation runs for 1 minute:" ] }, { "cell_type": "code", "execution_count": 7, "id": "cell-11", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Evaluating initial design\n", "Optimization complete 0:00:59 / D-error: 0.033939\n", "Elapsed time: 0:01:00\n", "D-error of initial design: 0.080551\n", "D-error of last stored design: 0.033939\n", "Utility Balance ratio: 94.88 %\n", "Algorithm iterations: 148538\n", "\n" ] } ], "source": [ "optimal_design, init_perf, final_perf, final_iter, ubalance_ratio = design.optimise(\n", " init_design=init_design,\n", " V=V,\n", " model='mnl',\n", " algorithm='rsc',\n", " time_lim=1,\n", " verbose=True\n", ")" ] }, { "cell_type": "markdown", "id": "cell-12", "metadata": {}, "source": [ "## Step 5: Block the design" ] }, { "cell_type": "code", "execution_count": 8, "id": "cell-13", "metadata": {}, "outputs": [ { "data": { "application/vnd.microsoft.datawrangler.viewer.v0+json": { "columns": [ { "name": "index", "rawType": "int64", "type": "integer" }, { "name": "CS", "rawType": "float64", "type": "float" }, { "name": "alt1_A", "rawType": "float64", "type": "float" }, { "name": "alt1_B", "rawType": "float64", "type": "float" }, { "name": "alt1_C", "rawType": "float64", "type": "float" }, { "name": "alt1_D", "rawType": "float64", "type": "float" }, { "name": "alt2_A", "rawType": "float64", "type": "float" }, { "name": "alt2_B", "rawType": "float64", "type": "float" }, { "name": "alt2_C", "rawType": "float64", "type": "float" }, { "name": "alt2_D", "rawType": "float64", "type": "float" }, { "name": "Block", "rawType": "int64", "type": "integer" } ], "ref": "a3f2f157-fca8-473d-b478-b5d556f94e02", "rows": [ [ "0", "1.0", "1.0", "10.0", "5.0", "1.0", "3.0", "15.5", "0.0", "1.0", "2" ], [ "1", "2.0", "2.0", "15.5", "3.0", "2.0", "2.0", "10.0", "3.0", "0.0", "3" ], [ "2", "3.0", "3.0", "15.0", "5.0", "0.0", "1.0", "15.0", "0.0", "2.0", "3" ], [ "3", "4.0", "1.0", "15.5", "0.0", "1.0", "3.0", "10.0", "5.0", "1.0", "1" ], [ "4", "5.0", "3.0", "15.0", "3.0", "0.0", "1.0", "15.0", "3.0", "2.0", "1" ], [ "5", "6.0", "2.0", "10.0", "0.0", "2.0", "2.0", "15.5", "5.0", "0.0", "3" ], [ "6", "7.0", "2.0", "15.0", "5.0", "2.0", "2.0", "15.0", "0.0", "0.0", "1" ], [ "7", "8.0", "1.0", "10.0", "3.0", "2.0", "3.0", "15.5", "3.0", "0.0", "2" ], [ "8", "9.0", "3.0", "10.0", "3.0", "0.0", "1.0", "15.5", "3.0", "2.0", "2" ], [ "9", "10.0", "3.0", "10.0", "0.0", "2.0", "1.0", "15.5", "5.0", "0.0", "1" ], [ "10", "11.0", "1.0", "15.0", "3.0", "0.0", "3.0", "15.0", "3.0", "2.0", "3" ], [ "11", "12.0", "3.0", "15.5", "5.0", "1.0", "1.0", "10.0", "0.0", "1.0", "1" ], [ "12", "13.0", "3.0", "15.5", "3.0", "2.0", "1.0", "10.0", "3.0", "0.0", "3" ], [ "13", "14.0", "1.0", "15.0", "5.0", "1.0", "3.0", "15.0", "0.0", "1.0", "2" ], [ "14", "15.0", "2.0", "10.0", "0.0", "0.0", "2.0", "15.5", "5.0", "2.0", "2" ], [ "15", "16.0", "2.0", "15.0", "5.0", "0.0", "2.0", "15.0", "0.0", "2.0", "2" ], [ "16", "17.0", "2.0", "15.5", "0.0", "1.0", "2.0", "10.0", "5.0", "1.0", "3" ], [ "17", "18.0", "1.0", "15.5", "0.0", "1.0", "3.0", "10.0", "5.0", "1.0", "1" ] ], "shape": { "columns": 10, "rows": 18 } }, "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
CSalt1_Aalt1_Balt1_Calt1_Dalt2_Aalt2_Balt2_Calt2_DBlock
01.01.010.05.01.03.015.50.01.02
12.02.015.53.02.02.010.03.00.03
23.03.015.05.00.01.015.00.02.03
34.01.015.50.01.03.010.05.01.01
45.03.015.03.00.01.015.03.02.01
56.02.010.00.02.02.015.55.00.03
67.02.015.05.02.02.015.00.00.01
78.01.010.03.02.03.015.53.00.02
89.03.010.03.00.01.015.53.02.02
910.03.010.00.02.01.015.55.00.01
1011.01.015.03.00.03.015.03.02.03
1112.03.015.55.01.01.010.00.01.01
1213.03.015.53.02.01.010.03.00.03
1314.01.015.05.01.03.015.00.01.02
1415.02.010.00.00.02.015.55.02.02
1516.02.015.05.00.02.015.00.02.02
1617.02.015.50.01.02.010.05.01.03
1718.01.015.50.01.03.010.05.01.01
\n", "
" ], "text/plain": [ " CS alt1_A alt1_B alt1_C alt1_D alt2_A alt2_B alt2_C alt2_D \\\n", "0 1.0 1.0 10.0 5.0 1.0 3.0 15.5 0.0 1.0 \n", "1 2.0 2.0 15.5 3.0 2.0 2.0 10.0 3.0 0.0 \n", "2 3.0 3.0 15.0 5.0 0.0 1.0 15.0 0.0 2.0 \n", "3 4.0 1.0 15.5 0.0 1.0 3.0 10.0 5.0 1.0 \n", "4 5.0 3.0 15.0 3.0 0.0 1.0 15.0 3.0 2.0 \n", "5 6.0 2.0 10.0 0.0 2.0 2.0 15.5 5.0 0.0 \n", "6 7.0 2.0 15.0 5.0 2.0 2.0 15.0 0.0 0.0 \n", "7 8.0 1.0 10.0 3.0 2.0 3.0 15.5 3.0 0.0 \n", "8 9.0 3.0 10.0 3.0 0.0 1.0 15.5 3.0 2.0 \n", "9 10.0 3.0 10.0 0.0 2.0 1.0 15.5 5.0 0.0 \n", "10 11.0 1.0 15.0 3.0 0.0 3.0 15.0 3.0 2.0 \n", "11 12.0 3.0 15.5 5.0 1.0 1.0 10.0 0.0 1.0 \n", "12 13.0 3.0 15.5 3.0 2.0 1.0 10.0 3.0 0.0 \n", "13 14.0 1.0 15.0 5.0 1.0 3.0 15.0 0.0 1.0 \n", "14 15.0 2.0 10.0 0.0 0.0 2.0 15.5 5.0 2.0 \n", "15 16.0 2.0 15.0 5.0 0.0 2.0 15.0 0.0 2.0 \n", "16 17.0 2.0 15.5 0.0 1.0 2.0 10.0 5.0 1.0 \n", "17 18.0 1.0 15.5 0.0 1.0 3.0 10.0 5.0 1.0 \n", "\n", " Block \n", "0 2 \n", "1 3 \n", "2 3 \n", "3 1 \n", "4 1 \n", "5 3 \n", "6 1 \n", "7 2 \n", "8 2 \n", "9 1 \n", "10 3 \n", "11 1 \n", "12 3 \n", "13 2 \n", "14 2 \n", "15 2 \n", "16 3 \n", "17 1 " ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "optimal_design_blocked, corr_history = design.gen_blocks(optimal_design, n_blocks=3)\n", "optimal_design_blocked" ] }, { "cell_type": "markdown", "id": "cell-14", "metadata": {}, "source": [ "## (Optional) Evaluate the design" ] }, { "cell_type": "code", "execution_count": 9, "id": "cell-15", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.033939284712415994 94.87569390189945\n" ] } ], "source": [ "perf, ubalance = design.evaluate(optimal_design, V, model='mnl')\n", "print(perf, ubalance)" ] }, { "cell_type": "markdown", "id": "cell-16", "metadata": {}, "source": [ "## References\n\n[1] Quan, W., Rose, J. M., Collins, A. T., & Bliemer, M. C. (2011). A comparison of algorithms for generating efficient choice experiments." ] } ], "metadata": { "kernelspec": { "display_name": "choicedesign-oSBhddzi-py3.13", "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.13.1" } }, "nbformat": 4, "nbformat_minor": 5 }