---
title: "A Quantified Kraljic Matrix"
author: "Bradley C. Boehmke"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{A Quantified Kraljic Matrix}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

Purchasing strategies are a significant contributing factor to the overall performance of a firm. Not only has it been argued that transitioning purchasing from a tactical to a strategic role provides sustainable competitive advantage, compelling evidence supports the relationship between strategic purchasing and supplier integration, performance, power, and total cost of ownership among other benefits. Consequently, it has become widely accepted that establishing a strategic purchasing approach is imperative for today’s firm. 

Towards this goal, the most established portfolio model in literature and practice is Kraljic’s model[^kraljic] known as the Kraljic Portfolio Matrix (KPM). However, one of the primary weaknesses of the KPM is the qualitative nature of the model, which results in a subjective method for weighting and positioning suppliers or commodities in the quadrants of the KPM. The purpose of this paper is to illustrate how the `kraljicMatrix` package can be used as a quantitative framework to objectively position purchases in the KPM matrix along with identifying which products and services to begin strategic sourcing efforts with.

# The Kraljic Portfolio Matrix

Kraljic (1983) introduced the first comprehensive portfolio approach for purchasing and supply management.  Although other models have been developed, Kraljic’s KPM approach has become the dominant methodology built upon in literature and the foundation for purchasing strategies for many organizations. Kraljic’s approach leverages a portfolio matrix that classifies products on the basis of two dimensions: the external dimension (‘Supply Risk’) concerns the factors regarding suppliers and supply market, while the internal dimension (‘Profit Impact’) relates to the importance and profit impact of a given product. Each dimension needs to be assessed against a number of variables where an overall classification score (‘low’ and ‘high’) is established. The result is a  matrix and a classification in four categories: non-critical, leverage, bottleneck, and strategic items as illustrated in Figure 1. This categorization allows commodities to be classified in a way that minimizes the supply risk while maximizing purchasing power and profits of the firm. Furthermore, positioning commodities in this matrix form not only enables managers to visually see trade-offs between items, but the classification also allows firms to develop distinctive management approaches for each category.[^gelderman]

<center>
<img src="images/kpm.png" alt="Kraljic Portfolio Matrix" style="width:80%;height:80%;">
</center>

# A Quantitative Approach for Positioning

A significant question in applying the KPM is how to categorize purchased products and services within the matrix. Organizations vary in how they measure supply risk and profit impact.  Furthermore, some organizations may choose to measure their purchases against different dimensions; however, the fundamental purpose of the matrix remains.  For our purpose, we assume that the organization has developed a means to condense their measurement of each dimension to a single value.  For example, many organizations use an index (i.e. IBIS*World* Buyer Power Score) to measure one of the dimensions. Or some organizations develop an indexed value function that generates a single value score for many attributes (i.e. profit impact can be a function of volume purchased, expected growth in demand, percent of total purchase cost, impact on product quality and business growth, etc.).  However, once you have a single value that represents each dimension, subjectivity still largely drives how they are positioned in the KPM.  The `kraljicMatrix` package was designed to assist with this concern and the examples that follow walk you through how to implement `kraljicMatrix` functions. 

## Primary functions in `kraljicMatrix`

There are ten primary functions provided by `kraljicMatrix` as follows:

Function              | Purpose
----------------------|----------------------------------------------------
`SAVF_score`          | Computes a utility score based on an exponential single attribute value function.
`SAVF_preferred_rho`  | Computes the preferred rho that minimizes the squared error between subject matter inputs and exponentially fitted utility scores.
`SAVF_plot_rho_error` | Plots the squared error terms for the rho search space to illustrate the preferred rho that minimizes the squared error between subject matter desired values and exponentially fitted scores.
`SAVF_plot`           | Plots the single attribute utility curve along with the subject matter desired values for comparison.
`MAVF_score`          | Computes the multi-attribute value score based on `x` and `y` attribute utility scores and their respective weights.
`MAVF_sensitivity`    | Computes summary statistics for multi-attribute value scores for `x` and `y` given a range of swing weights for each attribute.
`kraljic_quadrant`    | Identifies the Kraljic purchasing matrix quadrant for each product or service based on the attribute utility scores of \code{x} and \code{y}.
`kraljic_matrix`      | Plots each product or service in the Kraljic purchasing matrix based on the attribute value score of `x` and `y`.
`get_frontier`        | Identifies and extracts the observations that have the Pareto optimal combination of `x` and `y`.
`geom_frontier`       | Plots the Pareto optimal front in a `ggplot2` object.


