Интерактивный дашборд динамики цен на недвижимость на основе Parquet и DuckDB

Материал из Поле цифровой дидактики

Описание проекта

Этот проект демонстрирует создание интерактивного дашборда для анализа динамики цен на недвижимость с использованием DuckDB (встраиваемой аналитической базы данных) и Plotly Dash. Проект наглядно показывает ключевые методы работы с большими данными:

  • Пакетная обработка: Эффективная работа с большими объёмами данных без полной загрузки в память.
  • Колоночное хранение: Использование формата Parquet для ускорения аналитических запросов и экономии места.
  • Векторизованные SQL-запросы: Агрегация и фильтрация данных на лету с помощью DuckDB.

В качестве источника данных используется открытый набор «Индексы цен на рынке жилья» от Росстата (ЕМИСС), доступный в формате Parquet.

Источник данных

Датасет «Индексы цен на рынке жилья (ЕМИСС)» от Росстата.


Код дашборда

Код для создания интерактивного дашборда. Он выполняет следующие шаги:

  1. Подключается к DuckDB и загружает данные из Parquet-файла.
  2. Создаёт интерактивный веб-интерфейс с выпадающим списком для выбора региона.
  3. Строит линейный график динамики цен для выбранного региона.
  4. Отображает среднюю цену за весь период.
import duckdb
import dash
from dash import dcc, html, Input, Output
import plotly.express as px
import pandas as pd

# 1. Подключение к DuckDB и загрузка данных
conn = duckdb.connect()

# Прямая ссылка на Parquet-файл (можно заменить на локальный путь)
DATA_URL = "https://repository.econdata.tech/dataset/emiss_30925/resource/60378ec6-c7a8-4cec-9a59-e841ca206b3f"

# Регистрируем Parquet-файл как таблицу в DuckDB
conn.execute(f"""
    CREATE OR REPLACE TABLE real_estate AS 
    SELECT * FROM '{DATA_URL}'
""")

# Предварительно получаем список уникальных регионов для выпадающего списка
regions_df = conn.execute("SELECT DISTINCT region FROM real_estate ORDER BY region").fetchdf()
regions = regions_df['region'].tolist()

# 2. Инициализация Dash-приложения
app = dash.Dash(__name__)

app.layout = html.Div([
    html.H1("📈 Интерактивный дашборд: Динамика цен на недвижимость", 
            style={'textAlign': 'center'}),
    
    html.Label("Выберите регион:"),
    dcc.Dropdown(
        id='region-dropdown',
        options=[{'label': r, 'value': r} for r in regions],
        value=regions[0],  # значение по умолчанию
        clearable=False
    ),
    
    dcc.Graph(id='price-chart'),
    
    html.Div(id='avg-price-text', style={'marginTop': 20, 'fontSize': 20})
])

# 3. Callback для обновления графика и текста при смене региона
@app.callback(
    [Output('price-chart', 'figure'),
     Output('avg-price-text', 'children')],
    Input('region-dropdown', 'value')
)
def update_dashboard(selected_region):
    # SQL-запрос с агрегацией данных по выбранному региону
    query = f"""
        SELECT 
            date,
            AVG(price_index) as avg_index
        FROM real_estate
        WHERE region = '{selected_region}'
        GROUP BY date
        ORDER BY date
    """
    df = conn.execute(query).fetchdf()
    
    # Создание графика Plotly
    fig = px.line(df, x='date', y='avg_index', 
                  title=f'Динамика индекса цен в регионе: {selected_region}',
                  labels={'avg_index': 'Индекс цен', 'date': 'Дата'})
    
    # Расчёт среднего значения для текстового блока
    avg_price = df['avg_index'].mean()
    avg_text = f"Средний индекс цен за период: {avg_price:.2f}"
    
    return fig, avg_text

# 4. Запуск сервера
if __name__ == '__main__':
    app.run_server(debug=True)

Как это работает

  1. DuckDB напрямую читает Parquet-файл, извлекая только нужные колонки и строки (благодаря предикативному пушдауну, Predicate Pushdown). Это позволяет обрабатывать гигабайты данных на обычном компьютере.
  2. Dash создаёт веб-интерфейс на чистом Python, без необходимости писать HTML или JavaScript.
  3. При выборе региона в выпадающем списке выполняется SQL-запрос к DuckDB, который агрегирует данные и возвращает результат для построения графика.

Демонстрация ключевых методов Big Data

  • Экономия памяти: DuckDB загружает данные частями (chunks), не расходуя всю оперативную память.
  • Колоночное хранение (Parquet): Чтение только нужных колонок ускоряет запросы в десятки раз по сравнению с CSV.
  • Векторизованные запросы: DuckDB использует SIMD-инструкции процессора для параллельной обработки данных.

Ссылки