Rahpsurvey package (ver
0.4.1)ahpsurvey packageThe ahpsurvey package provides a workflow to quantify
and visualise inconsistent pairwise comparisons that aids researchers in
improving the AHP design and adopting appropriate analytically methods
for the AHP.
Install the package directly from CRAN (if you have not already installed the package).
# install.packages("ahpsurvey")And load the ahpsurvey library.
library(ahpsurvey)A Saaty scale is composed of 9 items on each end (17 options per
pairwise comparison) where decision-makers are asked to indicate how
much attribute/ characteristic A is more preferred to B (or vice versa),
and how much it is preferred in a 9-point scale. Respondents are asked
to make pairwise comparisons for a range of attributes, and indicate
their priorities for each of them. Afterwards, we load the data needed,
cleaned_data.csv, which consists of cleaned data of 17
individuals based on the raw data collected from students via the
distributed questionnaire (designed on the QuestionPro website at https://questionpro.com/t/AQ41hZtckV):
| ID | FD_TC | FD_SR | FD_HC | FD_LL | FD_CF | TC_SR | TC_HC | TC_LL | TC_CF | SR_HC | SR_LL | SR_CF | HC_LL | HC_CF | LL_CF |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 4 | -9 | 3 | 5 | -3 | -9 | -4 | 1 | -3 | 9 | 9 | 9 | 5 | 4 | -3 |
| 2 | 1 | -9 | 8 | 3 | -3 | -9 | 5 | 3 | -3 | 9 | 9 | 9 | -9 | -9 | -5 |
| 3 | 9 | -5 | 9 | 9 | 9 | -9 | 9 | 9 | 9 | 9 | 9 | 9 | -3 | -2 | -4 |
| 4 | -8 | -9 | -6 | -7 | -8 | -9 | -4 | 2 | 8 | 9 | 8 | 8 | -8 | -7 | 8 |
| 5 | -7 | -6 | -6 | -6 | 7 | 4 | 3 | -4 | 9 | 4 | 5 | 9 | 2 | 9 | 9 |
| 6 | -5 | -7 | -3 | -6 | -8 | -6 | -2 | -5 | -7 | 6 | 5 | 3 | -7 | -4 | -4 |
| 7 | 5 | -5 | 9 | 3 | -3 | -5 | 4 | -3 | -2 | 6 | 3 | 3 | -9 | -9 | -2 |
| 8 | -6 | -9 | 7 | -2 | -4 | -8 | 8 | 6 | -3 | 9 | 8 | 5 | -5 | -9 | -4 |
| 9 | -2 | -8 | 8 | -5 | 1 | -2 | 6 | 1 | 1 | 8 | 1 | 5 | -9 | -8 | 4 |
| 10 | -7 | -7 | 7 | -6 | -7 | -4 | 8 | -7 | -3 | 8 | -6 | 6 | -8 | -6 | -7 |
| 11 | -4 | -7 | 4 | 5 | 5 | -5 | 8 | 7 | 7 | 9 | 9 | 9 | -2 | 2 | 1 |
| 12 | -7 | -7 | -5 | -7 | 9 | -7 | -7 | -7 | 9 | 8 | 6 | 9 | -7 | 9 | 9 |
| 13 | -5 | -7 | 5 | -4 | 7 | -5 | 6 | -5 | 7 | 7 | 5 | 7 | -7 | 5 | 9 |
| 14 | 2 | -3 | 5 | 4 | 1 | -5 | 1 | -2 | -2 | 5 | 4 | 6 | -5 | -5 | 1 |
| 15 | -9 | 2 | -9 | -9 | -7 | 9 | 4 | -3 | 7 | -9 | -9 | -6 | -8 | -5 | 7 |
| 16 | 9 | 1 | 9 | 1 | 9 | -7 | 9 | -7 | 9 | 9 | 4 | 9 | -9 | -9 | 9 |
| 17 | -8 | -4 | -5 | -6 | -3 | 2 | 4 | 1 | 2 | 4 | 4 | 5 | -5 | -3 | 3 |
In the data:
FD: Food delivery
TC: Tourism, cultural exchange
SR: Shower room
HC: Health care
LL: Luggage / Locker Storage
CF: Cafe
atts <- c("FD", "TC", "SR", "HC", "LL", "CF")
dict <- c("FD" = "Food delivery",
"TC" = "Tourism, cultural exchange",
"SR" = "Shower rooms",
"HC" = "Health care",
"LL" = "Luggage / Locker Storage",
"CF" = "Cafe")The simulated dataset consists of fifteen pairwise comparisons of 6 attributes, which are “Food delivery”, “Tourism, cultural exchange”, “Shower room”, “Health care”, “Luggage / Locker Storage” and “Cafe.” An individual compares the attributes in a pairwise attribute comparison; if “Food delivery” is more important than “Tourism, cultural exchange” by 2 units on the Saaty scale, the dataset will code it as -2. This is essential to bear in mind as we move on.
Based on the Saaty scale, a pairwise comparison matrix of \(N\) attributes for the \(k^{th}\) individual is obtained:
\[ \mathbf{S_k} =\begin{pmatrix} a_{1,1} & a_{1,2} & \cdots & a_{1,N} \\ a_{2,1} & a_{2,2} & \cdots & a_{2,N} \\ \vdots & \vdots & a_{i,j} & \vdots \\ a_{N,1} & a_{N,2} & \cdots & a_{N,N} \end{pmatrix} \]
Where \(a_{i,j}\) represents the pairwise comparison between the attribute \(i\) and \(j\). If \(i\) is more important than \(j\) for 6 units, \(a_{i,j} = 6\) and \(a_{j,i} = \frac{1}{6}\), i.e. the reciprocal. Data must be reformatted into this pairwise comparison matrix format to proceed.
The reformatting of the survey data (with one row per individual)
into such a matrix necessary for further analysis is cumbersome for
researchers. Furthermore, as researchers conducting the AHP as an
integrated part of a survey, we typically receive data in the above
format: the pairwise comparisons are coded in positive and negative
numbers as opposed to reciprocals. In the case where the decision-maker
chose 6, the sensible codebook maker would code it as -6, which denotes
that Food delivery is more important than Tourism, cultural
exchange in 6 units for that decision-maker. For
ahp.mat to work, the value in A_B variable have to be the
importance A has over B in positive values. In this case, the values
should be converted from negative to positive, and the negative values
would be converted to its reciprocal in the pairwise matrix. When data
is coded in the above way, set negconvert = TRUE. If the
data is already coded in the reciprocal (as opposed to negatives), set
reciprocal = FALSE.
Some caveats prior to entering the data into the ahp.mat
function. ahp.mat does not recognise the names of the
original dataframe, and figures out which attribute corresponds to which
entirely based on the order of the columns. For example, when the
attributes are A, B, C and D, the dataframe should be ordered in
A_B, A_C, A_D, B_C, B_D, C_D, and the attributes listed as
c(A,B,C,D), in that order.
The ahp.mat function takes four arguments:
df: the dataframe
atts: a list of attributes in the correct
order
negconvert: whether to convert all positive values
to negative (logical, defaults to FALSE)
reciprocal: whether to convert negative values
(after negconvert) to its reciprocals (defaults to
TRUE).
The ahp.mat function creates a list of pairwise
comparison matrices for all decision-makers. As seen below, the pairwise
matrices resembles the original Saaty criteria weights, which is a good
sanity check.
The following only shows the first decision-maker’s pairwise comparison matrix:
AHP_data_mat <- ahp.mat(df = AHP_data, atts = atts, negconvert = TRUE)
AHP_data_mat %>% head(1) %>%
kable()
|
The ahp.indpref function computes the individual
priorities of the decision-makers, and returns a data.frame
containing the preference weights of the decision-makers. The three
arguments are as follows:
ahpmat: The list of matrices created by
ahp.mat.
atts: a list of attributes in the correct
order.
method: It normalises the matrices so that all the
columns add up to 1, and then computes the averages of the row as the
preference weights of each attribute. Four modes of finding the averages
are available:
arithmetic: the arithmetic meangeometric: the geometric meanrootmean: the square root of the sum of the squared
valueeigen: the individual preference weights are computed
using the Dominant Eigenvalue method described in (Saaty 2003)Here are the Individual priorities using arithmetic mean method.
arithm_ind <- ahp.indpref(AHP_data_mat, atts, method = "arithmetic")
round(arithm_ind, 3) %>%
rownames_to_column('ID') %>%
kable()| ID | FD | TC | SR | HC | LL | CF |
|---|---|---|---|---|---|---|
| 1 | 0.123 | 0.292 | 0.021 | 0.111 | 0.316 | 0.137 |
| 2 | 0.102 | 0.110 | 0.021 | 0.520 | 0.183 | 0.064 |
| 3 | 0.040 | 0.097 | 0.021 | 0.361 | 0.282 | 0.199 |
| 4 | 0.419 | 0.118 | 0.020 | 0.193 | 0.072 | 0.178 |
| 5 | 0.224 | 0.058 | 0.053 | 0.075 | 0.076 | 0.514 |
| 6 | 0.428 | 0.218 | 0.030 | 0.189 | 0.088 | 0.047 |
| 7 | 0.094 | 0.186 | 0.037 | 0.519 | 0.099 | 0.064 |
| 8 | 0.187 | 0.083 | 0.022 | 0.496 | 0.160 | 0.052 |
| 9 | 0.165 | 0.075 | 0.039 | 0.552 | 0.047 | 0.122 |
| 10 | 0.232 | 0.113 | 0.061 | 0.454 | 0.072 | 0.069 |
| 11 | 0.094 | 0.048 | 0.022 | 0.275 | 0.249 | 0.312 |
| 12 | 0.200 | 0.144 | 0.022 | 0.096 | 0.048 | 0.489 |
| 13 | 0.136 | 0.087 | 0.027 | 0.238 | 0.051 | 0.461 |
| 14 | 0.089 | 0.232 | 0.039 | 0.371 | 0.146 | 0.123 |
| 15 | 0.317 | 0.037 | 0.398 | 0.124 | 0.023 | 0.101 |
| 16 | 0.032 | 0.153 | 0.027 | 0.482 | 0.048 | 0.259 |
| 17 | 0.433 | 0.050 | 0.060 | 0.226 | 0.081 | 0.150 |
The ahp.aggpref function computes the aggregated
priorities of all decision-makers using the specified methods. The
following arguments are given:
method: Same as ahp.indpref. It normalises
the matrices so that all the columns add up to 1, and then computes the
averages of the row as the preference weights of each attribute. Four
modes of finding the averages are available:
arithmetic: the arithmetic meangeometric: the geometric meanrootmean: the square root of the sum of the squared
valueeigen: the individual preference weights are computed
using the Dominant Eigenvalues method.aggmethod: how to aggregate the individual priorities.
arithmetic, geometric and
rootmean (same principle as method)tmean trimmed meantgmean trimmed geometric meansd returns the standard deviation from the arithmetic
mean.arithm_agg <- ahp.aggpref(AHP_data_mat, atts, method = "arithmetic", aggmethod = "arithmetic")
round(arithm_agg, 3) %>% t() %>% kable()| FD | TC | SR | HC | LL | CF |
|---|---|---|---|---|---|
| 0.195 | 0.124 | 0.054 | 0.311 | 0.12 | 0.197 |
The consistency indices and consistency ratio of a given choice is defined by the following equation:
\[CR = \bigg(\frac{\lambda_{max}-n}{n-1}\bigg)\bigg(\frac{1}{RI}\bigg)\]
Where \(\lambda_{max}\) is the
maximum eigenvalue of the pairwise comparison vector and \(n\) is the number of attributes. The \(RI\) when 6 attributes are present is
1.258. See the documentation for ahp.ri to generate your
own RI based on a specific number of dimensions and random seed.
Saaty showed that when the \(CR\) is
higher than 0.1, the choice is deemed to be inconsistent. The
ahpsurvey package allows researchers to quantify the
inconsistency among the decision-makers and make decisions in their
analysis, either to drop inconsistent observations or look for ways to
adjust for inconsistency.
The ahp.cr function returns a vector of \(CR\) that can be merged to other dataframes
as a measure of the individuals’ consistency.
(cr1 <- ahp.cr(AHP_data_mat, atts) %>%
data.frame('CR1'=.) %>%
rownames_to_column('ID')) %>%
t() %>%
kable()| ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| CR1 | 0.1937 | 0.1672 | 0.2617 | 0.6225 | 0.3441 | 0.1397 | 0.1321 | 0.1665 | 0.0817 | 0.5708 | 0.0906 | 0.3617 | 0.2163 | 0.0812 | 0.2100 | 0.2639 | 0.1269 |
table(cr1$CR1 <= 0.1)##
## FALSE TRUE
## 14 3
You may also specify your own random index generated with
ahp.ri to be used with ahp.cr, as follows:
## Generate a random index with 1000 simulations, 6 dimensions and seed 30000 for reproducibility (seed = 42 by default).
(RI <- ahp.ri(nsims = 1000, dim = length(atts), seed = 30000))## [1] 1.26
## Use this RI to calculate the consistency ratio instead of the default one.
(cr2 <- ahp.cr(AHP_data_mat, atts, RI)%>%
data.frame('CR2'=.) %>%
rownames_to_column('ID')) %>%
t() %>%
kable()| ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| CR2 | 0.1924 | 0.1661 | 0.2600 | 0.6183 | 0.3418 | 0.1388 | 0.1312 | 0.1654 | 0.0812 | 0.5670 | 0.0900 | 0.3593 | 0.2149 | 0.0807 | 0.2086 | 0.2622 | 0.1260 |
table(cr2$CR2 <= 0.1)##
## FALSE TRUE
## 14 3
A better way would be to extract the pairwise comparison with the
maximum inconsistency error, and returning a list of the most
inconsistent pairwise comparisons for each decision-maker. This process
is automated in the ahp.pwerror function, which returns a
dataframe of the top three most inconsistent pairwise comparison made by
each decision-maker.
AHP_data %>%
ahp.mat(atts) %>%
ahp.pwerror(atts) %>%
head() %>%
kable()| top1 | top2 | top3 |
|---|---|---|
| FD_CF | HC_CF | FD_HC |
| HC_LL | TC_HC | HC_CF |
| TC_HC | TC_CF | HC_LL |
| HC_LL | FD_TC | FD_LL |
| TC_SR | LL_CF | TC_CF |
| HC_LL | FD_LL | FD_TC |
A better way to visualise the pairwise comparisons is a bar chart:
AHP_data_mat %>%
ahp.pwerror(atts) %>%
gather(top1, top2, top3, key = "max", value = "pair") %>%
table() %>%
as.data.frame() %>%
ggplot(aes(x = pair, y = Freq, fill = max)) +
geom_bar(stat = 'identity') +
scale_y_continuous("Frequency", breaks = seq(0, 180, 20)) +
scale_fill_discrete(breaks = c("top1", "top2", "top3"), labels = c("1", "2", "3")) +
scale_x_discrete("Pair") +
guides(fill = guide_legend(title="Rank")) +
theme(axis.text.x = element_text(angle = 20, hjust = 1),
panel.background = element_rect(fill = NA),
panel.grid.major.y = element_line(colour = "grey80"),
panel.grid.major.x = element_blank(),
panel.ontop = FALSE)Figure 4. Pairwise comparison and its frequency as the most, second-most, and third most inconsistent pairwise comparisons
The function ahp.harker takes five optional
arguments:
round is logical and tells ahp.harker
whether to convert the newly replaced values to integers and its
reciprocals, and can be set to TRUE if desired.
iterations denotes how many pairwise comparisons
should be changed. For example, if iterations = 3,
ahp.harker changes the first, second, and third most
inconsistent pairwise comparisons using that method. Researchers should
think carefully how many pairwise comparisons should be replaced, as
every time a pairwise comparison is replaced, some information is
inevitably lost. Note that the maximum number of iterations is capped at
\(iterations \leq \frac{1}{2}n(n-1)\)
with \(n\) being the number of
attributes.
stopcr: The stopping Consistency Ratio. It
complements iterations by giving iterations a
criteria to stop when a matrix is sufficiently consistent.
ahp.harker will continue looping and replacing more
elements of the pairwise comparison matrices until the consistency ratio
of the new matrix is lower than stopcr, or the maximum
number of iterations is reached, and will stop and move onto the next
individual. When stopcr is set, the number of replaced
elements will differ amongst each decision-maker. Thus, it is advised
that the analyst set printiter = TRUE to see how many
iterations has the pairwise matrix of that individual has been modified
by the algorithm.
limit: In many cases, the algorithm will intend to
replace a value with a number higher than 9 or lower than \(\frac{1}{9}\). limit caps the
maximum and minimum value of the replacement to 9 and \(\frac{1}{9}\) respectively.
printiter is a logical argument of whether the
number of iterations taken for each pairwise matrix is reported or not.
Generally it is not needed if stopcr is not specified. When
stopcr is specified, this is a good way of identifying how
many pairwise comparisons are actually replaced by the algorithm for
each decision maker. The printout above shows
"Ind 1 Iterations: 1", which shows that although I
specified iterations = 10, individual 1
(Ind 1) was only iterated one time before it reached the
target consistency ratio, 0.1. Only one element was
replaced.
The following code will demonstrate how ahp.harker
improved the consistency of the decision-makers in our collected
data.
n_iterations <- length(atts)*(length(atts)-1)/2
crmat <- matrix(NA, nrow = nrow(AHP_data), ncol = n_iterations + 1)
colnames(crmat) <- 0:n_iterations
crmat[,1] <- AHP_data %>%
ahp.mat(atts, negconvert = TRUE) %>%
ahp.cr(atts)
for (it in 1:n_iterations){
crmat[,it+1] <- AHP_data %>%
ahp.mat(atts, negconvert = TRUE) %>%
ahp.harker(atts, iterations = it, stopcr = 0.1,
limit = T, round = T, printiter = F) %>%
ahp.cr(atts)
}
data.frame(table(crmat[,1] <= 0.1),
table(crmat[,3] <= 0.1),
table(crmat[,5] <= 0.1),
table(crmat[,7] <= 0.1),
table(crmat[,9] <= 0.1),
table(crmat[,11] <= 0.1),
table(crmat[,13] <= 0.1),
table(crmat[,15] <= 0.1)
) %>%
select(Var1, Freq, Freq.1, Freq.2, Freq.3, Freq.4, Freq.5, Freq.6, Freq.7) %>%
rename("Consistent?" = "Var1",
"No iteration" = "Freq",
"2 iterations" = "Freq.1",
"4 iterations" = "Freq.2",
"6 iterations" = "Freq.3",
"8 iterations" = "Freq.4",
"10 iterations" = "Freq.5",
"12 iterations" = "Freq.6",
"14 iterations" = "Freq.7") %>%
kable()| Consistent? | No iteration | 2 iterations | 4 iterations | 6 iterations | 8 iterations | 10 iterations | 12 iterations | 14 iterations |
|---|---|---|---|---|---|---|---|---|
| FALSE | 14 | 11 | 8 | 7 | 6 | 4 | 5 | 3 |
| TRUE | 3 | 6 | 9 | 10 | 11 | 13 | 12 | 14 |
While using Harker’s method cannot completely lower the CR of all decision-makers to desired levels, it allows researchers to keep a lot more observations; whereas we would have to truncate 14 samples, now we only have to censor 3 samples with 14 iteration.
crmat %>%
as.data.frame() %>%
gather(key = "iter", value = "cr") %>%
mutate(iter = as.integer(iter)) %>%
ggplot(aes(x = iter, y = cr, group = iter)) +
geom_hline(yintercept = 0.1, color = "red", linetype = "dashed")+
geom_jitter(alpha = 0.2, width = 0.3, height = 0, color = "turquoise4") +
geom_boxplot(fill = "transparent", color = "#808080", outlier.shape = NA) +
scale_x_continuous("Iterations", breaks = 0:n_iterations) +
scale_y_continuous("Consistency Ratio") +
theme_minimal()Figure 5. Consistency Ratios under different number of iterations with the maximum deviation method
it <- 14
thres <- 0.1
cr.df1 <- data.frame(cr = AHP_data %>%
ahp.mat(atts, negconvert = TRUE) %>%
ahp.harker(atts, iterations = it, stopcr = 0.1, limit = T, round = T, printiter = F) %>%
ahp.cr(atts))
cr.df2 <- cr.df1 %>%
mutate(rowid = seq_len(nrow(AHP_data)), cr.dum = as.factor(ifelse(. <= thres, 1, 0))) %>%
select(cr.dum, rowid)
AHP_data_mat_harker <- AHP_data %>%
ahp.mat(atts = atts, negconvert = TRUE) %>%
ahp.harker(atts, iterations = it, stopcr = 0.1, limit = T, round = T, printiter = F)Here are the individual priorities after dealing with inconsistent data
arithm_ind_harker <- ahp.indpref(AHP_data_mat_harker, atts, method = "arithmetic")
arithm_ind_harker %>% rownames_to_column('ID') %>% kable()| ID | FD | TC | SR | HC | LL | CF |
|---|---|---|---|---|---|---|
| 1 | 0.085 | 0.246 | 0.021 | 0.112 | 0.339 | 0.197 |
| 2 | 0.087 | 0.118 | 0.022 | 0.452 | 0.244 | 0.077 |
| 3 | 0.027 | 0.082 | 0.028 | 0.288 | 0.288 | 0.288 |
| 4 | 0.297 | 0.191 | 0.033 | 0.123 | 0.081 | 0.275 |
| 5 | 0.108 | 0.033 | 0.065 | 0.109 | 0.187 | 0.497 |
| 6 | 0.354 | 0.306 | 0.032 | 0.146 | 0.113 | 0.049 |
| 7 | 0.072 | 0.184 | 0.032 | 0.545 | 0.099 | 0.069 |
| 8 | 0.148 | 0.061 | 0.024 | 0.520 | 0.185 | 0.062 |
| 9 | 0.165 | 0.075 | 0.039 | 0.552 | 0.047 | 0.122 |
| 10 | 0.158 | 0.077 | 0.040 | 0.537 | 0.042 | 0.145 |
| 11 | 0.094 | 0.048 | 0.022 | 0.275 | 0.249 | 0.312 |
| 12 | 0.119 | 0.107 | 0.033 | 0.095 | 0.053 | 0.595 |
| 13 | 0.093 | 0.052 | 0.025 | 0.201 | 0.105 | 0.523 |
| 14 | 0.089 | 0.232 | 0.039 | 0.371 | 0.146 | 0.123 |
| 15 | 0.309 | 0.039 | 0.380 | 0.129 | 0.024 | 0.120 |
| 16 | 0.030 | 0.121 | 0.031 | 0.404 | 0.068 | 0.348 |
| 17 | 0.347 | 0.055 | 0.062 | 0.300 | 0.083 | 0.153 |
Here are the aggregated priorities after dealing with inconsistent data
arithm_agg_harker <- ahp.aggpref(AHP_data_mat_harker, atts, method = "arithmetic", aggmethod = "arithmetic")
arithm_agg_harker %>% t() %>% kable()| FD | TC | SR | HC | LL | CF |
|---|---|---|---|---|---|
| 0.152 | 0.119 | 0.055 | 0.303 | 0.138 | 0.233 |
As of version 0.3.0, you can quickly execute most of the functions
described in this vignette with a canned routine. Here I demonstrate how
the AHP_data dataset is processed using the AHP to output
the aggregated and individual priorities of individuals, using the
arithmetic mean method.
Here are the individual priorities:
canned <- ahp(df = as.data.frame(AHP_data),
atts = atts,
negconvert = TRUE,
reciprocal = TRUE,
method = 'arithmetic',
aggmethod = "arithmetic",
agg = TRUE)
canned$indpref %>% rownames_to_column('ID') %>% kable()| ID | FD | TC | SR | HC | LL | CF | CR | top1 | top2 | top3 |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 0.123 | 0.292 | 0.021 | 0.111 | 0.316 | 0.137 | 0.194 | FD_CF | HC_CF | FD_HC |
| 2 | 0.102 | 0.110 | 0.021 | 0.520 | 0.183 | 0.064 | 0.167 | HC_LL | TC_HC | HC_CF |
| 3 | 0.040 | 0.097 | 0.021 | 0.361 | 0.282 | 0.199 | 0.262 | TC_HC | TC_CF | FD_HC |
| 4 | 0.419 | 0.118 | 0.020 | 0.193 | 0.072 | 0.178 | 0.622 | HC_LL | FD_TC | LL_CF |
| 5 | 0.224 | 0.058 | 0.053 | 0.075 | 0.076 | 0.514 | 0.344 | TC_SR | LL_CF | TC_CF |
| 6 | 0.428 | 0.218 | 0.030 | 0.189 | 0.088 | 0.047 | 0.140 | HC_LL | FD_LL | FD_TC |
| 7 | 0.094 | 0.186 | 0.037 | 0.519 | 0.099 | 0.064 | 0.132 | HC_LL | HC_CF | TC_HC |
| 8 | 0.187 | 0.083 | 0.022 | 0.496 | 0.160 | 0.052 | 0.167 | TC_HC | FD_TC | HC_LL |
| 9 | 0.165 | 0.075 | 0.039 | 0.552 | 0.047 | 0.122 | 0.082 | HC_LL | SR_LL | TC_HC |
| 10 | 0.232 | 0.113 | 0.061 | 0.454 | 0.072 | 0.069 | 0.571 | SR_LL | HC_LL | TC_HC |
| 11 | 0.094 | 0.048 | 0.022 | 0.275 | 0.249 | 0.312 | 0.091 | TC_HC | TC_CF | FD_TC |
| 12 | 0.200 | 0.144 | 0.022 | 0.096 | 0.048 | 0.489 | 0.362 | LL_CF | HC_LL | TC_CF |
| 13 | 0.136 | 0.087 | 0.027 | 0.238 | 0.051 | 0.461 | 0.216 | LL_CF | HC_LL | TC_HC |
| 14 | 0.089 | 0.232 | 0.039 | 0.371 | 0.146 | 0.123 | 0.081 | HC_LL | HC_CF | FD_HC |
| 15 | 0.317 | 0.037 | 0.398 | 0.124 | 0.023 | 0.101 | 0.210 | SR_LL | TC_SR | SR_HC |
| 16 | 0.032 | 0.153 | 0.027 | 0.482 | 0.048 | 0.259 | 0.264 | HC_LL | TC_HC | LL_CF |
| 17 | 0.433 | 0.050 | 0.060 | 0.226 | 0.081 | 0.150 | 0.127 | TC_SR | FD_TC | FD_LL |
You can also see clearly the individual priorities calculated using the arithmetic mean method, the consistency ratio of each individual, and which three pairwise comparisons are the most inconsistent.
Here are the aggregated priorities:
canned$aggpref %>% t() %>% kable()| FD | TC | SR | HC | LL | CF | |
|---|---|---|---|---|---|---|
| AggPref | 0.195 | 0.124 | 0.054 | 0.311 | 0.120 | 0.197 |
| SD.AggPref | 0.132 | 0.072 | 0.090 | 0.168 | 0.089 | 0.157 |
The most preference is Health care.
canned$aggpref %>%
as.data.frame() %>%
rownames_to_column() %>%
ggplot(aes(x = rowname, y = AggPref, fill = rowname)) +
geom_col() +
gghighlight(rowname == rownames(canned$aggpref)[which.max(canned$aggpref)]) +
labs(x = 'Factor of e-Palette', y = 'Aggregated Preference') +
theme(legend.position = "none")Figure 6. The most aggregate prefered factor of e-Palette before excluding observations having inconsistency
You can also quickly censor inconsistent observations and estimate
the aggregated preference weight of the population, and its standard
deviation. The unique command here in this canned routine is
censorcr, where you may specify the consistency ratio
censoring threshold, which allows you to remove observations a higher
consistency ratio than you specified. Usually, researchers censor
observations with a CR higher than 0.1. But sometimes
it is different depending on your discipline. Note that specifying
qt only affects aggpref calculation, and does
not censor the observations in $indpref.
Here are the number of observations that were excluded because of the inconsistency in their responses.
canned1 <- ahp(df = as.data.frame(AHP_data),
atts = atts,
negconvert = TRUE,
reciprocal = TRUE,
method = 'arithmetic',
aggmethod = "arithmetic",
qt = 0.2,
censorcr = 0.1,
agg = TRUE)## [1] "Number of observations censored = 14"
Here are the individual priorities:
canned1$indpref %>% rownames_to_column('ID') %>% kable()| ID | FD | TC | SR | HC | LL | CF | CR | top1 | top2 | top3 |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 0.165 | 0.075 | 0.039 | 0.552 | 0.047 | 0.122 | 0.082 | SR_HC | FD_HC | FD_SR |
| 2 | 0.094 | 0.048 | 0.022 | 0.275 | 0.249 | 0.312 | 0.091 | FD_LL | TC_LL | HC_CF |
| 3 | 0.089 | 0.232 | 0.039 | 0.371 | 0.146 | 0.123 | 0.081 | FD_LL | TC_HC | FD_TC |
Here are the aggregated priorities:
canned1$aggpref %>% t() %>% kable() | FD | TC | SR | HC | LL | CF | |
|---|---|---|---|---|---|---|
| AggPref | 0.116 | 0.118 | 0.033 | 0.399 | 0.147 | 0.186 |
| SD.AggPref | 0.042 | 0.099 | 0.010 | 0.141 | 0.101 | 0.110 |
The most preference is also Health care.
canned1$aggpref %>%
as.data.frame() %>%
rownames_to_column() %>%
ggplot(aes(x = rowname, y = AggPref, fill = rowname)) +
geom_col() +
gghighlight(rowname == rownames(canned$aggpref)[which.max(canned$aggpref)]) +
labs(x = 'Factor of e-Palette', y = 'Aggregated Preference') +
theme(legend.position = "none")Figure 7. The most aggregate prefered factor of e-Palette after excluding observations having inconsistency
REFERENCES