Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
where $X_{ik}$ includes structural attributes (sqft, bedrooms, age), location variables (distance to CBD, school quality), and neighborhood characteristics. The implicit price of attribute $k$ is $\partial P/\partial X_k = \beta_k \cdot P$.
Repeat-Sales Index
For two sales of property $i$ at times $s$ and $t$:
where $D_\tau$ are time dummies and $\delta_\tau$ estimates log price changes. The Case-Shiller weighted repeat-sales accounts for variance growing with holding period.
Affordability Measures
Price-to-Income Ratio (PIR): $\text{PIR} = P / Y_{\text{median}}$
Housing Affordability Index (HAI): $\text{HAI} = \frac{\text{Qualifying Income}}{Y_{\text{median}}} \times 100$, where qualifying income = monthly payment × 12 / 0.28
import numpy as np
import pandas as pd
import statsmodels.api as sm
from sklearn.ensemble import GradientBoostingRegressor
import matplotlib.pyplot as plt
print("Housing market analysis environment ready")
Core Workflow
Step 1: Hedonic Regression with Spatial Effects
import numpy as np
import pandas as pd
import statsmodels.api as sm
from scipy.spatial.distance import cdist
import matplotlib.pyplot as plt
# -----------------------------------------------------------------# Simulate hedonic dataset: 1000 transactions# -----------------------------------------------------------------
np.random.seed(42)
n = 1000# Location: x, y coordinates in a 20km x 20km city
x = np.random.uniform(0, 20, n)
y = np.random.uniform(0, 20, n)
# Distance to CBD at (10, 10)
cbd_dist = np.sqrt((x - 10)**2 + (y - 10)**2)
# Structural attributes
sqft = np.random.lognormal(7.0, 0.4, n) # 330-2700 sqft
bedrooms = np.random.choice([1, 2, 3, 4, 5], n, p=[0.1, 0.25, 0.35, 0.2, 0.1])
age = np.random.randint(0, 80, n).astype(float)
garage = np.random.binomial(1, 0.6, n)
school_rating = np.random.uniform(3, 10, n)
# True hedonic model (log-linear)
ln_P = (
11.0# intercept ~ $60k baseline
+ 0.7 * np.log(sqft) # size elasticity 0.7
+ 0.05 * bedrooms # each bedroom +5%
- 0.005 * age # depreciation
+ 0.10 * garage # garage premium
+ 0.06 * school_rating # school quality
- 0.04 * cbd_dist # CBD gradient: -4%/km
+ np.random.normal(0, 0.12, n) # unexplained
)
price = np.exp(ln_P)
df = pd.DataFrame({
"price": price, "sqft": sqft, "bedrooms": bedrooms,
"age": age, "garage": garage, "school_rating": school_rating,
"cbd_dist": cbd_dist, "x": x, "y": y
})
# -----------------------------------------------------------------# OLS hedonic regression# -----------------------------------------------------------------
df["ln_price"] = np.log(df["price"])
df["ln_sqft"] = np.log(df["sqft"])
features = ["ln_sqft", "bedrooms", "age", "garage", "school_rating", "cbd_dist"]
X_reg = sm.add_constant(df[features])
ols = sm.OLS(df["ln_price"], X_reg).fit(cov_type="HC3")
print("=== OLS Hedonic Regression ===")
print(ols.summary().tables[1])
print(f"\nAdjusted R²: {ols.rsquared_adj:.4f}")
# Marginal implicit prices at median house
median_price = df["price"].median()
print(f"\nMedian house price: ${median_price:,.0f}")
print(f"Implicit price of 1 extra sqft: ${ols.params['ln_sqft'] * median_price / df['sqft'].median():,.0f}")
print(f"CBD gradient: {ols.params['cbd_dist']*100:.1f}% per km")
# -----------------------------------------------------------------# Bid-rent gradient visualization# -----------------------------------------------------------------
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
# Price vs CBD distance
axes[0].scatter(df["cbd_dist"], df["ln_price"], alpha=0.3, s=5, c="steelblue")
d_line = np.linspace(0, 14, 100)
axes[0].plot(d_line, ols.params["const"] + ols.params["cbd_dist"] * d_line +
ols.params["ln_sqft"] * np.log(df["sqft"].median()) +
ols.params["bedrooms"] * 3 + ols.params["school_rating"] * 7,
"r-", lw=2, label="Bid-rent gradient")
axes[0].set_xlabel("Distance from CBD (km)")
axes[0].set_ylabel("ln(Price)")
axes[0].set_title("Bid-Rent Gradient")
axes[0].legend()
# Price heatmap on city gridfrom scipy.interpolate import griddata
xi = np.linspace(0, 20, 100)
yi = np.linspace(0, 20, 100)
Xi, Yi = np.meshgrid(xi, yi)
Pi = griddata((df["x"], df["y"]), df["price"], (Xi, Yi), method="linear")
im = axes[1].contourf(Xi, Yi, Pi / 1e6, levels=20, cmap="RdYlGn_r")
axes[1].plot(10, 10, "k*", ms=15, label="CBD")
axes[1].set_title("Price Surface ($ million)")
plt.colorbar(im, ax=axes[1])
axes[1].legend()
# Residual spatial pattern
residuals = ols.resid
sc = axes[2].scatter(df["x"], df["y"], c=residuals, cmap="RdBu_r",
vmin=-0.3, vmax=0.3, s=10)
axes[2].plot(10, 10, "k*", ms=15)
axes[2].set_title("OLS Residuals (Spatial Pattern?)")
plt.colorbar(sc, ax=axes[2], label="Residual")
plt.tight_layout()
plt.savefig("hedonic_regression.png", dpi=150, bbox_inches="tight")
plt.close()
print("\nFigure saved: hedonic_regression.png")
Step 2: Repeat-Sales House Price Index
import numpy as np
import pandas as pd
import statsmodels.api as sm
import matplotlib.pyplot as plt
# -----------------------------------------------------------------# Simulate repeat sales dataset# 500 properties, each sold 2-3 times over 10 years (40 quarters)# -----------------------------------------------------------------
np.random.seed(42)
n_properties = 500
n_quarters = 40# True price index (simulates a housing boom-bust cycle)
true_index = np.zeros(n_quarters)
true_index[:20] = np.linspace(0, 0.8, 20) # 80% appreciation over 5 years
true_index[20:30] = np.linspace(0.8, 0.5, 10) # 30% crash
true_index[30:] = np.linspace(0.5, 0.7, 10) # partial recovery
records = []
for prop_id inrange(n_properties):
# Two sales: first sale in 0-19, second in 10-39
t1 = np.random.randint(0, 25)
t2 = np.random.randint(t1 + 4, n_quarters)
base_ln_price = np.random.normal(12.5, 0.5) # property fixed effect# Prices at each sale time
noise1 = np.random.normal(0, 0.08)
noise2 = np.random.normal(0, 0.08)
ln_p1 = base_ln_price + true_index[t1] + noise1
ln_p2 = base_ln_price + true_index[t2] + noise2
records.append({"prop_id": prop_id, "t": t1, "ln_price": ln_p1})
records.append({"prop_id": prop_id, "t": t2, "ln_price": ln_p2})
sales_df = pd.DataFrame(records).sort_values(["prop_id", "t"])
# -----------------------------------------------------------------# Construct repeat-sales pairs# -----------------------------------------------------------------
pairs = []
for prop_id, grp in sales_df.groupby("prop_id"):
grp = grp.reset_index(drop=True)
for i inrange(len(grp) - 1):
pairs.append({
"prop_id": prop_id,
"t_sell": int(grp.loc[i+1, "t"]),
"t_buy": int(grp.loc[i, "t"]),
"ln_price_diff": grp.loc[i+1, "ln_price"] - grp.loc[i, "ln_price"]
})
pairs_df = pd.DataFrame(pairs)
print(f"Repeat-sale pairs: {len(pairs_df)}")
# -----------------------------------------------------------------# Case-Shiller OLS repeat-sales regression# Time dummies: omit period 0 as base# -----------------------------------------------------------------
periods = list(range(1, n_quarters)) # periods 1..39defbuild_repeat_sales_matrix(pairs_df, periods):
"""Build design matrix for repeat-sales regression.
Each row: ln(P_sell) - ln(P_buy) = sum of time dummies between buy and sell.
Returns X (design matrix) and y (price changes).
"""
n = len(pairs_df)
X = np.zeros((n, len(periods)))
y = pairs_df["ln_price_diff"].values.copy()
period_map = {p: i for i, p inenumerate(periods)}
for row_idx, row inenumerate(pairs_df.itertuples()):
for tau inrange(row.t_buy + 1, row.t_sell + 1):
if tau in period_map:
X[row_idx, period_map[tau]] = 1return X, y
X_rs, y_rs = build_repeat_sales_matrix(pairs_df, periods)
# OLS (no constant — natural normalization: index[0] = 0)
result_rs = sm.OLS(y_rs, X_rs).fit()
index_ols = np.concatenate([[0.0], result_rs.params]) # prepend 0 for period 0print(f"R² of repeat-sales regression: {result_rs.rsquared:.4f}")
print(f"Peak index level: {index_ols.max():.3f} at period {np.argmax(index_ols)}")
# -----------------------------------------------------------------# Visualization# -----------------------------------------------------------------
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
axes[0].plot(true_index, "b--", label="True Index", lw=2)
axes[0].plot(index_ols, "r-", label="OLS Repeat-Sales", lw=2)
axes[0].set_xlabel("Quarter")
axes[0].set_ylabel("Log Price Change (base=0)")
axes[0].set_title("Repeat-Sales House Price Index")
axes[0].legend()
axes[0].axhline(0, color="gray", lw=0.8)
# Distribution of holding period lengths
holding = pairs_df["t_sell"] - pairs_df["t_buy"]
axes[1].hist(holding, bins=20, color="steelblue", edgecolor="black")
axes[1].set_xlabel("Holding Period (quarters)")
axes[1].set_ylabel("Frequency")
axes[1].set_title("Distribution of Holding Periods")
plt.tight_layout()
plt.savefig("repeat_sales_index.png", dpi=150, bbox_inches="tight")
plt.close()
print("\nFigure saved: repeat_sales_index.png")