| huff | R Documentation |
Computes probability surfaces to predict market share and sales potential based on distance decay and store attractiveness. The Huff model is widely used in retail site selection to estimate the probability that a consumer at a given location will choose a particular store.
huff(
demand,
stores,
attractiveness_col,
attractiveness_exponent = 1,
distance_exponent = -1.5,
sales_potential_col = NULL,
cost_matrix = NULL,
distance_metric = "euclidean"
)
demand |
An sf object representing demand points or areas. Can be customer locations, census block groups, grid cells, etc. |
stores |
An sf object representing store/facility locations. |
attractiveness_col |
Character vector. Column name(s) in |
attractiveness_exponent |
Numeric vector. Exponent(s) for attractiveness
(default 1). Must be same length as |
distance_exponent |
Numeric. Distance decay exponent (default -1.5). Should be negative; more negative = faster decay with distance. |
sales_potential_col |
Optional character. Column name in |
cost_matrix |
Optional. Pre-computed distance/cost matrix (demand x stores). If NULL, Euclidean distance is computed from geometries. |
distance_metric |
Distance metric if cost_matrix is NULL: "euclidean" (default) or "manhattan". |
The Huff model calculates the probability that a consumer at location i will choose store j using:
P_{ij} = \frac{A_j \times D_{ij}^\beta}{\sum_k A_k \times D_{ik}^\beta}
Where:
A_j is the composite attractiveness of store j
D_{ij} is the distance from i to j
\beta is the distance decay exponent (default -1.5)
When multiple attractiveness variables are specified, the composite attractiveness is computed as:
A_j = \prod_m V_{jm}^{\alpha_m}
Where V_{jm} is the value of attractiveness variable m for store j,
and \alpha_m is the corresponding exponent.
The distance exponent is typically negative because probability decreases with distance. Common values range from -1 to -3.
A list with:
$demand: Original demand sf with added columns:
.primary_store: ID of highest-probability store
.entropy: Competition measure (higher = more competition)
.prob_<store_id>: Probability columns for each store
$stores: Original stores sf with added columns:
.market_share: Proportion of total market captured
.expected_sales: Expected sales (sum of prob × potential)
$probability_matrix: Full probability matrix (n_demand × n_stores)
Metadata in "spopt" attribute includes parameters used.
Market Share: The weighted average probability across all demand points, representing the proportion of total market potential captured by each store.
Expected Sales: The sum of (probability × sales_potential) for each store, representing the expected sales volume.
Entropy: A measure of local competition. Higher entropy indicates more competitive areas where multiple stores have similar probabilities.
Huff, D. L. (1963). A Probabilistic Analysis of Shopping Center Trade Areas. Land Economics, 39(1), 81-90. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.2307/3144521")}
Huff, D. L. (1964). Defining and Estimating a Trading Area. Journal of Marketing, 28(3), 34-38. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1177/002224296402800307")}
library(sf)
# Create demand grid with spending potential
demand <- st_as_sf(expand.grid(x = 1:10, y = 1:10), coords = c("x", "y"))
demand$spending <- runif(100, 1000, 5000)
# Existing stores with varying sizes (attractiveness)
stores <- st_as_sf(data.frame(
id = c("Store_A", "Store_B", "Store_C"),
sqft = c(50000, 25000, 75000),
parking = c(200, 100, 300),
x = c(2, 8, 5), y = c(2, 8, 5)
), coords = c("x", "y"))
# Single attractiveness variable
result <- huff(demand, stores,
attractiveness_col = "sqft",
distance_exponent = -2,
sales_potential_col = "spending")
# Multiple attractiveness variables with different exponents
# Composite: A = sqft^1.0 * parking^0.5
result_multi <- huff(demand, stores,
attractiveness_col = c("sqft", "parking"),
attractiveness_exponent = c(1.0, 0.5),
distance_exponent = -2,
sales_potential_col = "spending")
# View market shares
result_multi$stores[, c("id", "sqft", "parking", ".market_share", ".expected_sales")]
# Evaluate a new candidate store
candidate <- st_as_sf(data.frame(
id = "New_Store", sqft = 40000, parking = 250, x = 3, y = 7
), coords = c("x", "y"))
all_stores <- rbind(stores, candidate)
result_with_candidate <- huff(demand, all_stores,
attractiveness_col = c("sqft", "parking"),
attractiveness_exponent = c(1.0, 0.5),
distance_exponent = -2,
sales_potential_col = "spending")
# Compare market shares with and without candidate
result_with_candidate$stores[, c("id", ".market_share")]
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.