Page 1 of 1

NGENE and Survey Engine

PostPosted: Fri Jun 20, 2025 7:27 am
by Joy_Lawrence
Good Afternoon,
I have a subscription of both NGENE and Survey Engine. Ideally I wanted to design my DCE in ngene first and then import the xl-template to Survey engine. Please look at my ngene commands below:

design
;alts = opt1*, opt2*
;eff = (mnl, d)
;alg = swap
;rows = 42
;block = 6
;cond:
if(opt1.x1= 0, opt1.x2=[0,1]),
if(opt1.x1= 2, opt1.x2=[1,2]),
if(opt1.x1= 1, opt1.x2=[0,1,2]),
if(opt2.x1= 0, opt2.x2=[0,1]),
if(opt2.x1= 2, opt2.x2=[1,2]),
if(opt2.x1= 1, opt2.x2=[0,1,2])

;model:
U(opt1) = b1.dummy [0.0001|0.0001] * x1[1,2,0] ? speed (low,high, ultrafast)
+ b2.dummy[-0.0001|-0.0001] * x2[1,2,0] ? linear variable of price where 0(25pence/kWh), 1( 57 pence/kWh), 2(80 pence/kWh)
+ b3.dummy[0|0] * x3[1,2,0] ? locality (categorical variable with no ordering)
+ b4.dummy[0|0|0] * x4[1,2,3,0] ? types of journey services (categorical variable with no ordering)
+ b5.dummy[0.0001|0.0001] * x5[1,2,0] ? type of fuel used (ordered in terms of clean-ness)
+ b6.dummy[0|0] * x6[1,2,0] ? types of loans and subscriptions (categorical variable with no ordering)
+ b7.dummy[-0.0001] * x7[1,0] ? late-fee, yes = 1, no= 0 (if yes, then lesser utility)
/
U(opt2) = b1 * x1
+ b2 * x2
+ b3 * x3
+ b4 * x4
+ b5 * x5
+ b6 * x6
+ b7 * x7
$

Q-1) I have an unlabeled DCE design with two alt. and 7 attributes with 2, 3 and 4 levels in each.
Could you kindly check if the code, and rows seem correct to you ?

Q-2) When I run this without the +ve or -ve priors , but only the few constraints then it gives me a d-error of 0.1 , but the moment I put these few near-zero priors based on how I think the attributes of those levels increasing up may impact positively or negatively to the overall utility function , then NGENE gives me the following error :
*****Warning:
An attempt will be made to balance the frequency of each level in attributes affected by constraints, however complete balance might not be possible.

A valid initial random design could not be generated after approximately 10 seconds. In this time, of the 88599 attempts made, there were 0 row repetitions, 112 alternative repetitions, and 88487 cases of dominance. There are a number of possible causes for this, including the specification of too many constraints, not having enough attributes or attribute levels for the number of rows required, and the use of too many scenario attributes. A design may yet be found, and the search will continue for 10 minutes. Alternatively, you can stop the run and alter the syntax.
Error: Aborting the run. After approximately 10 minutes, an initial random design was not found.
Finished, at 9:42:54 PM, 6/19/2025 ******

Can you suggest me what other ways I can try to attain a good pilot design with an Unlabelled DCE that ideally needs non-zero priors , for my first 100 sample?

Q-3) If i try to design the same , directly on Survey Engine instead of NGENE and use their ''generate using ngene'' option then in the ''layout'' section its ordered differently (please check the attached image)
[img][https://drive.google.com/file/d/1dXRMrpdu-4P7rBVC6ntIHsh_6ZLSlt8m/view?usp=sharing/img]
In SE , as you can see the priors are set alongside 0 and 1 for the first attribute called Speed and unlike NGENE its not attached with 1,2 levels where 0 is the base. Does it mean in Svy. Engine the sign of the priors would alter and become the opposite if (in this case ) 2 becomes the base ?
All I want is to generate a design whose design matrix ultimately is the same whether generated in SE through NGENE or, designed in NGENE and imported to Svy engine.

Q-4) In the same image for the second attribute of Price (or cost, which will ultimately help us finding WTP) , which was a continuous variable, I ticked on the 'linear' option in Svy. Engine so it transformed them to effects coding and therefore only one prior is to be set there. Hope I did it correctly?
But in NGENE (code above ) I had to take two priors if I use dummy 0,1,2 codes for 25,57,80£
These inconsistencies are making me confused.
Your guidance will be really helpful. Thanks