Furthermore, an example dataset `psc` is provided in the `kraljicMatrix` package. This data contains 200 product and service contracts (PSC).  Each PSC has an x attribute (i.e. supply risk) score from 1 (worst) to 5 (best) and y attribute (i.e. profit impact) score from 1 (worst) to 10 (best).

```{r, eval=FALSE}
psc
## # A tibble: 200 × 3
##      PSC x_attribute y_attribute
##    <chr>       <int>       <int>
## 1   D233        3.01        4.84
## 2   F352        4.34        5.64
## 3   T713        3.37        4.30
## 4   K833        2.67        5.53
## 5   Q121        3.48        4.33
## 6   C791        3.32        7.32
## 7   Y207        3.48        5.42
## 8   W439        2.47        3.35
## 9   N290        1.66        4.02
## 10  C251        1.00        7.47
## # ... with 190 more rows
```


```{r, echo=FALSE, warning=FALSE, message=FALSE}
psc <- tibble::tibble(
  PSC = c("D233", "F352", "T713", "K833", "Q121", "C791", "Y207", "W439", "N290", "C251", "U115", "Y679", "P256","B272", "Y895", "D663", "D400", "S883", "G274", "S229", "V324", "C529", "H379", "S528", "Q844", "X925", "A202", "W483", "Q507", "X898", "T845", "F318", "Y357", "Y536", "R954", "Y416", "E103", "I425", "C305", "W936", "H489", "N923", "G904", "I329", "T636", "G220", "W441", "C432", "N429", "N527", "X253", "N376", "L595", "K472", "H824", "X945", "D604", "E997", "K815", "E817", "D655", "R315", "P402", "F754", "Y853", "K960", "T856", "Z840", "H423", "Q618", "S855", "U622", "Q410", "G641", "Q255", "B187", "B238", "K980", "V809", "O854", "B455", "J637", "C309", "H426", "F973", "P184", "N763", "G691", "T373", "V761", "V437", "Y396", "S405", "I418", "R631", "I364", "D442", "D353", "J313", "Q795", "O131", "O920", "Y670", "V906", "O977", "J164", "M578", "V879", "M450", "E908", "B666", "D994", "N741", "A261", "H986", "W685", "Z776", "Z821", "A859", "S961", "E928", "F520", "X634", "B875", "C284", "X262", "V177", "C877", "D623", "M607", "P171", "E580", "I440", "D581", "E370", "M667", "G230", "G626", "G783", "N915", "X119", "Q697", "M496", "S868", "F334", "R777", "P941", "N436", "W932", "E537", "T317", "K942", "D715", "M176", "F452", "V162", "D983", "H278", "V649", "M775", "T269", "T173", "O522", "W299", "G852", "P291", "X597", "U310", "Q541", "M375", "A365", "L979", "X283", "T962", "E808", "A363", "I617", "B829", "G698", "B188", "U646", "O288", "T127", "C901", "I116", "V870", "S346", "J758", "S965", "E619", "I682", "M354", "H562", "K482", "L568", "Z491", "A668", "T203", "J332", "G362"), 
  x_attribute = c(3.01, 4.34, 3.37, 2.67, 3.48, 3.32, 3.48, 2.47, 1.66, 1.00, 1.40, 2.99, 4.93, 1.62, 1.00, 3.42, 2.66, 1.31, 3.24, 1.45, 2.70, 1.61, 3.99, 2.40, 1.77, 3.92, 2.88, 2.75, 3.37, 2.53, 2.94, 4.68, 5.00, 4.01, 1.18, 1.00, 4.46, 3.54, 1.00, 1.43, 1.00, 2.57, 2.41, 1.90, 3.39, 3.43, 2.84, 4.65, 3.95, 3.01, 1.69, 2.11, 3.73, 3.84, 1.33, 4.18, 3.25, 5.00, 2.85, 4.31, 2.95, 2.52, 5.00, 2.49, 1.64, 3.96, 2.57, 4.74, 2.46, 3.13, 4.32, 1.41, 4.66, 3.05, 4.95, 1.71, 2.03, 3.18, 2.05, 1.89, 2.42, 4.66, 4.12, 5.00, 3.46, 3.56, 3.30, 2.01, 4.22, 3.86, 4.24, 2.15, 3.28, 4.21, 2.35, 2.36, 2.83, 2.60, 2.60, 1.16, 2.37, 4.48, 3.98, 1.00, 3.88, 1.22, 2.31, 3.82, 2.57, 4.75, 3.51, 4.58, 3.82, 3.83, 2.67, 3.95, 4.53, 3.70, 3.75, 3.47, 3.18, 4.21, 5.00, 4.00, 4.91, 2.70, 2.28, 1.00, 1.00, 2.95, 3.40, 4.06, 1.22, 1.61, 3.48, 3.53, 2.41, 3.42, 2.60, 3.87, 2.62, 5.00, 3.76, 1.64, 2.68, 1.78, 1.56, 2.67, 3.80, 2.98, 2.46, 4.81, 4.03, 3.22, 5.00, 2.74, 1.86, 4.43, 3.31, 2.28, 4.01, 3.99, 2.21, 2.25, 2.72, 3.31, 4.54, 3.67, 4.19, 2.23, 3.49, 3.80, 5.00, 2.28, 3.97, 3.42, 2.10, 1.88, 2.02, 3.89, 1.00, 5.00, 2.60, 3.80, 4.32, 5.00, 3.01, 4.17, 2.46, 5.00, 2.38, 2.37, 2.13, 2.41, 1.74, 1.00, 3.78, 1.00, 3.07, 2.29),
  y_attribute = c(4.84, 5.64, 4.30, 5.53, 4.33, 7.32, 5.42, 3.35, 4.02, 7.47, 6.58, 1.00, 3.04, 2.46, 4.91, 5.49, 4.72, 5.73, 8.98, 7.57, 3.30, 2.65, 4.76, 5.75, 5.76, 4.60, 2.44, 7.98, 8.82, 5.11, 3.44, 4.23, 6.55, 1.75, 4.80, 6.32, 7.71, 3.50, 5.49, 6.52, 5.06, 2.48, 4.45, 5.60, 6.58, 2.79, 6.58, 6.05, 7.60, 3.51, 4.75, 4.83, 4.12, 7.88, 4.45, 6.83, 1.34, 1.53, 4.04, 6.55, 6.64, 6.24, 5.82, 5.67, 4.97, 4.04, 5.21, 4.87, 5.52, 4.02, 4.89, 5.46, 5.54, 1.40, 6.41, 2.46, 5.53, 6.90, 6.47, 5.93, 4.66, 3.15, 2.66, 5.58, 3.91, 5.09, 6.18, 2.63, 6.93, 1.20, 4.67, 6.77, 5.19, 6.15, 2.38, 6.78, 5.91, 5.74, 4.51, 4.56, 6.65, 4.32, 3.76, 6.34, 6.74, 5.23, 1.00, 5.03, 4.39, 7.11, 6.11, 4.52, 3.93, 6.76, 4.34, 6.46, 5.05, 7.75, 1.54, 1.10, 7.36, 4.61, 5.19, 4.92, 2.07, 6.54, 5.81, 8.37, 6.50, 4.22, 3.00, 6.68, 4.99, 4.88, 5.27, 3.71, 1.36, 3.37, 6.80, 4.70, 5.27, 4.19, 7.50, 2.86, 1.18, 6.96, 4.40, 3.98, 3.58, 3.00, 3.06, 1.50, 4.17, 4.42, 4.36, 6.96, 5.51, 3.86, 7.40, 5.63, 4.08, 5.04, 7.29, 9.54, 2.72, 5.77, 6.23, 5.50, 4.32, 3.00, 3.30, 6.41, 4.52, 4.74, 6.46, 2.99, 6.77, 6.16, 6.28, 3.63, 10.00, 5.00, 8.18, 4.76, 7.30, 5.88, 8.21, 7.48, 6.02, 3.65, 7.21, 2.66, 5.15, 6.38, 5.95, 5.74, 4.30, 2.96, 5.89, 2.63)
)
```


