Skip to main content

Reconciled Two-Step Floating Catchment Area Model for spatial accessibility analysis

Project description

r2SFCA: Reconciled Two-Step Floating Catchment Area Model

A Python package for spatial accessibility analysis that reconciles 2SFCA and i2SFCA methods through distance decay parameterization and cross-entropy minimization.

Authors: Lingbo Liu (lingboliu@fas.harvard.edu), Fahui Wang (fwang@lsu.edu)

Overview

The r2SFCA package implements a unified framework for spatial accessibility analysis that:

  • Reconciles demand-side (2SFCA) and supply-side (i2SFCA) accessibility measures
  • Optimizes distance decay parameters through cross-entropy minimization
  • Supports multiple decay functions with configurable parameters
  • Provides comprehensive evaluation metrics and visualization tools
  • Enables grid search and Adam optimization for parameter estimation

Installation

pip install r2sfca

Quick Start

import pandas as pd
from r2sfca import R2SFCA

# Load your spatial accessibility data
df = pd.read_csv('your_data.csv')

# Initialize the R2SFCA model
model = R2SFCA(
    df=df,
    demand_col='Demand',
    supply_col='Supply',
    travel_cost_col='TravelCost',
    demand_id_col='DemandID',
    supply_id_col='SupplyID',
    observed_flow_col='O_Fij',  # Optional, for validation
    decay_function='exponential'
)

# Calculate accessibility and crowdedness scores
accessibility = model.access_score(beta=2.5)
crowdedness = model.crowd_score(beta=2.5)

# Perform grid search to find optimal parameters
results = model.search_fij(
    beta_range=(0.0, 5.0, 0.1),
    # param2_range = (10, 20.0, 5.0),#optional for sigmoid and gaussian function
    # either parameter can be a fixed value
    metrics=['cross_entropy', 'correlation', 'rmse']
)

# Optimize parameters using Adam optimizer
optimization_result = model.solve_beta(
    metric='cross_entropy',
    # param2=20.0, #optional for sigmoid and gaussian function
    method='adam',
    num_epochs=400
)

Data Requirements

Your input dataframe should contain the following columns:

  • Demand: Demand values (e.g., population)
  • Supply: Supply values (e.g., service capacity)
  • TravelCost: Travel cost/distance between demand and supply locations
  • DemandID: Unique identifiers for demand locations
  • SupplyID: Unique identifiers for supply locations
  • O_Fij (optional): Observed flow values for model validation

Decay Functions

The package supports six distance decay functions:

1. Exponential Decay

f(d) = exp(-β * d)

2. Power Decay

f(d) = d^(-β)

3. Sigmoid Decay

f(d) = 1 / (1 + exp(steepness * (d - β)))

4. Square Root Exponential Decay

f(d) = exp(-β * sqrt(d))

5. Gaussian Decay

f(d) = exp(-β * (d/d0)²)

6. Log-Squared Decay

f(d) = exp(-β * log(d)²)

API Reference

R2SFCA Class

Constructor

R2SFCA(df, demand_col, supply_col, travel_cost_col, demand_id_col, supply_id_col, 
       observed_flow_col=None, decay_function='exponential', epsilon=1e-15)

Methods

dist_decay(beta, **kwargs)

Calculate distance decay values using the specified decay function.

Parameters:

  • beta: Primary decay parameter
  • **kwargs: Additional parameters (steepness for sigmoid, d0 for gaussian)

Note: Uses the travel_cost data stored in the model during initialization.

Returns: Decay values

fij(beta, **kwargs)

Calculate Fij values (demand-side accessibility) using 2SFCA method.

Parameters:

  • beta: Decay parameter
  • **kwargs: Additional parameters for decay function

Returns: Fij values

tij(beta, **kwargs)

Calculate Tij values (supply-side accessibility) using i2SFCA method.

Parameters:

  • beta: Decay parameter
  • **kwargs: Additional parameters for decay function

Returns: Tij values

search_fij(beta_range, param2_range=None, metrics=None, normalize=True)

Perform grid search over parameter ranges to find optimal values.