Re: NGENE and Survey Engine

PostPosted: Sat Jun 21, 2025 5:43 pm
by Michiel Bliemer
Q1) Yes that looks good and the number of rows is reasonable. You could possibly go to 48 rows to make it divisible by 2, 3, and 4 levels, which would allow attribute level balance, but your constraints may make it difficult to achieve this. It is not a must.

Q2) For the four attributes for which you have non-zero priors, Ngene will try to avoid dominance. Using the default swapping algorithm, which is a column-based algorithm, it is very difficult to find 42 rows without any dominance. Since you have attributes without a clear preference order, dominance is likely not a major issue in your design, so one solution is to indeed set all priors to zero. If you want non-zero priors, then you need to use the modified Federov algorithm, i.e., ;alg = mfederov. In that case, you will need to rewrite your conditional constraints into reject constraints as I have done below. This script will generate a design. Note that the mfederov algorithm does not aim for attribute level balance, but since you have dummy coded all attributes the design should have reasonable attribute level balance by default, so not a real issue in your case. Note that the mfederov algorithm requires a much longer run time as it replaces each choice task with a choice task from a candidate set (default size 2000) and re-evaluates the design.

Code: Select all
design
;alts = opt1*, opt2*
;eff = (mnl, d)
;alg = mfederov
;rows = 42
;block = 6
;reject:
opt1.x1 = 0 and opt1.x2 = 2,
opt1.x2 = 2 and opt1.x2 = 0,
opt2.x1 = 0 and opt2.x2 = 2,
opt2.x2 = 2 and opt2.x2 = 0

;model:
U(opt1) = b1.dummy [0.0001|0.0001] * x1[1,2,0] ? speed (low,high, ultrafast)
+ b2.dummy[-0.0001|-0.0001] * x2[1,2,0] ? linear variable of price where 0(25pence/kWh), 1( 57 pence/kWh), 2(80 pence/kWh)
+ b3.dummy[0|0] * x3[1,2,0] ? locality (categorical variable with no ordering)
+ b4.dummy[0|0|0] * x4[1,2,3,0] ? types of journey services (categorical variable with no ordering)
+ b5.dummy[0.0001|0.0001] * x5[1,2,0] ? type of fuel used (ordered in terms of clean-ness)
+ b6.dummy[0|0] * x6[1,2,0] ? types of loans and subscriptions (categorical variable with no ordering)
+ b7.dummy[-0.0001] * x7[1,0] ? late-fee, yes = 1, no= 0 (if yes, then lesser utility)
/
U(opt2) = b1 * x1
+ b2 * x2
+ b3 * x3
+ b4 * x4
+ b5 * x5
+ b6 * x6
+ b7 * x7
$


Q3) The last level is always the reference level. You can use any numbering system you want. If you want the same as SurveyEngine, you would indeed change the priors. So:

+ b2.dummy[-0.0001|-0.0002] * x2[1,2,0] ? linear variable of price where 0(25pence/kWh), 1( 57 pence/kWh), 2(80 pence/kWh)
Here, it is indicated that level 1 is less preferred than level 0 (because of higher price) and level 2 is less preferred than level 1 (because of higher price)

This is the same as:
+ b2.dummy[0.0002|0.0001] * x2[0,1,2] ? linear variable of price where 0(25pence/kWh), 1( 57 pence/kWh), 2(80 pence/kWh)
Here, it is indicated the level 0 is most preferred (because of lowest price) and level 2 is least preferred.