## Implementation of `kraljicMatrix`

The x and y attributes are simply evaluation measures. They enable each product and service to obtain a score for each dimension being measured. For example, the x attribute score (1-5 in .01 increments) could be the IBIS*World* Buyer Power Score measuring supply market complexity.  However, to plot these attributes on the KPM matrix we need to normalize the value scores such that the values are between 0-1.  To do this we can use an exponential single attribute value function (SAVF). For example, let $v_x(x_i)$ represent the normalized value of the x attribute such that $x^0$ and $x^*$ are the lowest and highest preferred value of attribute x respectively.  Thus, $v_x(x^0)=0$ and $v_x(x^*)=1$. Consequently, let $v_x(x_i)$ be the SAVF of exponential form whereby each $x_i$ is an input and $\rho_x$ is the exponential constant for $v_x(x_i)$:

$$v_x(x_i)=\frac{1-e^{[-(x_i-x^0)/\rho_x]}}{1-e^{[-(x^*-x^0)/\rho_x]}} \forall i \in PSC$$

However, prior to applying the SAVF to our x and y attributes we must first identify the appropriate $\rho$ value.  The benefit of applying an exponential SAVF is that it can take on many forms of increasing rates, along with aligning to a linear value function. Consequently, if certain x attribute values are valued more than other values an exponential SAVF will capture this utility curve. To identify the appropriate exponential rate, subject matter expert (SME) inputs are typically evaluated and an exponential rate that most closely matches the preffered values provided by the SMEs is chosen. Thus, let's assume for our given x attribute the SME inputs suggest that x attribute values of 3, 4, & 5 provide a utility score of .75, .90 & 1.0 respectively (this represents a decreasing rate of return utility curve).  Knowing that our x attribute is bounded between 1 and 5 we can search for a rho value between 0-1 that provides the best fit utility function using the `SAVF_preferred_rho` function. 

