Снова измерения температуры 📈 — и снова проблема: каждый день датчик даёт случайное смещение (bias). Нам нужно не просто его найти, а сделать это более надёжно — с учётом неопределённости.
🔁 Уточнённые цели
1. Оценить дневной bias через байесовскую регрессию
2. Использовать нелинейный тренд вместо скользящего среднего
3. Построить интервалы доверия для оценённой температуры
4. Визуализировать, насколько хорошо работает очистка
📦 Шаг 1. Генерация данных (как раньше)
📐 Шаг 2. Построим нелинейную модель тренда (например, полиномиальную регрессию)
🧮 Шаг 3. Байесовская оценка bias (через среднее и стандартную ошибку)
📊 Шаг 4. Оценка качества и визуализация
📈 Визуализация с доверительными интервалами
✅ Вывод
✔️ Нелинейная регрессия даёт лучшее приближение тренда, чем скользящее среднее
✔️ Байесовская оценка даёт не только среднюю оценку bias, но и доверительные интервалы
✔️ Модель учитывает неопределённость и шум — ближе к реальной инженерной задаче
✔️ RMSE почти сравнивается с дисперсией шума → bias эффективно устраняется
🔁 Уточнённые цели
1. Оценить дневной bias через байесовскую регрессию
2. Использовать нелинейный тренд вместо скользящего среднего
3. Построить интервалы доверия для оценённой температуры
4. Визуализировать, насколько хорошо работает очистка
📦 Шаг 1. Генерация данных (как раньше)
import pandas as pd
import numpy as np
np.random.seed(42)
days = pd.date_range("2023-01-01", periods=10, freq="D")
true_temp = np.sin(np.linspace(0, 3 * np.pi, 240)) * 10 + 20
bias_per_day = np.random.uniform(-2, 2, size=len(days))
df = pd.DataFrame({
"datetime": pd.date_range("2023-01-01", periods=240, freq="H"),
})
df["day"] = df["datetime"].dt.date
df["true_temp"] = true_temp
df["bias"] = df["day"].map(dict(zip(days.date, bias_per_day)))
df["measured_temp"] = df["true_temp"] + df["bias"] + np.random.normal(0, 0.5, size=240)
{}
📐 Шаг 2. Построим нелинейную модель тренда (например, полиномиальную регрессию)
from sklearn.linear_model import Ridge
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline
# Модель полиномиальной регрессии степени 6
X_time = np.arange(len(df)).reshape(-1, 1)
y = df["measured_temp"].values
model = make_pipeline(PolynomialFeatures(degree=6), Ridge(alpha=1.0))
model.fit(X_time, y)
df["trend_poly"] = model.predict(X_time)
df["residual"] = df["measured_temp"] - df["trend_poly"]
{}
🧮 Шаг 3. Байесовская оценка bias (через среднее и стандартную ошибку)
bias_stats = df.groupby("day")["residual"].agg(["mean", "std", "count"])
bias_stats["stderr"] = bias_stats["std"] / np.sqrt(bias_stats["count"])
df["bias_bayes"] = df["day"].map(bias_stats["mean"])
df["bias_stderr"] = df["day"].map(bias_stats["stderr"])
# Восстановим очищенную температуру
df["restored_bayes"] = df["measured_temp"] - df["bias_bayes"]
{}
📊 Шаг 4. Оценка качества и визуализация
from sklearn.metrics import mean_squared_error
rmse = mean_squared_error(df["true_temp"], df["restored_bayes"], squared=False)
print(f"📉 RMSE (после байесовской очистки): {rmse:.3f}")
{}
📈 Визуализация с доверительными интервалами
import matplotlib.pyplot as plt
for day in df["day"].unique():
day_data = df[df["day"] == day]
stderr = day_data["bias_stderr"].iloc[0]
plt.fill_between(day_data.index,
day_data["restored_bayes"] - stderr,
day_data["restored_bayes"] + stderr,
alpha=0.2, label=str(day) if day == df["day"].unique()[0] else "")
plt.plot(df["true_temp"], label="True Temp", lw=1.5)
plt.plot(df["restored_bayes"], label="Restored Temp (Bayes)", lw=1)
plt.legend()
plt.title("Восстановление температуры с доверительными интервалами")
plt.xlabel("Time")
plt.ylabel("°C")
plt.grid(True)
plt.show()
{}
✅ Вывод
✔️ Нелинейная регрессия даёт лучшее приближение тренда, чем скользящее среднее
✔️ Байесовская оценка даёт не только среднюю оценку bias, но и доверительные интервалы
✔️ Модель учитывает неопределённость и шум — ближе к реальной инженерной задаче
✔️ RMSE почти сравнивается с дисперсией шума → bias эффективно устраняется