Land valuation separates the value of land from improvements, essential for equitable taxation and market analysis. OpenAVM Kit provides sophisticated tools for both vacant land modeling and hedonic land extraction from improved sales.
Proper land valuation ensures fair taxation and provides insight into site value independent of structures.
from openavmkit.data import get_vacant_sales# Filter to vacant land sales onlydf_vacant = get_vacant_sales(df_sales, settings)# Train model on vacant salesmodel.fit(X_vacant, y_vacant)
Extract land value from improved property sales using building characteristics:
# Model total value, then attribute portion to land# based on improvement characteristicsmodel.fit(X_improved, y_improved)# Calculate land allocationland_allocation = predict_land_value(model, property_data)
Land Allocation = Land Model Prediction / Main Model Prediction
Example:
import pandas as pd# Main model predicts total valuepred_main = 450_000 # Total property value# Vacant/hedonic model predicts land valuepred_land = 180_000 # Land value# Calculate allocationalloc = pred_land / pred_main # 0.40 = 40%print(f"Land accounts for {alloc:.1%} of total value")
from openavmkit.modeling import plot_value_surfaceimport geopandas as gpd# Create GeoDataFramegdf = gpd.GeoDataFrame(df, geometry="geometry")# Plot land value per square footplot_value_surface( title="Land value per sqft", values=gdf["model_land_value_per_sqft"], gdf=gdf, cmap="viridis", norm="log" # Log scale for wide value ranges)
from openavmkit.utilities.plotting import plot_histogram_dfplot_histogram_df( df=df, fields=["model_land_alloc"], xlabel="% of value attributable to land", ylabel="Number of parcels", title="Land Allocation Distribution", bins=100, x_lim=(0.0, 1.0))
from openavmkit.utilities.settings import area_unitunit = area_unit(settings) # 'sf' or 'sm'# Land value per square foot/meterdf[f"model_land_value_{unit}"] = div_series_z_safe( df["model_land_value"], df[f"land_area_{unit}"])# Market value per land areadf[f"model_market_value_land_{unit}"] = div_series_z_safe( df["model_market_value"], df[f"land_area_{unit}"])# Market value per building areadf[f"model_market_value_impr_{unit}"] = div_series_z_safe( df["model_market_value"], df[f"bldg_area_finished_{unit}"])
Per-area metrics enable comparison across properties of different sizes.
from openavmkit.modeling import simple_ols# Regress sale price on land arearesults = simple_ols( df=df_vacant_sales, x_col="land_area_sf", y_col="sale_price", intercept=True)land_value_per_sf = results["slope"]print(f"Land value: ${land_value_per_sf:.2f} per sqft")print(f"R²: {results['r2']:.3f}")
Calculate land value by subtracting improvement value:
# Estimate improvement value from cost approachdf["impr_replacement_cost"] = ( df["bldg_area_finished_sf"] * cost_per_sf * df["depreciation_factor"])# Land value is residualdf["land_value_residual"] = ( df["model_market_value"] - df["impr_replacement_cost"])