Published on

Simulación y Análisis de Datos de un Hotel con Instagres, Python y Power BI

Authors
  • avatar
    Name
    Jordan Rodriguez
    Twitter

Simulación de flujo de atención de un hospedaje con Python y Power BI

Este tutorial, pensado para un perfil de Data Scientist experto, cubre todo el proceso: desde el aprovisionamiento rápido de la base de datos efímera en Instagres.com, el modelado de tablas (con diagrama ER), la instalación de librerías, la definición y ejecución de funciones Python para generar y cargar 2 años de histórico de un hotel con 1 000 clientes, hasta la conexión final con Power BI.

Puedes ejecutar en Open In Colab

1. Creación de la base de datos efímera en Instagres.com

Instagres.com permite aprovisionar en segundos una base de datos PostgreSQL que vive sólo 1 hora, con un solo clic y sin configuración adicional.

  1. Visita https://www.instagres.com
  2. Haz clic en New
  3. ¡Listo! Instagres crea tu BD efímera (1 hora de vida) y muestra la cadena de conexión.
# Ejemplo de Connection String generada automáticamente:
CONN_STR="postgresql://neondb_owner:npg_mL4hapw1PAIe@ep-round-glade-a2o8ygz2.eu-central-1.aws.neon.tech/neondb?sslmode=require"

2. Modelado del esquema de datos

Diseñamos un modelo relacional con tres tablas:

  • clients: Datos sociodemográficos y nivel de lealtad.
  • rooms: 30 habitaciones en 4 pisos, con tipo, capacidad y precio.
  • stays: Historial de estancias (check-in, check-out, importe total).

Diagrama ER

