huff 1.5.1__py3-none-any.whl → 1.5.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
huff/models.py CHANGED
@@ -4,8 +4,8 @@
4
4
  # Author: Thomas Wieland
5
5
  # ORCID: 0000-0001-5168-9846
6
6
  # mail: geowieland@googlemail.com
7
- # Version: 1.5.1
8
- # Last update: 2025-07-01 17:10
7
+ # Version: 1.5.2
8
+ # Last update: 2025-07-02 21:09
9
9
  # Copyright (c) 2025 Thomas Wieland
10
10
  #-----------------------------------------------------------------------
11
11
 
@@ -1292,21 +1292,6 @@ class InteractionMatrix:
1292
1292
  print(f"Optimization via {method} algorithm succeeded with parameters: {', '.join(str(round(par, 3)) for par in param_results)}.")
1293
1293
 
1294
1294
  else:
1295
-
1296
- # param_gamma = None
1297
- # param_lambda = None
1298
-
1299
- # supply_locations_metadata["weighting"][0]["param"] = param_gamma
1300
-
1301
- # if customer_origins_metadata["weighting"][0]["func"] == "logistic":
1302
-
1303
- # param_lambda2 = None
1304
- # customer_origins_metadata["weighting"][0]["param"][0] = param_lambda
1305
- # customer_origins_metadata["weighting"][0]["param"][1] = param_lambda2
1306
-
1307
- # else:
1308
-
1309
- # customer_origins_metadata["weighting"][0]["param"] = param_lambda
1310
1295
 
1311
1296
  print(f"Optimiziation via {method} algorithm failed with error message: '{ml_result.message}'. See https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html for all available algorithms.")
1312
1297
 
@@ -1316,20 +1301,28 @@ class InteractionMatrix:
1316
1301
  if update_estimates:
1317
1302
 
1318
1303
  if "p_ij_emp" not in self.interaction_matrix_df.columns:
1304
+
1319
1305
  self.interaction_matrix_df["p_ij_emp"] = self.interaction_matrix_df["p_ij"]
1320
- print("Probabilties in interaction matrix are treated as empirical probabilties")
1306
+
1307
+ print("NOTE: Probabilities in interaction matrix are treated as empirical probabilities")
1308
+
1321
1309
  else:
1322
- print("Interaction matrix contains empirical probabilties")
1310
+
1311
+ print("NOTE: Interaction matrix contains empirical probabilities")
1323
1312
 
1324
1313
  if "E_ij_emp" not in self.interaction_matrix_df.columns:
1314
+
1325
1315
  self.interaction_matrix_df["E_ij_emp"] = self.interaction_matrix_df["E_ij"]
1326
- print("Customer interactions in interaction matrix are treated as empirical interactions")
1316
+
1317
+ print("NOTE: Customer interactions in interaction matrix are treated as empirical interactions")
1318
+
1327
1319
  else:
1328
- print("Interaction matrix contains empirical customer interactions")
1320
+
1321
+ print("NOTE: Interaction matrix contains empirical customer interactions")
1329
1322
 
1330
1323
  if np.isnan(ml_result.x).any():
1331
1324
 
1332
- print("No update of estimates because fit parameters contain NaN")
1325
+ print("WARNING: No update of estimates because fit parameters contain NaN")
1333
1326
 
1334
1327
  update_estimates = False
1335
1328
 
@@ -1391,7 +1384,7 @@ class InteractionMatrix:
1391
1384
 
1392
1385
  if "transport_costs" not in interaction_matrix_metadata:
1393
1386
 
1394
- print("New destination(s) included. No transport costs calculation because not defined in original interaction matrix.")
1387
+ print("WARNING: New destination(s) included. No transport costs calculation because not defined in original interaction matrix.")
1395
1388
 
1396
1389
  interaction_matrix_df = pd.concat(
1397
1390
  [
@@ -1625,7 +1618,6 @@ class HuffModel:
1625
1618
  print ("Goodness-of-fit for " + interaction_matrix_metadata["fit"]["fit_by"])
1626
1619
 
1627
1620
  print("Sum of squared residuals ", round(huff_modelfit[1]["SQR"], 2))
1628
- print("Sum of squares ", round(huff_modelfit[1]["SQT"], 2))
1629
1621
  print("R-squared ", round(huff_modelfit[1]["Rsq"], 2))
1630
1622
  print("Mean squared error ", round(huff_modelfit[1]["MSE"], 2))
1631
1623
  print("Root mean squared error ", round(huff_modelfit[1]["RMSE"], 2))
@@ -1853,7 +1845,8 @@ class HuffModel:
1853
1845
  bounds: list = [(0.5, 1), (-3, -1)],
1854
1846
  constraints: list = [],
1855
1847
  fit_by = "probabilities",
1856
- update_estimates: bool = True
1848
+ update_estimates: bool = True,
1849
+ check_numbers: bool = True
1857
1850
  ):
1858
1851
 
1859
1852
  if fit_by in ["probabilities", "flows"]:
@@ -1869,6 +1862,16 @@ class HuffModel:
1869
1862
 
1870
1863
  elif fit_by == "totals":
1871
1864
 
1865
+ if check_numbers:
1866
+
1867
+ market_areas_df = self.market_areas_df
1868
+ interaction_matrix_df = self.get_interaction_matrix_df()
1869
+ T_j_market_areas_df = sum(market_areas_df["T_j"])
1870
+ T_j_interaction_matrix_df = sum(interaction_matrix_df["E_ij"])
1871
+
1872
+ if T_j_market_areas_df != T_j_interaction_matrix_df:
1873
+ print("WARNING: Sum of total market areas (" + str(int(T_j_market_areas_df)) + ") is not equal to sum of customer flows (" + str(int(T_j_interaction_matrix_df)) + ")")
1874
+
1872
1875
  supply_locations = self.interaction_matrix.supply_locations
1873
1876
  supply_locations_metadata = supply_locations.get_metadata()
1874
1877
 
@@ -1986,12 +1989,13 @@ class HuffModel:
1986
1989
  update_estimates = False
1987
1990
 
1988
1991
  else:
1989
-
1992
+
1990
1993
  self.interaction_matrix.utility()
1991
1994
  self.interaction_matrix.probabilities()
1992
- self.interaction_matrix.flows()
1995
+ self.interaction_matrix.flows()
1993
1996
 
1994
- self.interaction_matrix.marketareas()
1997
+ huff_model_new_marketareas = self.interaction_matrix.marketareas()
1998
+ self.market_areas_df["T_j"] = huff_model_new_marketareas.get_market_areas_df()["T_j"]
1995
1999
 
1996
2000
  self.interaction_matrix.metadata["fit"] = {
1997
2001
  "function": "huff_ml_fit",
@@ -2042,12 +2046,12 @@ class HuffModel:
2042
2046
 
2043
2047
  except:
2044
2048
 
2045
- print("Goodness-of-fit metrics could not be calculated due to NaN values.")
2049
+ print("WARNING: Goodness-of-fit metrics could not be calculated due to NaN values.")
2046
2050
  return None
2047
2051
 
2048
2052
  else:
2049
2053
 
2050
- print("Goodness-of-fit metrics could not be calculated. No empirical values of probabilities in interaction matrix.")
2054
+ print("WARNING: Goodness-of-fit metrics could not be calculated. No empirical values of probabilities in interaction matrix.")
2051
2055
 
2052
2056
  return None
2053
2057
 
@@ -2069,12 +2073,12 @@ class HuffModel:
2069
2073
 
2070
2074
  except:
2071
2075
 
2072
- print("Goodness-of-fit metrics could not be calculated due to NaN values.")
2076
+ print("WARNING: Goodness-of-fit metrics could not be calculated due to NaN values.")
2073
2077
  return None
2074
2078
 
2075
2079
  else:
2076
2080
 
2077
- print("Goodness-of-fit metrics could not be calculated. No empirical values of customer flows in interaction matrix.")
2081
+ print("WARNING: Goodness-of-fit metrics could not be calculated. No empirical values of customer flows in interaction matrix.")
2078
2082
 
2079
2083
  return None
2080
2084
 
@@ -2095,12 +2099,12 @@ class HuffModel:
2095
2099
 
2096
2100
  except:
2097
2101
 
2098
- print("Goodness-of-fit metrics could not be calculated due to NaN values.")
2102
+ print("WARNING: Goodness-of-fit metrics could not be calculated due to NaN values.")
2099
2103
  return None
2100
2104
 
2101
2105
  else:
2102
2106
 
2103
- print("Goodness-of-fit metrics could not be calculated. No empirical values of T_j in market areas data.")
2107
+ print("WARNING: Goodness-of-fit metrics could not be calculated. No empirical values of T_j in market areas data.")
2104
2108
 
2105
2109
  return None
2106
2110
 
@@ -2174,7 +2178,7 @@ class MCIModel:
2174
2178
 
2175
2179
  except:
2176
2180
 
2177
- print("Goodness-of-fit metrics could not be calculated due to NaN values.")
2181
+ print("WARNING: Goodness-of-fit metrics could not be calculated due to NaN values.")
2178
2182
  return None
2179
2183
 
2180
2184
  else:
@@ -2224,7 +2228,6 @@ class MCIModel:
2224
2228
  print ("Goodness-of-fit for probabilities")
2225
2229
 
2226
2230
  print("Sum of squared residuals ", round(mci_modelfit[1]["SQR"], 2))
2227
- print("Sum of squares ", round(mci_modelfit[1]["SQT"], 2))
2228
2231
  print("R-squared ", round(mci_modelfit[1]["Rsq"], 2))
2229
2232
  print("Mean squared error ", round(mci_modelfit[1]["MSE"], 2))
2230
2233
  print("Root mean squared error ", round(mci_modelfit[1]["RMSE"], 2))
@@ -3129,7 +3132,7 @@ def modelfit(
3129
3132
 
3130
3133
  if len(obs_exp_clean) < len(observed) or len(obs_exp_clean) < len(expected):
3131
3134
  if verbose:
3132
- print("Vectors 'observed' and/or 'expected' contain zeros which are dropped.")
3135
+ print("NOTE: Vectors 'observed' and/or 'expected' contain zeros which are dropped.")
3133
3136
 
3134
3137
  observed = obs_exp_clean["observed"].to_numpy()
3135
3138
  expected = obs_exp_clean["expected"].to_numpy()
Binary file
huff/tests/tests_huff.py CHANGED
@@ -4,8 +4,8 @@
4
4
  # Author: Thomas Wieland
5
5
  # ORCID: 0000-0001-5168-9846
6
6
  # mail: geowieland@googlemail.com
7
- # Version: 1.5.1
8
- # Last update: 2025-07-01 17:10
7
+ # Version: 1.5.2
8
+ # Last update: 2025-07-02 21:10
9
9
  # Copyright (c) 2025 Thomas Wieland
10
10
  #-----------------------------------------------------------------------
11
11
 
@@ -354,6 +354,9 @@ huff_model_fit3 = huff_model_fit2.ml_fit(
354
354
  huff_model_fit3.summary()
355
355
  # Show summary
356
356
 
357
+ print(huff_model_fit3.get_market_areas_df())
358
+ # Show market areas df
359
+
357
360
 
358
361
  # Buffer analysis:
359
362
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: huff
3
- Version: 1.5.1
3
+ Version: 1.5.2
4
4
  Summary: huff: Huff Model Market Area Analysis
5
5
  Author: Thomas Wieland
6
6
  Author-email: geowieland@googlemail.com
@@ -28,14 +28,10 @@ Thomas Wieland [ORCID](https://orcid.org/0000-0001-5168-9846) [EMail](mailto:geo
28
28
  See the /tests directory for usage examples of most of the included functions.
29
29
 
30
30
 
31
- ## Updates v1.5.1
32
- - Extensions:
33
- - HuffModel.ml_fit(): Fit Huff model parameters by empirical total market areas
34
- - HuffModel.summary(): Goodnes-of-fit depends on fit_by
35
- - load_market_areas(): Loading table with totals and including into InteractionMatrix, HuffModel and MCIModel objects
31
+ ## Updates v1.5.2
36
32
  - Bugfixes:
37
- - InteractionMatrix.summary(): NoneType parameter
38
- - InteractionMatrix.huff_ml_fit(): Update estimates possible even if fit algorithm did not converge
33
+ - HuffModel.ml_fit(): Correct values of expected T_j, corrected calculation of model fit metrices when fit_by="totals"
34
+ - HuffModel.ml_fit(): Check if sum of E_ij != sum of T_j
39
35
 
40
36
 
41
37
  ## Features
@@ -44,7 +40,7 @@ See the /tests directory for usage examples of most of the included functions.
44
40
  - Defining origins and destinations with weightings
45
41
  - Creating interaction matrix from origins and destinations
46
42
  - Different function types: power, exponential, logistic
47
- - Huff model parameter estimation via Maximum Likelihood (ML) by probalities and customer flows
43
+ - Huff model parameter estimation via Maximum Likelihood (ML) by probalities, customer flows, and total market areas
48
44
  - Huff model market simulation
49
45
  - **Multiplicative Competitive Interaction Model**:
50
46
  - Log-centering transformation of interaction matrix
@@ -1,10 +1,10 @@
1
1
  huff/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  huff/gistools.py,sha256=fgeE1IsUO7UIaawb23kuiz_Rlxn7T18iLLTA5yvgp74,7038
3
- huff/models.py,sha256=IihaZmutJjdKqzTVXGVmcYbauFJImF-UPsZ2QCPzw8s,125182
3
+ huff/models.py,sha256=e8aILi45qcJ9tvHJfKIFKWfD-DYXjZQ0gXOS4MpG7Ks,125430
4
4
  huff/ors.py,sha256=JlO2UEishQX87PIiktksOrVT5QdB-GEWgjXcxoR_KuA,11929
5
5
  huff/osm.py,sha256=9A-7hxeZyjA2r8w2_IqqwH14qq2Y9AS1GxVKOD7utqs,7747
6
6
  huff/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- huff/tests/tests_huff.py,sha256=eHnEiV8m7TjpAXnJqo1aZ0YlQCGHxK1iFXROEyhN5cU,12884
7
+ huff/tests/tests_huff.py,sha256=xHCR087rqLNWDFfZhi1giKDzffCx3IemWQmHrAUYxFw,12956
8
8
  huff/tests/data/Haslach.cpg,sha256=OtMDH1UDpEBK-CUmLugjLMBNTqZoPULF3QovKiesmCQ,5
9
9
  huff/tests/data/Haslach.dbf,sha256=GVPIt05OzDO7UrRDcsMhiYWvyXAPg6Z-qkiysFzj-fc,506
10
10
  huff/tests/data/Haslach.prj,sha256=2Jy1Vlzh7UxQ1MXpZ9UYLs2SxfrObj2xkEkZyLqmGTY,437
@@ -23,8 +23,8 @@ huff/tests/data/Haslach_supermarkets.prj,sha256=2Jy1Vlzh7UxQ1MXpZ9UYLs2SxfrObj2x
23
23
  huff/tests/data/Haslach_supermarkets.qmd,sha256=JlcOYzG4vI1NH1IuOpxwIPnJsCyC-pDRAI00TzEvNf0,2522
24
24
  huff/tests/data/Haslach_supermarkets.shp,sha256=X7QbQ0BTMag_B-bDRbpr-go2BQIXo3Y8zMAKpYZmlps,324
25
25
  huff/tests/data/Haslach_supermarkets.shx,sha256=j23QHX-SmdAeN04rw0x8nUOran-OCg_T6r_LvzzEPWs,164
26
- huff/tests/data/Wieland2015.xlsx,sha256=jUt9YcRrYL99AjxzXKMXD3o5erjd9r_jYfnALdrTQ3o,24333
27
- huff-1.5.1.dist-info/METADATA,sha256=BXRKyUp5qIEoYjNpo_w9zpUwMTDTO_aegNgr67qj8ns,6187
28
- huff-1.5.1.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
29
- huff-1.5.1.dist-info/top_level.txt,sha256=nlzX-PxZNFmIxANIJMySuIFPihd6qOBkRlhIC28NEsQ,5
30
- huff-1.5.1.dist-info/RECORD,,
26
+ huff/tests/data/Wieland2015.xlsx,sha256=H4rxCFlctn44-O6mIyeFf67FlgvznLX7xZqpoWYS41A,25788
27
+ huff-1.5.2.dist-info/METADATA,sha256=XnlmcfscK8c1P3EN40W8JcQnFE7AkWDT4NqLR9skTIY,5956
28
+ huff-1.5.2.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
29
+ huff-1.5.2.dist-info/top_level.txt,sha256=nlzX-PxZNFmIxANIJMySuIFPihd6qOBkRlhIC28NEsQ,5
30
+ huff-1.5.2.dist-info/RECORD,,
File without changes