Parameters:

  • beta_range: (start, end, step) for beta parameter
  • param2_range: (start, end, step) for second parameter
  • metrics: List of evaluation metrics to calculate
  • normalize: Whether to normalize Fij and Tij for cross-entropy calculation

Returns: DataFrame with grid search results

solve_beta(metric='cross_entropy', param2=None, method='minimize', **kwargs)

Solve for optimal beta parameter using optimization.

Parameters:

  • metric: Metric to optimize
  • param2: Second parameter value
  • method: Optimization method ('minimize' or 'adam')
  • **kwargs: Additional optimization parameters

Returns: Dictionary with optimization results

access_score(beta, **kwargs)

Calculate accessibility scores (Ai) for each demand location.

Parameters:

  • beta: Decay parameter
  • **kwargs: Additional parameters for decay function

Returns: Series with accessibility scores

crowd_score(beta, **kwargs)

Calculate crowdedness scores (Cj) for each supply location.

Parameters:

  • beta: Decay parameter
  • **kwargs: Additional parameters for decay function

Returns: Series with crowdedness scores

Evaluation Metrics

The package provides several evaluation metrics:

  • Cross Entropy: Measures the difference between Fij and Tij distributions
  • Correlation: Pearson correlation coefficient between Fij and Tij
  • RMSE: Root Mean Square Error
  • MSE: Mean Square Error
  • MAE: Mean Absolute Error
  • Fij-Flow Correlation: Correlation between estimated Fij and observed flows
  • Tij-Flow Correlation: Correlation between estimated Tij and observed flows

Visualization

Grid Search Results

from r2sfca.utils import plot_grid_search_results

# Plot grid search results
fig = plot_grid_search_results(
    results_df=results,
    x_col='beta',
    y_cols=['cross_entropy', 'correlation'],
    title='Grid Search Results',
    save_path='grid_search.png'
)

Model Comparison

from r2sfca.utils import plot_model_comparison

# Compare multiple models
fig = plot_model_comparison(
    results_dfs=[results1, results2, results3],
    labels=['Gaussian', 'Exponential', 'Power'],
    y_col='fij_flow_correlation',
    title='Model Comparison',
    save_path='model_comparison.png'
)

Summary Table

from r2sfca.utils import create_summary_table

# Create summary table
summary = create_summary_table(
    results_dfs=[results1, results2, results3],
    labels=['Gaussian', 'Exponential', 'Power'],
    metric='cross_entropy',
    minimize=True
)

Examples

Example 1: Basic Usage

import pandas as pd
import numpy as np
from r2sfca import R2SFCA

# Create sample data
np.random.seed(42)
n_demand = 100
n_supply = 50

data = []
for i in range(n_demand):
    for j in range(n_supply):
        data.append({
            'DemandID': i,
            'SupplyID': j,
            'Demand': np.random.poisson(1000),
            'Supply': np.random.poisson(100),
            'TravelCost': np.random.exponential(10),
            'O_Fij': np.random.poisson(50)
        })

df = pd.DataFrame(data)

# Initialize model
model = R2SFCA(
    df=df,
    demand_col='Demand',
    supply_col='Supply',
    travel_cost_col='TravelCost',
    demand_id_col='DemandID',
    supply_id_col='SupplyID',
    observed_flow_col='O_Fij',
    decay_function='gaussian'
)

# Calculate accessibility scores
accessibility = model.access_score(beta=2.0)
print(f"Accessibility scores: {accessibility.describe()}")

Example 2: Parameter Optimization

# Grid search
results = model.search_fij(
    beta_range=(0.0, 5.0, 0.2),
    metrics=['cross_entropy', 'correlation', 'rmse']
)

# Find optimal beta
optimal_idx = results['cross_entropy'].idxmin()
optimal_beta = results.loc[optimal_idx, 'beta']
print(f"Optimal beta: {optimal_beta}")

# Adam optimization
optimization_result = model.solve_beta(
    metric='cross_entropy',
    method='adam',
    num_epochs=200
)
print(f"Optimized beta: {optimization_result['optimal_beta']}")

Example 3: Model Comparison