erDiagram
    CLIENTS ||--o{ STAYS : has
    ROOMS   ||--o{ STAYS : has

    CLIENTS {
        int    client_id PK
        string first_name
        string last_name
        string gender
        date   birth_date
        string email
        string phone
        string nationality
        string loyalty_level
    }
    ROOMS {
        int    room_id PK
        int    floor
        string room_number
        string room_type
        int    capacity
        decimal price_per_night
    }
    STAYS {
        int    stay_id PK
        int    client_id FK
        int    room_id FK
        date   check_in_date
        date   check_out_date
        decimal total_amount
    }

3. Instalación de librerías Python

!pip install psycopg2-binary faker numpy pandas

4. Generación, simulación e ingestión de datos

A continuación el script completo, que incluye:

  • Conexión y creación de tablas
  • Generación de 1 000 clientes con Faker
  • Generación de 30 habitaciones
  • Simulación de 2 años de estancias (μ=15 llegadas/día, σ=12; estancia ~ exponencial(λ=1/3))
  • Ingestión masiva en batches
  • Validación de carga
  • Impresión automática de parámetros para Power BI
import psycopg2
import psycopg2.extras
import numpy as np
import pandas as pd
import random
from datetime import datetime, timedelta
from faker import Faker
from urllib.parse import urlparse, parse_qs

# — Parámetros de simulación —
CONN_STR   = "postgresql://usuario:password@host:puerto/hotel_demo?sslmode=require"
N_CLIENTS  = 1000
START_DATE = datetime.today() - timedelta(days=365*2)
END_DATE   = datetime.today()
MEAN_DAILY = 15
STD_DAILY  = 12
MEAN_STAY  = 3

fake = Faker("es_ES")
random.seed(42)
np.random.seed(42)

def connect_db():
    return psycopg2.connect(CONN_STR)

def create_tables(conn):
    cur = conn.cursor()
    cur.execute(\"\"\"    
    CREATE TABLE IF NOT EXISTS clients (
        client_id      SERIAL PRIMARY KEY,
        first_name     VARCHAR(50),
        last_name      VARCHAR(50),
        gender         VARCHAR(10),
        birth_date     DATE,
        email          VARCHAR(100),
        phone          VARCHAR(20),
        nationality    VARCHAR(50),
        loyalty_level  VARCHAR(20)
    );
    CREATE TABLE IF NOT EXISTS rooms (
        room_id         SERIAL PRIMARY KEY,
        floor           INTEGER,
        room_number     VARCHAR(4),
        room_type       VARCHAR(10),
        capacity        INTEGER,
        price_per_night NUMERIC(8,2)
    );
    CREATE TABLE IF NOT EXISTS stays (
        stay_id         SERIAL PRIMARY KEY,
        client_id       INTEGER REFERENCES clients(client_id),
        room_id         INTEGER REFERENCES rooms(room_id),
        check_in_date   DATE,
        check_out_date  DATE,
        total_amount    NUMERIC(10,2)
    );
    \"\"\")
    conn.commit()
    cur.close()

def generate_clients(n=N_CLIENTS):
    records = []
    for _ in range(n):
        gender = random.choice(['Male','Female'])
        first  = fake.first_name_male()   if gender=='Male'   else fake.first_name_female()
        last   = fake.last_name()
        birth  = fake.date_between(start_date='-70y', end_date='-18y')
        records.append((first, last, gender, birth,
                        fake.ascii_free_email(), fake.phone_number(),
                        fake.country(), random.choice(['Bronze','Silver','Gold','Platinum'])))
    return pd.DataFrame(records, columns=[
        'first_name','last_name','gender','birth_date',
        'email','phone','nationality','loyalty_level'
    ])

def generate_rooms():
    floor_sizes = [8,8,7,7]
    types       = ['Single','Double','Suite']
    caps        = {'Single':1,'Double':2,'Suite':4}
    prices      = {'Single':80.0,'Double':120.0,'Suite':250.0}
    records = []
    for floor, count in enumerate(floor_sizes, start=1):
        for num in range(1, count+1):
            rt = random.choice(types)
            records.append((floor, f"{floor}{str(num).zfill(2)}", rt, caps[rt], prices[rt]))
    return pd.DataFrame(records, columns=[
        'floor','room_number','room_type','capacity','price_per_night'
    ])

def generate_stays(clients_df, rooms_df):
    records    = []
    client_ids = clients_df.index + 1
    room_ids   = rooms_df.index   + 1
    current    = START_DATE
    while current <= END_DATE:
        k = max(0, int(np.random.normal(MEAN_DAILY, STD_DAILY)))
        for _ in range(k):
            c      = random.choice(client_ids)
            length = max(1, int(np.random.exponential(MEAN_STAY)))
            ci     = current
            co     = current + timedelta(days=length)
            r      = random.choice(room_ids)
            price  = rooms_df.loc[r-1, 'price_per_night']
            total  = round(price * length, 2)
            records.append((c, r, ci.date(), co.date(), total))
        current += timedelta(days=1)
    return pd.DataFrame(records, columns=[
        'client_id','room_id','check_in_date','check_out_date','total_amount'
    ])

def ingest_df(conn, df, table):
    cols = ",".join(df.columns)
    vals = ",".join([f"%({c})s" for c in df.columns])
    query = f"INSERT INTO {table} ({cols}) VALUES ({vals})"
    cur = conn.cursor()
    psycopg2.extras.execute_batch(cur, query, df.to_dict('records'), page_size=500)
    conn.commit()
    cur.close()

def check_data_exists(conn):
    for tbl in ['clients','rooms','stays']:
        cur = conn.cursor()
        cur.execute(f"SELECT COUNT(*) FROM {tbl}")
        cnt = cur.fetchone()[0]
        status = "✅ OK" if cnt>0 else "❌ VACÍA"
        print(f"{tbl:10s}: {cnt:6d} rows → {status}")
        cur.close()

def parse_conn_str(conn_str: str) -> dict:
    parsed = urlparse(conn_str)
    params = {
        'host':     parsed.hostname,
        'port':     parsed.port or 5432,
        'database': parsed.path.lstrip('/'),
        'user':     parsed.username,
        'password': parsed.password,
    }
    qp = parse_qs(parsed.query)
    if 'sslmode' in qp:
        params['sslmode'] = qp['sslmode'][0]
    return params

def print_powerbi_params(conn_str: str):
    params = parse_conn_str(conn_str)
    print("\n# Parámetros para Power BI")
    for key, val in params.items():
        print(f"{key}={val}")

def main():
    conn    = connect_db()
    create_tables(conn)
    clients = generate_clients()
    rooms   = generate_rooms()
    stays   = generate_stays(clients, rooms)
    ingest_df(conn, clients, 'clients')
    ingest_df(conn, rooms,   'rooms')
    ingest_df(conn, stays,   'stays')
    check_data_exists(conn)
    print_powerbi_params(CONN_STR)
    conn.close()

if __name__ == '__main__':
    main()

5. Ejecución

En tu entorno (Colab, terminal o IDE):

python hotel_simulation.py

Deberías ver algo como:

clients   :   1000 rows → ✅ OK  
rooms     :     30 rows → ✅ OK  
stays     : ~11000 rows → ✅ OK  

# Parámetros para Power BI
host=ep-round-glade-a2o8ygz2.eu-central-1.aws.neon.tech
port=5432
database=neondb
user=neondb_owner
password=npg_mL4hapw1PAIe
sslmode=require

6. Conexión desde Power BI

Para Windows, asegúrate de instalar primero el conector de PostgreSQL: Link descarga

Reinicia Power BI Desktop tras la instalación.

  1. Abre Power BI DesktopObtener datosBases de datosPostgreSQL.
  2. Servidor: <host_de_Instagres>
  3. Base de datos: <database_name>
  4. Modo: Importar o DirectQuery.
  5. Credenciales: Básico → usuario y contraseña de Instagres.
  6. SSL: Marca Requerir cifrado (SSL).
  7. Selecciona las tablas y pulsa Cargar.

¡Ya estás listo para construir dashboards de ocupación, ADR y LTV con tus datos simulados!