File size: 5,005 Bytes
fa7b8b5
 
 
 
 
 
 
94ba0ac
fa7b8b5
94ba0ac
fa7b8b5
 
94ba0ac
 
 
 
fa7b8b5
 
94ba0ac
fa7b8b5
94ba0ac
 
3c2a2dc
94ba0ac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa7b8b5
 
 
94ba0ac
 
 
 
 
 
 
 
 
 
 
fa7b8b5
 
94ba0ac
fa7b8b5
b6f5dd4
 
94ba0ac
b6f5dd4
94ba0ac
 
 
e46c84a
 
94ba0ac
08aba45
94ba0ac
 
 
714bb14
94ba0ac
 
 
fa7b8b5
 
714bb14
94ba0ac
714bb14
94ba0ac
 
 
 
714bb14
94ba0ac
 
 
 
 
 
 
 
 
 
 
 
fa7b8b5
 
 
 
b1ead6c
 
fa7b8b5
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import gradio as gr
import pandas as pd
import numpy as np
import json
from io import StringIO


def adjust_population_by_distance(df_distances, df_population, distance_threshold, decay_factor):
    """
    Adjusts the population of each origin based on the distance to any destination, applying a decay effect for distances beyond the threshold.

    Parameters:
    - df_distances (pd.DataFrame): DataFrame with distances from origins to destinations.
    - df_population (pd.Series): Series with population for each origin.
    - distance_threshold (float): Distance beyond which the decay effect is applied.
    - decay_factor (float): Factor controlling the rate of decay in willingness to travel beyond the threshold.

    Returns:
    - pd.Series: Adjusted population for each origin.
    """
    # Calculate the minimum distance from each origin to any destination
    min_distance = df_distances.min(axis=1)

    # Adjust the population based on the minimum distance and the decay factor
    def adjustment_factor(distance):
        if distance > distance_threshold:
            return np.exp(-(distance - distance_threshold) * decay_factor)
        else:
            return 1

    adjustment_factors = min_distance.apply(adjustment_factor)
    return df_population * adjustment_factors

def huff_model_probability(df_distances, df_attractiveness, alpha, beta, df_population=None, distance_threshold=None, decay_factor=0.1):
    """
    Calculates the probability of choosing among destinations based on an enhanced Huff model that considers a willingness to travel threshold and applies a decay effect for distances beyond this threshold.

    Parameters:
    - df_distances (pd.DataFrame): DataFrame where rows are origins, columns are destinations, and values are distances.
    - df_attractiveness (pd.Series): Series with attractiveness weights for each destination.
    - alpha (float): Attractiveness parameter of the Huff model.
    - beta (float): Distance decay parameter of the Huff model.
    - df_population (pd.Series, optional): Series with population for each origin. Defaults to 1 if not provided.
    - distance_threshold (float, optional): Distance beyond which the decay effect on willingness to travel is applied.
    - decay_factor (float, optional): Factor controlling the rate of decay in willingness to travel beyond the threshold.

    Returns:
    - pd.DataFrame: DataFrame with probabilities of choosing each destination from each origin.
    """
    if df_population is None:
        df_population = pd.Series(np.ones(df_distances.shape[0]), index=df_distances.index)

    if distance_threshold is not None:
        df_population = adjust_population_by_distance(df_distances, df_population, distance_threshold, decay_factor)

    attractiveness_term = df_attractiveness ** alpha
    distance_term = df_distances ** -beta

    numerator = (attractiveness_term * distance_term).multiply(df_population, axis=0)
    denominator = numerator.sum(axis=1)
    probabilities = numerator.div(denominator, axis=0)

    return probabilities

def app_function(input_json):
    print("Received input")
    # Parse the input JSON string
    try:
        inputs = json.loads(input_json)
    except json.JSONDecodeError:
        inputs = json.loads(input_json.replace("'", '"'))
    print("Parsed input keys:", inputs.keys())

    # Assuming the input structure is correctly formatted to include the necessary parameters
    inputs = inputs["input"]

    # Convert 'df_distances' from a list of lists into a DataFrame
    df_distances = pd.DataFrame(inputs["df_distances"])
    print("df_distances shape:", df_distances.shape)
    
    # Convert 'df_attractiveness' into a Series
    df_attractiveness = pd.Series(inputs["df_attractiveness"])
    print("df_attractiveness shape:", df_attractiveness.shape)
    
    # Extract alpha and beta parameters
    alpha = inputs["alpha"]
    beta = inputs["beta"]
    
    # Check if 'df_population' is provided and convert to Series, else default to None
    df_population = pd.Series(inputs["df_population"]) if "df_population" in inputs else None

    # Additional parameters for the updated Huff model
    distance_threshold = inputs.get("distance_threshold", None)
    decay_factor = inputs.get("decay_factor", 0.1)  # Default decay factor if not provided
    
    # Call the updated Huff model function
    probabilities = huff_model_probability(
        df_distances=df_distances,
        df_attractiveness=df_attractiveness,
        alpha=alpha,
        beta=beta,
        df_population=df_population,
        distance_threshold=distance_threshold,
        decay_factor=decay_factor
    )

    return probabilities.to_json(orient='split')

# Define the Gradio interface with a single JSON input
iface = gr.Interface(
    fn=app_function,
    inputs=gr.Textbox(label="Input JSON", lines=20, placeholder="Enter JSON with all parameters here..."),
    outputs=gr.JSON(label="Output JSON"),
    title="Dynamic Huff Model"
)

iface.launch()