# Compare different decay functions
decay_functions = ['exponential', 'power', 'gaussian', 'sigmoid']
results_list = []
labels = []

for decay_func in decay_functions:
    model_temp = R2SFCA(
        df=df,
        demand_col='Demand',
        supply_col='Supply',
        travel_cost_col='TravelCost',
        demand_id_col='DemandID',
        supply_id_col='SupplyID',
        observed_flow_col='O_Fij',
        decay_function=decay_func
    )
    
    results = model_temp.search_fij(
        beta_range=(0.0, 3.0, 0.1),
        metrics=['cross_entropy', 'fij_flow_correlation']
    )
    
    results_list.append(results)
    labels.append(decay_func.title())

# Plot comparison
from r2sfca.utils import plot_model_comparison

fig = plot_model_comparison(
    results_dfs=results_list,
    labels=labels,
    y_col='fij_flow_correlation',
    title='Decay Function Comparison'
)

Advanced Usage

Custom Decay Function Parameters

# Gaussian decay with custom d0 parameter
model = R2SFCA(df, decay_function='gaussian')
fij = model.fij(beta=2.0, d0=30.0)  # Custom d0 value

# Sigmoid decay with custom steepness
model = R2SFCA(df, decay_function='sigmoid')
fij = model.fij(beta=1.5, steepness=5.0)  # Custom steepness

Multiple Parameter Optimization

# Grid search with second parameter
results = model.search_fij(
    beta_range=(0.0, 3.0, 0.1),
    param2_range=(1.0, 10.0, 0.5),  # For sigmoid steepness
    metrics=['cross_entropy', 'correlation']
)

Custom Evaluation Metrics

# Use custom metrics
results = model.search_fij(
    beta_range=(0.0, 3.0, 0.1),
    metrics=['cross_entropy', 'rmse', 'mae', 'fij_flow_correlation']
)

Performance Considerations

  • For large datasets, consider using the Adam optimizer instead of grid search
  • The package uses vectorized operations for efficiency
  • Memory usage scales with the number of demand-supply pairs
  • Consider sampling for very large datasets during parameter optimization

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Citation

If you use this package in your research, please cite:

@article{r2sfca2025,
   author = {Liu, Lingbo and Wang, Fahui},
   title = {Reconciling 2SFCA and i2SFCA via distance decay parameterization},
   journal = {International Journal of Geographical Information Science},
   pages = {1-18},
   note = {doi: 10.1080/13658816.2025.2562255},
   ISSN = {1365-8816},
   DOI = {10.1080/13658816.2025.2562255},
   url = {https://doi.org/10.1080/13658816.2025.2562255},
   year = {2025},
   type = {Journal Article}
}

Support

For questions and support, please open an issue on GitHub or contact the development team.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

r2sfca-1.1.3.tar.gz (19.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

r2sfca-1.1.3-py3-none-any.whl (15.9 kB view details)

Uploaded Python 3

File details

Details for the file r2sfca-1.1.3.tar.gz.

File metadata

  • Download URL: r2sfca-1.1.3.tar.gz
  • Upload date:
  • Size: 19.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.4

File hashes

Hashes for r2sfca-1.1.3.tar.gz
Algorithm Hash digest
SHA256 281b11f2e2420577b53c136e1f8455f16065ba855d2e396fcf2d93349086a6b2
MD5 937873f15d89b9fe8bf9deb612c2c012
BLAKE2b-256 770d2428323bf239e36c38d032a709275801c9fb6c30ef8e57ff813299d7d1d3

See more details on using hashes here.

File details

Details for the file r2sfca-1.1.3-py3-none-any.whl.

File metadata

  • Download URL: r2sfca-1.1.3-py3-none-any.whl
  • Upload date:
  • Size: 15.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.4

File hashes

Hashes for r2sfca-1.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 f5ce2fec1e04e34f2ff288a53df25026185aa5b9fb60571d23756070ea603c0b
MD5 4c50c57fbfe29d511689609f1c7fa843
BLAKE2b-256 56681e0aaed3e71a7d102d19772133a9593e0448a2b9b752908636f1906f8ecc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page