π MaxDiff Analysis
Definition
MaxDiff is an approach for obtaining preference/importance scores for multiple items (brand preferences, brand images, product features, advertising claims, etc.). Although MaxDiff shares much in common with conjoint analysis, it is easier to use and applicable to a wider variety of research situations. MaxDiff is also known as "best-worst scaling."
This article contains an example MaxDiff data file with a portfolio including two methods to rank the different product/service offerings based on:
- Paired Preference Test (Basic)
- Preference Share (Advanced)
This relates to the article in the AskiaDesign section of the our Help Centre on how to script a MaxDiff example.
Paired Preference Test
We create a tab definition with 3 calculations: n, % and paired preference:
We add the "Vote" loop in rows (for statistical tests purposes) and the sub-question "rec_items", which contains the attributes in the column (in our example with 55 attributes).
Now set-up a transposed table as below - this transposition makes the % down effectively appear as % across. Why do we do this?
We are going to use the Paired preference calculation which is basically a colsig test between the most and least chosen responses and returns the t-test value between them. This calculation must be based on % down. However, it's more useful for us to see % across saying least/most.
When you run your table, you obtain this result (see MaxDiffExample1):
The biggest difference between most and least favoured attribute/statement is represented by a blue row and a higher paired preference value. These would be the attributes to concentrate on improving in the grocery store example above. The least important are the red rows with a lower paired preference value.
Preference Share
However, to rank the product/service items, you could use a more advanced analyse with the Preference share approach. Based on the expected 'utility' of each product/service offering when a respondent selects the most/least statements, this allows you to represent the importance of each attribute in %.
To do it in AskiaAnalyse, we propose you two solutions:
- Using an aggregated script.
Firstly, to prepare the different calculation steps, we recommend you include some coded variables into a "Vote" loop in AskiaDesign (see Maxdiff methodology in Design / Additional info).
The attributes representing the product/service offering will be stored into the "Rec_Items" ("Vote" sub-question ) and the different calculation steps will be represented into the "Vote" loop items:
# | Steps | Description | Formula |
A | Recode_most | Product / service offering most selected |
cf Design |
B | Recode_least | Product / service offering least selected |
cf Design |
C |
Recode_Not_selected | Product / service offering proposed but not selected |
cf Design |
D | Recode_Offered | Product / service offering proposed for selection |
|
E | Utility: Like | Expected utility for each liked Product /Service offering | |
F | Utility: Dislike | Expected utility for each disliked Product /Service offering | |
G | Utility: item | Expected utility for each Product /Service offering | |
H | Utility: scaled | Scaled utility for each Product /Service offering | |
I | Utility: transformed | Transformed utility for each Product /Service offering | |
J | Preference share | Preference share for each Product /Service offering | |
K | Index | Index of each Product /Service offering (Base 100 = Preference Share.Avg) |
To perform these above calculations, we will apply a cleaning script in the Tab Settings/Sorting which will replace the content of each row item loop by the result generated by the aggregated calculation script.
Note: we detect some keywords in the row item loop caption. So if you want to rename it, don't forgot to change them as well in the cleaning script (green highlighted word below):
Dim rm_ycoord
Dim rl_ycoord
Dim s_ycoord
Dim ns_ycoord
Dim to_ycoord
Dim ul_ycoord
Dim udl_ycoord
Dim ui_ycoord
Dim us_ycoord
Dim ut_ycoord
Dim ps_ycoord
Dim in_ycoord
Dim j
For j = CurrentTable.StartY to CurrentTable.MaxY
If InStr("Most",CurrentTable.GetCell(CurrentTable.StartX-1,j).Text) Then
rm_ycoord=j
Endif
If InStr("Least",CurrentTable.GetCell(CurrentTable.StartX-1,j).Text) Then
rl_ycoord=j
Endif
If InStr("Selected",CurrentTable.GetCell(CurrentTable.StartX-1,j).Text) Then
s_ycoord=j
Endif
If InStr("Not Selected",CurrentTable.GetCell(CurrentTable.StartX-1,j).Text) Then
ns_ycoord=j
Endif
If InStr("Offered",CurrentTable.GetCell(CurrentTable.StartX-1,j).Text) Then
to_ycoord=j
Endif
If InStr("Utility Like",CurrentTable.GetCell(CurrentTable.StartX-1,j).Text) Then
ul_ycoord=j
Endif
If InStr("Utility DisLike",CurrentTable.GetCell(CurrentTable.StartX-1,j).Text) Then
udl_ycoord=j
Endif
If InStr("Utility Item",CurrentTable.GetCell(CurrentTable.StartX-1,j).Text) Then
ui_ycoord=j
Endif
If InStr("Utility Scaled",CurrentTable.GetCell(CurrentTable.StartX-1,j).Text) Then
us_ycoord=j
Endif
If InStr("Utility Transformed",CurrentTable.GetCell(CurrentTable.StartX-1,j).Text) Then
ut_ycoord=j
Endif
If InStr("Preference Share",CurrentTable.GetCell(CurrentTable.StartX-1,j).Text) Then
ps_ycoord=j
Endif
If InStr("Index",CurrentTable.GetCell(CurrentTable.StartX-1,j).Text) Then
in_ycoord=j
Endif
Next j
Dim Rec_most
Dim Rec_least
Dim Rec_not_selected
Dim Rec_Total_offered
Dim UtilityLike
Dim UtilityDisLike
Dim Rec_Preference_Share
Dim arrUtilityItemVals = {}
Dim i
For i = CurrentTable.StartX to CurrentTable.MaxX
Rec_most = CurrentTable.GetCell(i,rm_ycoord).Value ' {1}
Rec_least = CurrentTable.GetCell(i,rl_ycoord).Value ' {2}
Rec_not_selected = CurrentTable.GetCell(i,ns_ycoord).Value ' {3}
'Rec_Total_offered = CurrentTable.GetCell(i,to_ycoord).Value ' {5}
Rec_Total_offered = Rec_most + Rec_least + Rec_not_selected
UtilityLike = (Rec_most/Rec_Total_offered)/(1-(Rec_most/Rec_Total_offered))
UtilityDisLike = (Rec_least/Rec_Total_offered)/(1-(Rec_least/Rec_Total_offered))
CurrentTable.GetCell(i,to_ycoord).SetText(Rec_Total_Offered.Round(0).ToString()).SetBackColor("YELLOW")
CurrentTable.GetCell(i,ul_ycoord).SetText(UtilityLike.Log().Round(5).ToString()).SetBackColor("YELLOW")
CurrentTable.GetCell(i,udl_ycoord).SetText((-1*UtilityDisLike.Log()).Round(5).ToString()).SetBackColor("YELLOW")
CurrentTable.GetCell(i,ui_ycoord).SetText(((UtilityLike.Log()-UtilityDisLike.Log())/2).Round(5).ToString()).SetBackColor("YELLOW")
arrUtilityItemVals.Push(((UtilityLike.Log()-UtilityDisLike.Log())/2))
Next i
Dim e = 2.7182818284590452353602874713526624977572
Dim arrUtilityTransformedVals = {}
Dim ii
For ii = CurrentTable.StartX to CurrentTable.MaxX
Rec_most = CurrentTable.GetCell(ii,rm_ycoord).Value ' {1}
Rec_least = CurrentTable.GetCell(ii,rl_ycoord).Value ' {2}
Rec_not_selected = CurrentTable.GetCell(i,ns_ycoord).Value ' {3}
'Rec_Total_offered = CurrentTable.GetCell(i,to_ycoord).Value ' {5}
Rec_Total_offered = Rec_most + Rec_least + Rec_not_selected
UtilityLike = (Rec_most/Rec_Total_offered)/(1-(Rec_most/Rec_Total_offered))
UtilityDisLike = (Rec_least/Rec_Total_offered)/(1-(Rec_least/Rec_Total_offered))
'utility scaled
CurrentTable.GetCell(ii,us_ycoord).SetText((arrUtilityItemVals[ii-1] - arrUtilityItemVals.avg() ).Round(5).ToString()).SetBackColor("YELLOW")
'utility transformed
CurrentTable.GetCell(ii,ut_ycoord).SetText(Pow(e,(arrUtilityItemVals[ii-1] - arrUtilityItemVals.avg() )).Round(5).ToString()).SetBackColor("YELLOW")
arrUtilityTransformedVals.Push(Pow(e,(arrUtilityItemVals[ii-1] - arrUtilityItemVals.avg() )))
Next ii
'Preference Share
Dim iii
Dim arrPreferenceShare = {}
For iii = CurrentTable.StartX to CurrentTable.MaxX
Rec_most = CurrentTable.GetCell(iii,rm_ycoord).Value ' {1}
Rec_least = CurrentTable.GetCell(iii,rl_ycoord).Value ' {2}
Rec_not_selected = CurrentTable.GetCell(i,ns_ycoord).Value ' {3}
Rec_Total_offered = Rec_most + Rec_least + Rec_not_selected
UtilityLike = (Rec_most/Rec_Total_offered)/(1-(Rec_most/Rec_Total_offered))
UtilityDisLike = (Rec_least/Rec_Total_offered)/(1-(Rec_least/Rec_Total_offered))
CurrentTable.GetCell(iii,ps_ycoord).SetText((100* arrUtilityTransformedVals[iii-1]/ arrUtilityTransformedVals.sum()).Round(0).ToString()+"%").SetBackColor("YELLOW")
arrPreferenceShare.Push((100* arrUtilityTransformedVals[iii-1]/ arrUtilityTransformedVals.sum()))
Next iii
'Index
Dim iiii
For iiii = CurrentTable.StartX to CurrentTable.MaxX
CurrentTable.GetCell(iiii,in_ycoord).SetText((arrPreferenceShare[iiii-1] * 100 / arrPreferenceShare.Avg()).Round(0).ToString()).SetBackColor("YELLOW")
next iiii
Then we transpose the table (see Tab Settings/Breaks options) for a better rendering.
As a result, we highlight in yellow the cells with the content replaced by the aggregated script (see MaxDiff_Example2).
- Using calculated variables
From the 5.6.1 version, we can use the 'changeLevel()' script and create:
- A variable by Closed level a loop Services with the items (Closed level).
- A variable Numeric by script: Utility (in the Services level).
- A variable Numeric by script: Utility transformed (in the Services level).
Note that this variable will not be used into a Tab Definition but just as intermediary variable.
- And finally, a variable Numeric by script: Preference share (in the Services level).
As a result, we have (see MaxDiff_Example3).
You can report the following results:
Index
|
%Like / % Dislike |
The example QES files and portfolios can be found in these examples: