AHP is a method allowing individuals or groups to make complex decisions. The core concept of AHP is that alternatives are always compared pairwise (and not, say, by giving a score, or sorting alternatives). AHP is used in many fields, from finance to criminal investigation.
For a general introduction to AHP, you might be interested in this.
Another good introduction is here
For a more formal introduction to the subject, see: Saaty, T. L. (2001). Decision Making for Leaders: The Analytic Hierarchy Process for Decisions in a Complex World, New Edition 2001 (3 Revised). Pittsburgh, PA: RWS Publications.
This package is built on top of the data.tree package, and uses R6
reference classes. To learn more about these, you might be interested in the Introduction:
library(R6)
vignette('Introduction', package = 'R6')
Even though this is not required, the data.tree Introduction vignette might also be helpful:
library(data.tree)
vignette(package = 'data.tree')
This vignette follows a well-known AHP example that you can also find e.g. on Wikipedia. In this example, the Jones family wants to buy a new car and uses AHP to decide systematically which car they should buy. Even though a few details are different from the original article, it is recommended to consider this vignette as an extension of that article, and not as a self sufficient document.
When deciding which car to buy, the family considers the following criteria: cost, safety, style, and capacity. Additionally, some of the criteria have sub-criteria.
The Jones’ have a shortlist of 6 cars.
We can draw the hierarchy like this:
Ahp Tree
Using the ahp package, the AHP hierarchy tree can be defined in an ahp file. An ahp file is a text file in yaml format, following a few conventions. For example:
## Version: 2.0
##
## #########################
## # Alternatives Section
## #
##
## Alternatives: &alternatives
## # Here, we list all the alternatives, together with their attributes.
## # We can use these attributes later in the file when defining
## # preferenceFunctions. The attributes can be quantitative or
## # qualitative.
## Accord Sedan:
## price: 20360
## mpg: 31
## passengers: 5
## cargo: 14
## curb weight: 3289
## safety class: Midsize Car
## crash rating: 4 in Side Impact Front
## residual value: 0.52
## Accord Hybrid:
## price: 31090
## mpg: 35
## passengers: 5
## cargo: 14
## curb weight: 3501
## safety class: Midsize Car
## crash rating: 4 in Side Impact Front
## residual value: 0.46
## Pilot:
## price: 27595
## mpg: 22
## passengers: 8
## cargo: 87.6
## curb weight: 4264
## safety class: Midsize SUV
## crash rating: 4 in Rollover
## residual value: 0.4
## CR-V:
## price: 20700
## mpg: 27
## passengers: 5
## cargo: 72.9
## curb weight: 3389
## safety class: Small SUV
## crash rating: 4 in Rollover
## residual value: 0.55
## Element:
## price: 18980
## mpg: 25
## passengers: 4
## cargo: 74.6
## curb weight: 3433
## safety class: Small SUV
## crash rating: 3 in Rollover
## residual value: 0.48
## Odyssey:
## price: 25645
## mpg: 26
## passengers: 8
## cargo: 147.4
## curb weight: 4385
## safety class: Minivan
## crash rating: All 5 Stars
## residual value: 0.48
##
## #
## # End of Alternatives Section
## #####################################
##
## #####################################
## # Goal Section
## #
##
##
## Goal:
## # The goal spans a tree of criteria and the alternatives
## name: Buy Car
## description: >
## This is a classic single decision maker problem. It models
## the situation facing by a family that wants to buy a new car.
## author: unknown
## preferences:
## # preferences are typically defined pairwise
## # 1 means: A is equal to B
## # 9 means: A is highly preferrable to B
## # 1/9 means: B is highly preferrable to A
## pairwise:
## - [Cost, Safety, 3]
## - [Cost, Style, 7]
## - [Cost, Capacity, 3]
## - [Safety, Style, 9]
## - [Safety, Capacity, 1]
## - [Style, Capacity, 1/7]
## children:
## Cost:
## preferences:
## pairwise:
## - [Purchase Price, Fuel Cost, 2]
## - [Purchase Price, Maintenance Cost, 5]
## - [Purchase Price, Resale Value, 3]
## - [Fuel Cost, Maintenance Cost, 2]
## - [Fuel Cost, Resale Value, 2]
## - [Maintenance Cost, Resale Value, 1/2]
## children:
## Purchase Price:
## preferences:
## pairwise:
## - [Accord Sedan, Accord Hybrid, 9]
## - [Accord Sedan, Pilot, 9]
## - [Accord Sedan, CR-V, 1]
## - [Accord Sedan, Element, 1/2]
## - [Accord Sedan, Odyssey, 5]
## - [Accord Hybrid, Pilot, 1]
## - [Accord Hybrid, CR-V, 1/9]
## - [Accord Hybrid, Element, 1/9]
## - [Accord Hybrid, Odyssey, 1/7]
## - [Pilot, CR-V, 1/9]
## - [Pilot, Element, 1/9]
## - [Pilot, Odyssey, 1/7]
## - [CR-V, Element, 1/2]
## - [CR-V, Odyssey, 5]
## - [Element, Odyssey, 6]
## children: *alternatives
## # We don't need to retype the alternatives here. Instead
## # we can simply make a reference to the alternatives anchor
## # defined in the alternatives section of the file.
## Fuel Cost:
## # Alternatively to the pairwise preferences, you
## # can define a preference function. This function
## # is in R syntax, and needs to have two arguments.
## # The Calculate method will pass all combinations
## # of alternatives to this function, and the function
## # is expected to return the pairwise preference, i.e.
## # a number between 1/9 and 9.
## preferences:
## pairwiseFunction:
## function(a1, a2) min(9, max(1/9, a2$mpg/a1$mpg))
## children: *alternatives
## Maintenance Cost:
## preferences:
## pairwise:
## - [Accord Sedan, Accord Hybrid, 1.5]
## - [Accord Sedan, Pilot, 4]
## - [Accord Sedan, CR-V, 4]
## - [Accord Sedan, Element, 4]
## - [Accord Sedan, Odyssey, 5]
## - [Accord Hybrid, Pilot, 4]
## - [Accord Hybrid, CR-V, 4]
## - [Accord Hybrid, Element, 4]
## - [Accord Hybrid, Odyssey, 5]
## - [Pilot, CR-V, 1]
## - [Pilot, Element, 1.2]
## - [Pilot, Odyssey, 1]
## - [CR-V, Element, 1]
## - [CR-V, Odyssey, 3]
## - [Element, Odyssey, 2]
## children: *alternatives
## Resale Value:
## preferences:
## pairwiseFunction: >
## GetResalePreference <- function(a1, a2) {
## if (a1$`residual value` < a2$`residual value`) return (1/GetResalePreference(a2, a1))
## ratio <- a1$`residual value` / a2$`residual value`
## if (ratio < 1.05) return (1)
## if (ratio < 1.1) return (2)
## if (ratio < 1.15) return (3)
## if (ratio < 1.2) return (4)
## if (ratio < 1.25) return (5)
## return (5)
## }
## children: *alternatives
## Safety:
## preferences:
## pairwise:
## - [Accord Sedan, Accord Hybrid, 1]
## - [Accord Sedan, Pilot, 5]
## - [Accord Sedan, CR-V, 7]
## - [Accord Sedan, Element, 9]
## - [Accord Sedan, Odyssey, 1/3]
## - [Accord Hybrid, Pilot, 5]
## - [Accord Hybrid, CR-V, 7]
## - [Accord Hybrid, Element, 9]
## - [Accord Hybrid, Odyssey, 1/3]
## - [Pilot, CR-V, 2]
## - [Pilot, Element, 9]
## - [Pilot, Odyssey, 1/8]
## - [CR-V, Element, 2]
## - [CR-V, Odyssey, 1/8]
## - [Element, Odyssey, 1/9]
## children: *alternatives
## Style:
## preferences:
## pairwise:
## - [Accord Sedan, Accord Hybrid, 1]
## - [Accord Sedan, Pilot, 7]
## - [Accord Sedan, CR-V, 5]
## - [Accord Sedan, Element, 9]
## - [Accord Sedan, Odyssey, 6]
## - [Accord Hybrid, Pilot, 7]
## - [Accord Hybrid, CR-V, 5]
## - [Accord Hybrid, Element, 9]
## - [Accord Hybrid, Odyssey, 6]
## - [Pilot, CR-V, 1/6]
## - [Pilot, Element, 3]
## - [Pilot, Odyssey, 1/3]
## - [CR-V, Element, 7]
## - [CR-V, Odyssey, 5]
## - [Element, Odyssey, 1/5]
## children: *alternatives
## Capacity:
## preferences:
## pairwise:
## - [Cargo Capacity, Passenger Capacity, 1/5]
## children:
## Cargo Capacity:
## preferences:
## pairwiseFunction: >
## CargoPreference <- function(a1, a2) {
## if (a1$cargo < a2$cargo) return (1/CargoPreference(a2, a1))
## ratio <- a1$cargo / a2$cargo
## if (ratio < 3) return (1)
## if (ratio < 8) return (2)
## return (3)
## }
## children: *alternatives
## Passenger Capacity:
## preferences:
## pairwise:
## - [Accord Sedan, Accord Hybrid, 1]
## - [Accord Sedan, Pilot, 1/2]
## - [Accord Sedan, CR-V, 1]
## - [Accord Sedan, Element, 3]
## - [Accord Sedan, Odyssey, 1/2]
## - [Accord Hybrid, Pilot, 1/2]
## - [Accord Hybrid, CR-V, 1]
## - [Accord Hybrid, Element, 3]
## - [Accord Hybrid, Odyssey, 1/2]
## - [Pilot, CR-V, 2]
## - [Pilot, Element, 6]
## - [Pilot, Odyssey, 1]
## - [CR-V, Element, 3]
## - [CR-V, Odyssey, 1/2]
## - [Element, Odyssey, 1/6]
## children: *alternatives
##
## #
## # End of Goal Section
## #####################################
Let’s look at the various elements of this file.
The first section is a list of alternatives. Note that they have properties. For example:
Alternatives: &alternatives
Accord Sedan:
price: 20360
mpg: 31
passengers: 5
cargo: 14
curb weight: 3289
safety class: Midsize Car
crash rating: 4 in Side Impact Front
residual value: 0.52
Accord Hybrid:
price: 31090
mpg: 35
passengers: 5
...
You are entirely free regarding the type and format of information you store in your alternatives. Some models can do without any properties at all. However, often you would like to define your preferences as a function of properties. Later, you will see how you can define functions that refer to these properties to derive the pairwise preferences of alternatives with respect to a specific criteria.
The second section of the ahp file is the Goal. Here, you define your criteria tree, your pairwise preferences, and - if applicable - your preference functions.
Criteria are grouped hierarchically. Each criteria has at least the following sections:
An example of a criteria which has explicit pairwise preference is the
Cost:
preferences:
pairwise:
- [Purchase Price, Fuel Cost, 2]
- [Purchase Price, Maintenance Cost, 5]
- [Purchase Price, Resale Value, 3]
- [Fuel Cost, Maintenance Cost, 2]
- [Fuel Cost, Resale Value, 2]
- [Maintenance Cost, Resale Value, 1/2]
children:
Purchase Price:
preferences:
...
Here, we say, for instance, that Purchase Price is slightly more important to Fuel Cost. Purchase Price is, however, much more important than maintenance cost.
To keep the ahp file short, you can reference to the alternatives defined above. In order for this to work, your alternatives need to be defined as an anchor, using the & sign:
Alternatives: &alternatives
Accord Sedan:
price: 20360
...
Note that this is a standard YAML feature.
You can then later refer to the anchor using the * reference feature:
Style:
preferences:
pairwise:
- [Accord Sedan, Accord Hybrid, 1]
- [Accord Sedan, Pilot, 7]
- [Accord Sedan, CR-V, 5]
- [Accord Sedan, Element, 9]
- [Accord Sedan, Odyssey, 6]
- [Accord Hybrid, Pilot, 7]
- [Accord Hybrid, CR-V, 5]
- [Accord Hybrid, Element, 9]
- [Accord Hybrid, Odyssey, 6]
- [Pilot, CR-V, 1/6]
- [Pilot, Element, 3]
- [Pilot, Odyssey, 1/3]
- [CR-V, Element, 7]
- [CR-V, Odyssey, 5]
- [Element, Odyssey, 1/5]
children: *alternatives
Instead of defining the preferences explicitly in a pairwise manner, you can define a preference function. For example, you can define
Fuel Cost:
preferences:
function:
function(a1, a2) min(9, max(1/9, a1$mpg/a2$mpg))
children: *alternatives
...
Note that, in this case, we have a field preferenceFunction instead of preferences. The function itself is a standard R function, and the arguments a1 and a2 are pairwise combinations of the criteria, i.e. in this case, the alternatives.
Here, we simply say that the AHP preference is the ratio of the mpg (i.e. miles per gallon) a car uses. And since we store properties mpg on the alternatives, we can reference them directly here. We want the ratio to be between 1/9 and 9, as these are the typical AHP acceptable preferences.
You can even define a named preference function that you can use for recursion:
Resale Value:
preferences:
function: >
GetResalePreference <- function(a1, a2) {
if (a1$`residual value` < a2$`residual value`) return (1/GetResalePreference(a2, a1))
ratio <- a1$`residual value` / a2$`residual value`
if (ratio < 1.05) return (1)
if (ratio < 1.1) return (2)
if (ratio < 1.15) return (3)
if (ratio < 1.2) return (4)
if (ratio < 1.25) return (5)
return (5)
}
children: *alternatives
Loading the file is done by calling LoadFile
:
library(ahp)
ahpFile <- system.file("extdata", "car.ahp", package="ahp")
carAhp <- Load(ahpFile)
carAhp
, the return value of LoadFile
, is a data.tree
structure. Its structure is the same as the one of the file. If you are interested in solving AHP problems programmatically, all you need to do is to create a tree with that structure, using the data.tree
functions.
library(data.tree)
print(carAhp, filterFun = isNotLeaf)
## levelName
## 1 Buy Car
## 2 ¦--Cost
## 3 ¦ ¦--Purchase Price
## 4 ¦ ¦--Fuel Cost
## 5 ¦ ¦--Maintenance Cost
## 6 ¦ °--Resale Value
## 7 ¦--Safety
## 8 ¦--Style
## 9 °--Capacity
## 10 ¦--Cargo Capacity
## 11 °--Passenger Capacity
Calculate(carAhp)
print(carAhp, priority = function(x) x$parent$priority["Total", x$name])
## levelName priority
## 1 Buy Car NA
## 2 ¦--Cost 0.51007502
## 3 ¦ ¦--Purchase Price 0.48805379
## 4 ¦ ¦ ¦--Accord Sedan 0.24617542
## 5 ¦ ¦ ¦--Accord Hybrid 0.02455426
## 6 ¦ ¦ ¦--Pilot 0.02455426
## 7 ¦ ¦ ¦--CR-V 0.24617542
## 8 ¦ ¦ ¦--Element 0.36575063
## 9 ¦ ¦ °--Odyssey 0.09279001
## 10 ¦ ¦--Fuel Cost 0.25153610
## 11 ¦ ¦ ¦--Accord Sedan 0.14544902
## 12 ¦ ¦ ¦--Accord Hybrid 0.12882628
## 13 ¦ ¦ ¦--Pilot 0.20495090
## 14 ¦ ¦ ¦--CR-V 0.16699703
## 15 ¦ ¦ ¦--Element 0.18035679
## 16 ¦ ¦ °--Odyssey 0.17341999
## 17 ¦ ¦--Maintenance Cost 0.09986256
## 18 ¦ ¦ ¦--Accord Sedan 0.35819852
## 19 ¦ ¦ ¦--Accord Hybrid 0.31325042
## 20 ¦ ¦ ¦--Pilot 0.08369953
## 21 ¦ ¦ ¦--CR-V 0.09953251
## 22 ¦ ¦ ¦--Element 0.08791282
## 23 ¦ ¦ °--Odyssey 0.05740619
## 24 ¦ °--Resale Value 0.16054755
## 25 ¦ ¦--Accord Sedan 0.23408904
## 26 ¦ ¦--Accord Hybrid 0.11101029
## 27 ¦ ¦--Pilot 0.03808108
## 28 ¦ ¦--CR-V 0.36023288
## 29 ¦ ¦--Element 0.12829335
## 30 ¦ °--Odyssey 0.12829335
## 31 ¦--Safety 0.23435219
## 32 ¦ ¦--Accord Sedan 0.21624385
## 33 ¦ ¦--Accord Hybrid 0.21624385
## 34 ¦ ¦--Pilot 0.07515991
## 35 ¦ ¦--CR-V 0.03603025
## 36 ¦ ¦--Element 0.02229468
## 37 ¦ °--Odyssey 0.43402745
## 38 ¦--Style 0.04051875
## 39 ¦ ¦--Accord Sedan 0.35785923
## 40 ¦ ¦--Accord Hybrid 0.35785923
## 41 ¦ ¦--Pilot 0.03886101
## 42 ¦ ¦--CR-V 0.15508522
## 43 ¦ ¦--Element 0.02275249
## 44 ¦ °--Odyssey 0.06758283
## 45 °--Capacity 0.21505404
## 46 ¦--Cargo Capacity 0.16666667
## 47 ¦ ¦--Accord Sedan 0.09193018
## 48 ¦ ¦--Accord Hybrid 0.09193018
## 49 ¦ ¦--Pilot 0.19640904
## 50 ¦ ¦--CR-V 0.19640904
## 51 ¦ ¦--Element 0.19640904
## 52 ¦ °--Odyssey 0.22691251
## 53 °--Passenger Capacity 0.83333333
## 54 ¦--Accord Sedan 0.13636364
## 55 ¦--Accord Hybrid 0.13636364
## 56 ¦--Pilot 0.27272727
## 57 ¦--CR-V 0.13636364
## 58 ¦--Element 0.04545455
## 59 °--Odyssey 0.27272727
Don’t worry if you don’t understand this command. But if you are interested you might want to look into the structure of carAhp, and read up on data.tree
documentation.
Visualize(carAhp)
visualize
Analyze(carAhp)
## Weight Odyssey Accord Sedan CR-V Element Accord Hybrid Pilot Inconsistency
## 1 Buy Car 100.0% 22.0% 21.0% 16.3% 15.1% 14.1% 11.5% 7.5%
## 2 ¦--Cost 51.0% 5.9% 11.7% 11.7% 12.9% 4.8% 4.0% 1.5%
## 3 ¦ ¦--Purchase Price 24.9% 2.3% 6.1% 6.1% 9.1% 0.6% 0.6% 6.8%
## 4 ¦ ¦--Fuel Cost 12.8% 2.2% 1.9% 2.1% 2.3% 1.7% 2.6% 0.0%
## 5 ¦ ¦--Resale Value 8.2% 1.1% 1.9% 2.9% 1.1% 0.9% 0.3% 3.2%
## 6 ¦ °--Maintenance Cost 5.1% 0.3% 1.8% 0.5% 0.4% 1.6% 0.4% 2.3%
## 7 ¦--Safety 23.4% 10.2% 5.1% 0.8% 0.5% 5.1% 1.8% 8.0%
## 8 ¦--Capacity 21.5% 5.7% 2.8% 3.1% 1.5% 2.8% 5.6% 0.0%
## 9 ¦ ¦--Passenger Capacity 17.9% 4.9% 2.4% 2.4% 0.8% 2.4% 4.9% 0.0%
## 10 ¦ °--Cargo Capacity 3.6% 0.8% 0.3% 0.7% 0.7% 0.3% 0.7% 0.4%
## 11 °--Style 4.1% 0.3% 1.5% 0.6% 0.1% 1.5% 0.2% 10.1%
Note that, thanks to the formattable
package, the columns are numerics
, even though they are formatted as percentages.
Another way to display the AHP analysis is with the ShowTable
function, which displays an html table with color codings to help interpret the numbers:
AnalyzeTable(carAhp)
Weight | Odyssey | Accord Sedan | CR-V | Element | Accord Hybrid | Pilot | Inconsistency | |
---|---|---|---|---|---|---|---|---|
Buy Car | 100.0% | 22.0% | 21.0% | 16.3% | 15.1% | 14.1% | 11.5% | 7.5% |
Cost | 51.0% | 5.9% | 11.7% | 11.7% | 12.9% | 4.8% | 4.0% | 1.5% |
Purchase Price | 24.9% | 2.3% | 6.1% | 6.1% | 9.1% | 0.6% | 0.6% | 6.8% |
Fuel Cost | 12.8% | 2.2% | 1.9% | 2.1% | 2.3% | 1.7% | 2.6% | 0.0% |
Resale Value | 8.2% | 1.1% | 1.9% | 2.9% | 1.1% | 0.9% | 0.3% | 3.2% |
Maintenance Cost | 5.1% | 0.3% | 1.8% | 0.5% | 0.4% | 1.6% | 0.4% | 2.3% |
Safety | 23.4% | 10.2% | 5.1% | 0.8% | 0.5% | 5.1% | 1.8% | 8.0% |
Capacity | 21.5% | 5.7% | 2.8% | 3.1% | 1.5% | 2.8% | 5.6% | 0.0% |
Passenger Capacity | 17.9% | 4.9% | 2.4% | 2.4% | 0.8% | 2.4% | 4.9% | 0.0% |
Cargo Capacity | 3.6% | 0.8% | 0.3% | 0.7% | 0.7% | 0.3% | 0.7% | 0.4% |
Style | 4.1% | 0.3% | 1.5% | 0.6% | 0.1% | 1.5% | 0.2% | 10.1% |
Finally, note that the Analyze
and AnalyzeTable
functions have many more options, e.g. to sort, filter, and further customize the output. For example:
AnalyzeTable(carAhp,
variable = "priority",
sort = "orig",
pruneFun = function(node, decisionMaker) PruneByCutoff(node, decisionMaker, 0.05),
weightColor = "skyblue",
consistencyColor = "red",
alternativeColor = "green")
Priority | Accord Sedan | Accord Hybrid | Pilot | CR-V | Element | Odyssey | Inconsistency | |
---|---|---|---|---|---|---|---|---|
Buy Car | 100.0% | 7.5% | ||||||
Cost | 51.0% | 1.5% | ||||||
Purchase Price | 48.8% | 24.6% | 2.5% | 2.5% | 24.6% | 36.6% | 9.3% | 6.8% |
Fuel Cost | 25.2% | 14.5% | 12.9% | 20.5% | 16.7% | 18.0% | 17.3% | 0.0% |
Maintenance Cost | 10.0% | 35.8% | 31.3% | 8.4% | 10.0% | 8.8% | 5.7% | 2.3% |
Resale Value | 16.1% | 23.4% | 11.1% | 3.8% | 36.0% | 12.8% | 12.8% | 3.2% |
Safety | 23.4% | 21.6% | 21.6% | 7.5% | 3.6% | 2.2% | 43.4% | 8.0% |
Capacity | 21.5% | 0.0% | ||||||
Passenger Capacity | 83.3% | 13.6% | 13.6% | 27.3% | 13.6% | 4.5% | 27.3% | 0.0% |
The ahp
package also supports multiple decision makers, as shown by the vacation example, provided with the ahp
package. The basic idea is that multiple people get to formulate their pairwise preferences, and then the AHP calculates the average. Often, each decision maker has the same voting weight, but that does not need to be the case.
In this example we look at a family that wants to decide where to go on vacation. There are two options: to the mountains, or to the beach. The family has already found a suitable hotel at each destination, and has calculated to total price of each destination. All three family members can vote on the destination, but mom and dad have twice the voting power of the kid.
The file is provided by the ahp
package, and you may look at its content as so:
ahpFile <- system.file("extdata", "vacation.ahp", package="ahp")
cat(readChar(ahpFile, file.info(ahpFile)$size))
Version: 2.0
Alternatives: &alternatives
Beach:
cost: 10000
Mountains:
cost: 5000
Goal:
name: Vacation
decision-makers:
#optional node, needed only if not all decision-makers have equal voting power
- Dad: 0.4
- Mom: 2/5
- Kid: 0.2
preferences:
Dad:
pairwise:
- [Costs, Fun, 4]
- [Costs, Spa, 9]
- [Fun, Spa, 4]
Mom:
pairwise:
- [Costs, Fun, 1/4]
- [Costs, Spa, 1/9]
- [Fun, Spa, 1/5]
Kid:
pairwise:
- [Costs, Fun, 1/9]
- [Costs, Spa, 1]
- [Fun, Spa, 9]
children:
Costs:
preferences:
Dad:
pairwiseFunction:
function(a1, a2) min(9, max(1/9, a2$cost/a1$cost))
Mom:
scoreFunction:
function(a) 1/a$cost
Kid:
priority:
- Beach: 1/2
- Mountains: 0.5
children: *alternatives
Fun:
preferences:
Dad:
pairwise:
- [Beach, Mountains, 1/6]
Mom:
pairwise:
- [Beach, Mountains, 2]
Kid:
# Often, entering pairwise preferences is lengthy, especially if you
# have multiple alternatives. Instead, you can enter scores, i.e. rate
# each alternative on a scale. The scale can be chosen freely. The
# priorities are derived as score / sum(scores)
score:
- Beach: 5
- Mountains: 0
children: *alternatives
Spa:
preferences:
Dad:
pairwise:
- [Beach, Mountains, 2]
Mom:
pairwise:
- [Beach, Mountains, 6]
Kid:
pairwise:
- [Beach, Mountains, 1/2]
children: *alternatives
The file structure is similar to the car.ahp
file. There are two main differences, however:
decision-maker
sectionpreferences
section, there are sub-nodes, one for each decision makerdecision-maker
sectionIn our example, this section is directly below the Goal:
decision-makers:
#optional node, needed only if not all decision-makers have equal voting power
- Dad: 0.4
- Mom: 2/5
- Kid: 0.2
The node contains a map of decision makers, together with their respective weights. As the commentary says, this section is optional, and only required if you do not have equal voting power.
Additionally, there may be more than a single decision-makers
section. If, for example, Dad has more voting power on the Cost criteria, and Mom more on the Spa, then you can add multiple decision-makers
nodes. These weights are inherited, i.e. each criteria node checks if it has a decision-makers
directive. If it doesn’t, it walks toward the root and checks on each ancestor. If it cannot find a directive, even at the root, it assumes equal voting power.
preferences
sectionIn the case of multiple decision makers, the preferences look like this:
preferences:
Dad:
pairwise:
- [Costs, Fun, 4]
- [Costs, Spa, 9]
- [Fun, Spa, 4]
Mom:
pairwise:
- [Costs, Fun, 1/4]
- [Costs, Spa, 1/9]
- [Fun, Spa, 1/5]
Kid:
pairwise:
- [Costs, Fun, 1/9]
- [Costs, Spa, 1]
- [Fun, Spa, 9]
Note, however, that different decision-makers can have different types of preferences, for instance:
Costs:
preferences:
Dad:
function:
function(a1, a2) min(9, max(1/9, a2$cost/a1$cost))
Mom:
pairwise:
- [Beach, Mountains, 1/3]
Kid:
weight:
- Beach: 1/2
- Mountains: 0.5
children: *alternatives
Here, Dad says that if alternative 1 has half the cost of alternative 2, it is twice as preferred. Mom wants to keep it simple and says that, cost-wise, whe prefers the mountains over the beach. The kid, finally, has not yet fully grasped the concept of money, so he simply gives a 0.5 weight to each alternative, essentially saying he’s indifferent.
To make the full analysis, averaging the decision-makers’ preferences, you use the same functions as for the single decision-maker case:
ahpFile <- system.file("extdata", "vacation.ahp", package="ahp")
vacationAhp <- Load(ahpFile)
Calculate(vacationAhp)
Visualize(vacationAhp)
visualize
AnalyzeTable(vacationAhp)
Weight | Beach | Mountains | Inconsistency | |
---|---|---|---|---|
Vacation | 100.0% | 52.4% | 47.6% | 6.8% |
Spa | 34.2% | 23.1% | 11.1% | 0.0% |
Costs | 33.0% | 12.1% | 20.9% | 0.0% |
Fun | 32.8% | 17.2% | 15.6% | 0.0% |
However, you may also drill down into each decision maker.
AnalyzeTable(vacationAhp, decisionMaker = "Dad")
Weight | Mountains | Beach | Inconsistency | |
---|---|---|---|---|
Vacation | 100.0% | 68.6% | 31.4% | 3.5% |
Costs | 71.7% | 47.8% | 23.9% | 0.0% |
Fun | 21.7% | 18.6% | 3.1% | 0.0% |
Spa | 6.6% | 2.2% | 4.4% | 0.0% |
AnalyzeTable(vacationAhp, decisionMaker = "Mom")
Weight | Beach | Mountains | Inconsistency | |
---|---|---|---|---|
Vacation | 100.0% | 78.7% | 21.3% | 6.8% |
Spa | 74.3% | 63.7% | 10.6% | 0.0% |
Fun | 19.4% | 12.9% | 6.5% | 0.0% |
Costs | 6.3% | 2.1% | 4.2% | NA |
AnalyzeTable(vacationAhp, decisionMaker = "Kid")
Weight | Beach | Mountains | Inconsistency | |
---|---|---|---|---|
Vacation | 100.0% | 89.4% | 10.6% | 0.0% |
Fun | 81.8% | 81.8% | 0.0% | NA |
Costs | 9.1% | 4.5% | 4.5% | NA |
Spa | 9.1% | 3.0% | 6.1% | 0.0% |