Q4) If you use dummy (or effects) coding in Ngene or SurveyEngine, then with 3 levels you need to specify 2 priors. If you do not use dummy (or effects) coding, then it becomes a linear effect and you only specify one prior. This is the same in SurveyEngine and Ngene, there is no inconsistency.
So you could specify:

+ b2.dummy[0|0] * x2[1,2,0] ? linear variable of price where 0(25pence/kWh), 1( 57 pence/kWh), 2(80 pence/kWh)

Or you could specify:

+ b2[0] * x2[25,57,80] ? linear variable of price in pence/kWh

In the latter case, you must use the actual numerical attribute levels. For a pilot study with (near) zero priors, I could recommend dummy coding all attributes. When you estimate the model, you can specify cost as a numerical attribute with a single parameter (or you can estimate dummy coding, you can choose).

Michiel

Re: NGENE and Survey Engine

PostPosted: Sun Jun 22, 2025 8:28 am
by Joy_Lawrence
Thank you for the response. It indeed cleared all my listed doubts.
I have a question though, because now I am faced with the decision to choose my design for pilot between these 3 options ( and I am stating the problem in its respective bracket):
a) default swap algorithm with zero priors and those constraints of mine (generates design, gives a d.error of 0.1, but if we take zero priors there might arise the issue of dominance in the choice tasks for some of those non-zero attributes, is it not??)
b) default swap with near-zero priors and all those constraints with 42 or 48 rows (still cannot generate any design)
c) m-fed alogorithm with 42 rows (took time and resulted in 0.17 as d-error > 0.10, which I hope is acceptable??? but are there any disadvantages of using it over default swapping? You mentioned it will have attribute balance by default, but how about dominance ? )

Q- Unrelated question: how to plug in a false-ish extra choice task with a dominant alternative choice task (which will not be counted later in estimation) to test if people are paying attention, when I am actually taking the entire generated design through the xl-sheet template to Svy. Engine and blocking them up to 6 blocks?

Re: NGENE and Survey Engine

PostPosted: Mon Jun 23, 2025 12:08 am
by Michiel Bliemer
Option (b) will not work with non-zero priors because there is too much dominance.
Option (a) and option (c) would both be fine. There is not really an issue with dominance as I will explain below. I would use option (a) with zero priors for a pilot study, and I would use option (c) with non-zero priors for the main study. You can consider 42 or 48 rows in each of the options.

Regarding dominance, consider the two options below:
Laptop A: Apple, 32GB memory, 4 TB harddisk
Laptop B: Dell, 16GB memory, 2 TB harddisk

In the above example, more memory and large harddisk are clearly preferred, so there is an ordering for these attributes. But for brand there is no such ordering, it is a nominal variable. So even if Laptop A seems dominant on memory and harddisk, we cannot say that Laptop A is dominant because some people will prefer a Windows laptop and choose Dell instead of laptop running MacOS.

To answer your last question: You simply manually put such a choice task into each block when you transfer the design to SurveyEngine. How best to do this, I will need to refer to SurveyEngine (they also have a forum).

Michiel

Re: NGENE and Survey Engine

PostPosted: Tue Jun 24, 2025 5:23 am
by Joy_Lawrence
Thank you, that was very helpful. I am trying to look for resources to add such an extra choice task in SEngine.
As I was checking the ''dictionary''section of survey engine , I noticed that all my variables are coded as 1, 2, 3, 4.... and ''Yes'' is coded as 2 and ''no'' as 1. Even for those choice attributes coding, its coded differently from NGENE. My NGENE design, (as you can see in my codes above) it was 1 and 0 respectively or 0, 1, 2, 3.... etc.
Will this have any problem because 1 in SE does not mean the same as 1 in NGENE design code ? And How to alleviate if yes?

Re: NGENE and Survey Engine

PostPosted: Wed Jun 25, 2025 2:32 pm
by Michiel Bliemer
You can choose any coding in Ngene, so if the survey instrument uses 1,2,3,.. etc then you can simply use 1,2,3,... in Ngene too. You do not have to start with 0 in Ngene, you can use any labelling.
Even if the coding is different, when you transfer the design to the survey instrument you can simply relabel the levels in Excel, e.g. 0 becomes a 1, 1 becomes a 2, etc.

As far as I can see, SurveyEngine uses design coding 0,1,2, etc for the underlying experimental design, so you would need to use this coding. After data collection, SurveyEngine may provide the data as 1,2,3, but as far as I am aware, the design uses design coding. So there may be an internal conversion in SurveyEngine from design to data (essentially +1). But please check with SurveyEngine.

Michiel

Re: NGENE and Survey Engine

PostPosted: Sat Jun 28, 2025 3:31 am
by Joy_Lawrence
Thank you, I have checked with Svy Engine, they said it should not be a problem, just to treat the variable codes later during estimation phase matching with how its coded in dictionary.
We have a doubt with the three constraints in my code, where I stated that if the speed is slow then price should be 25 or 57 and not the highest level 80, where the 3 levels are 0(25pence/kWh), 1( 57 pence/kWh), 2(80 pence/kWh). Similarly for ultrafast we constrained that it could be 57 or 80 but not the lowest 25....And one constraint I put for the middle ''fast'' is that it can take any value 25/57/80. Without putting this constraint on ''fast'' the other two constraints on slow and ultrafast were not showing in the choice tasks.
So now this has given rise to an issue where there were some choice tasks where Slow has a price of 57 but Fast has a price of 25 or Ultrafast has a price of 57 and Fast has price 80. (Cannot ideally happen)

Therefore is it possible to put couple of constraints which rather says : Whatever be the price of Slow (25/57/80) , the other alternative ie. fast / rapid can be equal or more than that value ONLY in a choice task? Similarly if its a comparision between Fast and Ultrafast, then they could take any values but Price of Ultrafast needs to be higher than that of Fast alternative in every choice task. How to frame such a constraint in NGENE?

Re: NGENE and Survey Engine

PostPosted: Sat Jun 28, 2025 10:07 am
by Michiel Bliemer
I am not sure that I understand. You specified the constraints below:

;cond:
if(opt1.x1= 0, opt1.x2=[0,1]),
if(opt1.x1= 2, opt1.x2=[1,2]),
if(opt1.x1= 1, opt1.x2=[0,1,2]),
if(opt2.x1= 0, opt2.x2=[0,1]),
if(opt2.x1= 2, opt2.x2=[1,2]),
if(opt2.x1= 1, opt2.x2=[0,1,2])

These two constraints are not really constraints, so can be omitted:
if(opt1.x1= 1, opt1.x2=[0,1,2]),
if(opt2.x1= 1, opt2.x2=[0,1,2])

But you are saying that when you omit them, the other constraints no longer 'work'? When I run the script, it works fine: whenever x1=0 then x2 is never 2, and when x1=2 then x2 is never 0.

Another way of writing these constraints is:
if(opt1.x1= 0, opt1.x2<2),
if(opt1.x1= 2, opt1.x2>0),
if(opt2.x1= 0, opt2.x2<2),
if(opt2.x1= 2, opt2.x2>0)

Or:
if(opt1.x1= 0, opt1.x2<=1),
if(opt1.x1= 2, opt1.x2>=1),
if(opt2.x1= 0, opt2.x2<=1),
if(opt2.x1= 2, opt2.x2>=1)

The same constraints can also be formulated as reject constraints:
;reject:
opt1.x1 = 0 and opt1.x2 = 2,
opt1.x2 = 2 and opt1.x2 = 0,
opt2.x1 = 0 and opt2.x2 = 2,
opt2.x2 = 2 and opt2.x2 = 0

Reject constraints have the most flexibility, so perhaps the constraints you mention can be formulated using something like (probably not exactly what you want but it hopefully gives you can idea):
reject:
opt1.x1 >= opt2.x1 and opt1.x2 < opt2.x2

Michiel