```{r, eval=FALSE}
SAVF_preferred_rho(desired_x = c(3, 4, 5),
                   desired_v = c(.8, .9, 1),
                   x_low = 1,
                   x_high = 5,
                   rho_low = 0,
                   rho_high = 1)
## [1] 0.6531
```

Thus, we can see that $\rho = 0.6531$ provides the best fit exponential SAVF. We can illustrate this two ways.  First, we can use `SAVF_plot` to plot the single attribute utility curve compared to the subject matter desired values. 

```{r, echo=FALSE}
SAVF_score <- function(x, x_low, x_high, rho){

  # return error if x_low is not less than x_high
  if(x_low >= x_high){
    stop("`x_low` must be less than `x_high`", call. = FALSE)
  }

  # return error if rho is not a single value
  if (length(rho) != 1) {
    stop("`rho` must be a numeric value of length 1", call. = FALSE)
  }

  # generate SAVF values
  value <- (1 - exp(-rho * (x - x_low))) / (1 - exp(-rho * (x_high - x_low)))

  # return values
  return(value)

}

SAVF_plot <- function(desired_x, desired_v, x_low, x_high, rho){

  # return error if x_low is not less than x_high
  if(x_low >= x_high){
    stop("`x_low` must be less than `x_high`", call. = FALSE)
  }

  # return error if rho is not a single value
  if (length(rho) != 1) {
    stop("`rho` must be a numeric value of length 1", call. = FALSE)
  }

  # create string of x values
  x <- seq(x_low, x_high, by = (x_high - x_low) / 1000)
  v <- SAVF_score(x, x_low, x_high, rho)

  # create data frames to plot
  df <- data.frame(x = x, v = v)
  desired <- data.frame(x = desired_x, v = desired_v)

  ggplot2::ggplot(df, ggplot2::aes(x, v)) +
    ggplot2::geom_line() +
    ggplot2::geom_point(data = desired, ggplot2::aes(x, v), shape = 23, size = 2, fill = "white")

}
```

```{r, fig.align='center', fig.height=3, fig.width=6}


SAVF_plot(desired_x = c(3, 4, 5),
          desired_v = c(.8, .9, 1),
          x_low = 1,
          x_high = 5,
          rho = 0.6531)
```

We can also visualize the errors of the $\rho$ search space with `SAVF_plot_rho_error`, which plots the squared error terms for all $\rho$ values within the $\rho$ search space to illustrate the preferred rho that minimizes the squared error between subject matter desired values and exponentially fitted scores. 

```{r, echo=FALSE}
SAVF_plot_rho_error <- function(desired_x, desired_v, x_low, x_high, rho_low, rho_high){

  # return error if x_low is not less than x_high
  if(x_low >= x_high){
    stop("`x_low` must be less than `x_high`", call. = FALSE)
  }

  # return error if rho_low is not less than rho_high
  if(rho_low >= rho_high){
    stop("`rho_low` must be less than `rho_high`", call. = FALSE)
  }

  # compute sequence of rho values
  rho <- seq(rho_low, rho_high, by = (rho_high - rho_low) / 10000)
  rho <- rho[rho != 0]

  # compute deltas between preferred and fitted values
  delta <- sapply(rho, function(x) sum((SAVF_score(desired_x, x_low, x_high, x) - desired_v)^2))

  # return rho that produces smallest error
  true_rho <- rho[which(delta == min(delta))]

  # plot value
  df <- data.frame(rho = rho, delta = delta)
  ggplot2::ggplot(df, ggplot2::aes(rho, delta)) +
    ggplot2::geom_line() +
    ggplot2::geom_point(ggplot2::aes(true_rho, min(delta)), shape = 23, size = 2, fill = "white")

}
```

```{r, fig.align='center', fig.height=3, fig.width=6}
SAVF_plot_rho_error(desired_x = c(3, 4, 5),
                    desired_v = c(.75, .9, 1),
                    x_low = 1,
                    x_high = 5,
                    rho_low = 0,
                    rho_high = 1)
```


Once we've identified the preferred $\rho$ value, we can now apply the exponential SAVF with `SAVF_score` to normalize our attributes based on our utility curve. 

```{r, echo=FALSE}
SAVF_score <- function(x, x_low, x_high, rho){

  # return error if x_low is not less than x_high
  if(x_low >= x_high){
    stop("`x_low` must be less than `x_high`", call. = FALSE)
  }

  # return error if rho is not a single value
  if (length(rho) != 1) {
    stop("`rho` must be a numeric value of length 1", call. = FALSE)
  }

  # generate SAVF values
  value <- (1 - exp(-rho * (x - x_low))) / (1 - exp(-rho * (x_high - x_low)))

  # return values
  return(value)

}
```

```{r, collapse=TRUE, message=FALSE, warning=FALSE}
# using dplyr to add a new variable while preserving existing data
library(dplyr)

# here we are assuming we found the appropriate rho value for the y attribute using
# the same process as mentioned above
psc <- psc %>%
  mutate(x_SAVF_score = SAVF_score(x_attribute, 1, 5, .653),
         y_SAVF_score = SAVF_score(y_attribute, 1, 10, .70))

psc
```

Now that we have the normalized x and y attribute utility scores we can proceed with plotting each PSC within the Kraljic matrix with `kraljic_matrix`.

```{r, echo=FALSE}
kraljic_matrix <- function(data, x, y){

  # return error if x or y are not numeric values
  x_col <- data[[deparse(substitute(x))]]
  y_col <- data[[deparse(substitute(y))]]

  if(!is.numeric(x_col) | !is.numeric(y_col)){
    stop("data for both column inputs must be numeric", call. = FALSE)
  }

  # plot Kraljic Matrix
  ggplot2::ggplot(data, ggplot2::aes_string(deparse(substitute(x)), deparse(substitute(y)))) +
    ggplot2::geom_point() +
    ggplot2::geom_vline(xintercept = .5) +
    ggplot2::geom_hline(yintercept = .5) +
    ggplot2::coord_cartesian(xlim = c(0,1), ylim = c(0,1)) +
    ggplot2::scale_x_reverse()
}
```


```{r, fig.align='center', fig.width=7, fig.height=5}
kraljic_matrix(psc, x_SAVF_score, y_SAVF_score)
```

This illustrates that most of our PSCs fall in the "Leverage" (upper left) quadrant while a few fall in the "Strategic" (upper right) and "Non-critical" (lower left) quadrants and no PSCs fall in the "Bottleneck" quadrant.  Keep in mind that each category benefits from a different strategic sourcing approach.  So decision-makers benefit from understanding specifically which products and services align to each so that they can coordinate the appropriate sourcing strategy for that particular product or service.  We can easily do this with the `kraljic_quadrant` function.

```{r, echo=FALSE}
kraljic_quadrant <- function(x, y){

  ifelse(x > .5 & y >= .5, "Leverage",
         ifelse(x > .5 & y < .5, "Critical",
                ifelse(x <= .5 & y >= .5, "Strategic",
                       ifelse(x < .5 & y < .5, "Bottleneck", NA))))

}
```

```{r, collapse=TRUE}
psc %>%
  mutate(quadrant = kraljic_quadrant(x_SAVF_score, y_SAVF_score))
```

Lastly, it is important to keep in mind that decision-makers may weight the importance of each attribute differently. Consequently, due to certain market environments, decision-makers may weight the x attribute (i.e. supply risk) of greater importance than the y attribute (i.e. profit impact). Thus, we can prioritize PSCs based on this preference by applying a multi-attribute value function (MAVF) with swing weights.  Swing weight values for x and y attributes ($w_x$ and $w_y$ respectively) are typically elicited from SMEs. This allows for calculation of the interaction swing weight $w_{xy} = 1 - w_x - w_y$.  Thus, we can calculate the MAVF as outlined by Keeney and Raiffa (1993)[^keeney]:

$$V(x,y) = w_x v_x (x) + w_y v_y (y) + w_{xy} v_x (x) v_y (y)$$

Thus, we can apply the `MAVF_score` function to compute the multi-attribute value score based on `x` and `y` attribute utility scores and their respective swing weights. So if through discussions with decision-makers we identify swing weight values of 0.65 and 0.35 for the x and y attributes respectively, we can obtain the computed MAVF score for each PSC:

```{r, echo=FALSE}
MAVF_score <- function(x, y, x_wt, y_wt){

  # return error if x and y are different lengths
  if(length(x) != length(y)){
    stop("`x` and `y` must be the same length", call. = FALSE)
  }

  # return error if x or y weights are not a single value
  if (length(x_wt) != 1 | length(y_wt) != 1) {
    stop("x and y weights must be numeric values of length 1", call. = FALSE)
  }

  x * x_wt + y * y_wt + (1 - x_wt - y_wt) * x * y

}
```

```{r, collapse=TRUE}
psc %>%
  mutate(MAVF = MAVF_score(x_SAVF_score, y_SAVF_score, 0.65, 0.35))
```

This allows us to quickly dissect our PSCs. For example, if decision-makers are most concerned with the "Leverage" quadrant but want to assess the top 10 PSCs based on the decision-makers preferences of the attributes we can efficiently make this assessment.  This identifies the top 10 PSCs that are most likely to benefit from a strategic sourcing approach specifically designed for "Leverage" PSCs.

```{r, collapse=TRUE}
psc %>%
  mutate(MAVF = MAVF_score(x_SAVF_score, y_SAVF_score, 0.65, 0.35),
         quadrant = kraljic_quadrant(x_SAVF_score, y_SAVF_score)) %>%
  filter(quadrant == "Leverage") %>%
  top_n(10, wt = MAVF)
```

And finally, since our swing weight inputs are subjective in nature we may wish to perform a senstivity analysis on these swing weights to see their impact on MAVF scores.  The `MAVF_sensitivity` function executes a sensitivity analysis by performing a Monte Carlo simulation with 1000 trials for each product or service (row). Each trial randomly selects a weight from a uniform distribution between lower and upper bound swing weight parameters and calculates the mult-attribute utility score. From these trials, summary statistics for each product or service (row) are calculated and reported for the final output.

```{r, echo=FALSE}
MAVF_sensitivity <- function(data, x, y, x_wt_min, x_wt_max, y_wt_min, y_wt_max){

  # return error if x_wt_min is not less than x_wt_max
  if(x_wt_min >= x_wt_max){
    stop("`x_wt_min` must be less than `x_wt_max`", call. = FALSE)
  }

  # return error if y_wt_min is not less than y_wt_max
  if(y_wt_min >= y_wt_max){
    stop("`y_wt_min` must be less than `y_wt_max`", call. = FALSE)
  }

  # create random wts
  x_wt <- runif(1000, min = x_wt_min, max = x_wt_max)
  y_wt <- runif(1000, min = y_wt_min, max = y_wt_max)
  w_wt <- 1 - x_wt - y_wt

  # parse out vectors from data
  x_col <- data[[deparse(substitute(x))]]
  y_col <- data[[deparse(substitute(y))]]

  # create vectors to fill
  Min. <- vector(mode = "numeric", length = nrow(data))
  `1st Qu.` <- vector(mode = "numeric", length = nrow(data))
  Median <- vector(mode = "numeric", length = nrow(data))
  Mean <- vector(mode = "numeric", length = nrow(data))
  `3rd Qu.` <- vector(mode = "numeric", length = nrow(data))
  Max. <- vector(mode = "numeric", length = nrow(data))
  Range <- vector(mode = "numeric", length = nrow(data))

  # loop through to compute values for each x y pair
  for(i in 1:nrow(data)){
    s <- summary(x_col[i] * x_wt + y_col[i] * y_wt + (1 - x_wt - y_wt) * x_col[i] * y_col[i])
    Min.[i] <- s[1]
    `1st Qu.`[i] <- s[2]
    Median[i] <- s[3]
    Mean[i] <- s[4]
    `3rd Qu.`[i] <- s[5]
    Max.[i] <- s[6]
    Range[i] <- s[6] - s[1]
  }

  # add new columns
  data$MAVF_Min <- Min.
  data$MAVF_1st_Q <- `1st Qu.`
  data$MAVF_Median <- Median
  data$MAVF_Mean <- Mean
  data$MAVF_3rd_Q <- `3rd Qu.`
  data$MAVF_Max <- Max.
  data$MAVF_Range <- Range


  # return data
  data

}
```


```{r, collapse=TRUE}
MAVF_sensitivity(psc,
                 x = x_SAVF_score,
                 y = y_SAVF_score,
                 x_wt_min = .55,
                 x_wt_max = .75,
                 y_wt_min = .25,
                 y_wt_max = .45) %>%
  select(PSC, starts_with("MAVF"))
```


# Additional Resources

This package originated from the research illustrated in this [Kraljic Matrix paper](https://www.dropbox.com/s/vkwrirmp1bdvp66/Article%20Submitted.docx?dl=0).  Please refer to it for more details regarding Kraljic purchasing matrix literature and the single and multi-attribute value functions discussed in this vignette.



[^kraljic]: Kraljic, P. (1983). Purchasing must become supply management. *Harvard Business Review, 61*(5), 109-117.
[^gelderman]: See [Gelderman & Semeijn (2006)](http://www.sciencedirect.com/science/article/pii/S1478409206000690) and [Gelderman & Van Weele (2003)](http://www.sciencedirect.com/science/article/pii/S147840920300044X) for more discussion regarding strategic management approaches.
[^keeney]: Keeney, R., & Raiffa, H. (1993). *Decisions with multiple objectives: preferences and value trade-offs*. Cambridge University Press.



