Skip to content

Problema 1

I) De las 3 tablas anexas, escribe una consulta en SQL que te dé los nombres de aquellos estudiantes cuyos amigos perciben un ingreso mayor que ellos. Los nombres deben de estar ordenados por el salario que ganan sus amigos.

Spinner
DataFrameas
df
variable
CREATE TABLE Estudiantes (
    ID INT PRIMARY KEY,
    Nombre VARCHAR(50)
);

INSERT INTO Estudiantes (ID, Nombre)
VALUES
(1, 'Manuel'), (2, 'Tania'), (3, 'Pedro'), (4, 'Ana'),
(5, 'Luis'), (6, 'Marta'), (7, 'Jorge'), (8, 'Clara'),
(9, 'Pablo'), (10, 'Sara'), (11, 'David'), (12, 'Laura'),
(13, 'Mario'), (14, 'Silvia'), (15, 'Carlos'), (16, 'Isabel'),
(17, 'Antonio'), (18, 'Elena'), (19, 'Francisco'), (20, 'Sofia');

CREATE TABLE Amigos (
    ID INT PRIMARY KEY,
    Amigo_ID INT
);

INSERT INTO Amigos (ID, Amigo_ID)
VALUES
(1, 2), (2, 20), (3, 3), (4, 12), (5, 4), (6, 5),
(7, 1), (8, 13), (9, 6), (10, 12), (11, 17), (12, 18),
(13, 19), (14, 8), (15, 9), (16, 15), (17, 10), (18, 7),
(19, 10), (20, 11);

CREATE TABLE Salarios (
    ID INT PRIMARY KEY,
    Salario FLOAT
);

INSERT INTO Salarios (ID, Salario)
VALUES
(1, 15200.1), (2, 10060.2), (3, 11500.5), (4, 12120),
(5, 13200.75), (6, 9500.4), (7, 14500), (8, 10300.3),
(9, 16000), (10, 8500.5), (11, 9000), (12, 17000.75),
(13, 11000.2), (14, 12500.4), (15, 13500.1), (16, 9200.6),
(17, 10100.8), (18, 11200.9), (19, 14000.25), (20, 14500.5);


SELECT 
    Estudiantes.Nombre AS Estudiante,
    EstudiantesAmigos.Nombre AS Amigo,
    CAST(ROUND(SalariosAmigos.Salario, 2) AS DECIMAL(10,2)) AS Salario_Amigo
FROM Estudiantes
JOIN Amigos ON Estudiantes.ID = Amigos.ID
JOIN Salarios AS SalariosEstudiantes ON Estudiantes.ID = SalariosEstudiantes.ID
JOIN Salarios AS SalariosAmigos ON Amigos.Amigo_ID = SalariosAmigos.ID
JOIN Estudiantes AS EstudiantesAmigos ON Amigos.Amigo_ID = EstudiantesAmigos.ID
WHERE SalariosAmigos.Salario > SalariosEstudiantes.Salario
ORDER BY SalariosAmigos.Salario DESC;

II) De las 3 tablas anexas, escribe una consulta en SQL que te dé el nombre del estudiante y el promedio del salario de sus amigos, pero solo para aquellos estudiantes cuyo promedio de salario de amigos sea mayor que el promedio de salario de todos los estudiantes. Los resultados deben estar ordenados por el promedio del salario de sus amigos en orden descendente.

Spinner
DataFrameas
df1
variable
CREATE TABLE Estudiantes (
    ID INT PRIMARY KEY,
    Nombre VARCHAR(50)
);

INSERT INTO Estudiantes (ID, Nombre)
VALUES
(1, 'Manuel'), (2, 'Tania'), (3, 'Pedro'), (4, 'Ana'),
(5, 'Luis'), (6, 'Marta'), (7, 'Jorge'), (8, 'Clara'),
(9, 'Pablo'), (10, 'Sara'), (11, 'David'), (12, 'Laura'),
(13, 'Mario'), (14, 'Silvia'), (15, 'Carlos'), (16, 'Isabel'),
(17, 'Antonio'), (18, 'Elena'), (19, 'Francisco'), (20, 'Sofia');

CREATE TABLE Amigos (
    ID INT PRIMARY KEY,
    Amigo_ID INT
);

INSERT INTO Amigos (ID, Amigo_ID)
VALUES
(1, 2), (2, 20), (3, 3), (4, 12), (5, 4), (6, 5),
(7, 1), (8, 13), (9, 6), (10, 12), (11, 17), (12, 18),
(13, 19), (14, 8), (15, 9), (16, 15), (17, 10), (18, 7),
(19, 10), (20, 11);

CREATE TABLE Salarios (
    ID INT PRIMARY KEY,
    Salario FLOAT
);

INSERT INTO Salarios (ID, Salario)
VALUES
(1, 15200.1), (2, 10060.2), (3, 11500.5), (4, 12120),
(5, 13200.75), (6, 9500.4), (7, 14500), (8, 10300.3),
(9, 16000), (10, 8500.5), (11, 9000), (12, 17000.75),
(13, 11000.2), (14, 12500.4), (15, 13500.1), (16, 9200.6),
(17, 10100.8), (18, 11200.9), (19, 14000.25), (20, 14500.5);


WITH PromedioGlobal AS (
    SELECT AVG(Salario) AS Promedio_Global FROM Salarios
)
SELECT 
    Estudiantes.Nombre AS Estudiante,
    EstudiantesAmigos.Nombre AS Amigo,
    CAST(ROUND(SalariosAmigos.Salario, 2) AS DECIMAL(10,2)) AS Salario_Amigo,
FROM Estudiantes
JOIN Amigos ON Estudiantes.ID = Amigos.ID
JOIN Salarios AS SalariosAmigos ON Amigos.Amigo_ID = SalariosAmigos.ID
JOIN Estudiantes AS EstudiantesAmigos ON Amigos.Amigo_ID = EstudiantesAmigos.ID
CROSS JOIN PromedioGlobal
WHERE SalariosAmigos.Salario > PromedioGlobal.Promedio_Global
ORDER BY SalariosAmigos.Salario DESC;

III) Desarrolla un ejemplo de visualización que muestre los resultados de tu análisis apoyándote en los datos.

import matplotlib.pyplot as plt
import numpy as np

estudiantes = [
    'Laura', 'Pablo', 'Francisco', 'Jorge', 'Manuel', 'Tania', 'Pedro', 'Ana', 
    'Luis', 'Marta', 'Clara', 'Sara', 'David', 'Mario', 'Silvia', 'Carlos', 
    'Isabel', 'Antonio', 'Elena', 'Sofia'
]
salarios_amigos = [
    17000.75, 16000, 14000.25, 14500, 15200.1, 10060.2, 11500.5, 12120, 
    13200.75, 9500.4, 10300.3, 8500.5, 9000, 11000.2, 12500.4, 13500.1, 
    9200.6, 10100.8, 11200.9, 14500.5
]
promedio_global = np.mean(salarios_amigos)

ordenados = sorted(zip(salarios_amigos, estudiantes), reverse=True)
salarios_amigos, estudiantes = zip(*ordenados)

salarios_amigos = salarios_amigos[:10]
estudiantes = estudiantes[:10]

plt.figure(figsize=(14, 8))
bars = plt.bar(estudiantes, salarios_amigos, color='orange', edgecolor='black', linewidth=1.2)

plt.axhline(y=promedio_global, color='red', linestyle='--', linewidth=1.5, label=f'Promedio Global: ${promedio_global:,.1f}')

for bar in bars:
    plt.text(
        bar.get_x() + bar.get_width() / 2,
        bar.get_height() + 200,
        f"${bar.get_height():,.1f}",
        ha='center', va='bottom', fontsize=10, color='black'
    )

plt.title("Top 10 Salarios de los Amigos de los Estudiantes\nComparado con el Promedio Global", fontsize=20, weight='bold')
plt.xlabel("Estudiante", fontsize=16)
plt.ylabel("Salario del Amigo", fontsize=16)
plt.xticks(fontsize=12, rotation=45, ha='right')
plt.yticks(fontsize=12)

plt.legend(fontsize=12, loc='upper right')

plt.show()

Problema 2

I) Dado un diccionario de productos cualesquiera que contiene el nombre de un producto arbitrario como clave y una lista de tuplas como valor, donde cada tupla representa un crédito, con la cantidad otorgada, tasa de interés anual y número de periodos en meses, de la siguiente manera:

Escribe una función en Python que retorne un diccionario con el nombre de cada producto y la tabla de amortización de cada crédito.

import pandas as pd

def calcular_tabla_amortizacion(productos):
    resultados = {}
    for producto, creditos in productos.items():
        tablas = []
        for monto, tasa_anual, periodos in creditos:
            if not periodos or periodos <= 0:
                tablas.append(f"Crédito inválido: Monto={monto}, Tasa={tasa_anual}, Periodos={periodos}")
                continue
            tasa_mensual = tasa_anual / 12
            pago_mensual = (monto * tasa_mensual * (1 + tasa_mensual) ** periodos) / ((1 + tasa_mensual) ** periodos - 1)
            saldo = monto
            tablas.append(pd.DataFrame([{
                "Periodo": p,
                "Pago Mensual": round(pago_mensual, 2),
                "Interés": round(saldo * tasa_mensual, 2),
                "Abono a Capital": round(pago_mensual - saldo * tasa_mensual, 2),
                "Saldo Restante": round((saldo := saldo - (pago_mensual - saldo * tasa_mensual)), 2)
            } for p in range(1, periodos + 1)]))
        resultados[producto] = tablas
    return resultados

productos = {
    "Producto 1": [(1000, 0.10, 24), (3000, 0.14, 24), (2000, 0.12, 36)],
    "Producto 2": [(5000, 0.08, 12), (7000, 0.16, 18), (6000, 0.12, None)],
    "Producto 3": [(11000, 0.06, 24), (9000, 0.17, 24)],
}

for producto, tablas in calcular_tabla_amortizacion(productos).items():
    print(f"\nTablas de amortización para {producto}:")
    for i, tabla in enumerate(tablas):
        print(f"\nCrédito {i + 1}:\n{tabla}" if isinstance(tabla, pd.DataFrame) else tabla)

II) Incluye en la función anterior como salida el cálculo de la duración del crédito. Esta se obtiene por medio de la siguiente fórmula:

donde:

𝑃 Saldo Insoluto del crédito

𝑛 Número de periodos

𝑓 Flujo del periodo k

𝑑 Días por vencer para el flujo del periodo k

𝑖 Tasa de interés anual

import pandas as pd

def calcular_tabla_amortizacion(productos):
    resultados = {}
    for producto, creditos in productos.items():
        tablas = []
        for monto, tasa_anual, periodos in creditos:
            if not periodos or periodos <= 0:
                tablas.append(f"Crédito inválido: Monto={monto}, Tasa={tasa_anual}, Periodos={periodos}")
                continue
            tasa_mensual = tasa_anual / 12
            pago_mensual = (monto * tasa_mensual * (1 + tasa_mensual) ** periodos) / ((1 + tasa_mensual) ** periodos - 1)
            saldo = monto
            tablas.append(pd.DataFrame([{
                "Periodo": p,
                "Pago Mensual": round(pago_mensual, 2),
                "Interés": round(saldo * tasa_mensual, 2),
                "Abono a Capital": round(pago_mensual - saldo * tasa_mensual, 2),
                "Saldo Restante": round((saldo := saldo - (pago_mensual - saldo * tasa_mensual)), 2)
            } for p in range(1, periodos + 1)]))
        resultados[producto] = tablas
    return resultados

def calcular_duracion_credito_desde_tabla(tablas_amortizacion):
    resultados = {}
    for producto, tablas in tablas_amortizacion.items():
        duraciones = []
        for tabla in tablas:
            if isinstance(tabla, pd.DataFrame):
                flujo_total = tabla["Pago Mensual"].sum()
                duracion = sum(tabla["Pago Mensual"] * (tabla["Periodo"] / 12))
                duracion_promedio = duracion / flujo_total if flujo_total else 0
                duraciones.append(round(duracion_promedio, 2))
            else:
                duraciones.append(tabla)
        resultados[producto] = duraciones
    return resultados

productos = {
    "Producto 1": [(1000, 0.10, 24), (3000, 0.14, 24), (2000, 0.12, 36)],
    "Producto 2": [(5000, 0.08, 12), (7000, 0.16, 18), (6000, 0.12, None)],
    "Producto 3": [(11000, 0.06, 24), (9000, 0.17, 24)],
}

tablas_amortizacion = calcular_tabla_amortizacion(productos)

duraciones_creditos = calcular_duracion_credito_desde_tabla(tablas_amortizacion)

for producto, duraciones in duraciones_creditos.items():
    print(f"\nDuraciones de los créditos para {producto}:")
    for i, duracion in enumerate(duraciones):
        print(f"Crédito {i + 1}: {duracion} años" if isinstance(duracion, (float, int)) else duracion)

III) Usando comprensión de listas y diccionarios, reescribe la función anterior para que el código sea más eficiente y compacto. El usuario debe ser capaz de escoger si sólo quiere ordenar los valores de los diccionarios, mostrar la tabla de amortización o ambos.

import pandas as pd

def procesar_creditos(productos, accion):
    tablas_amortizacion = {
        producto: [
            (lambda tasa_mensual=tasa_anual / 12: (
                (saldo := monto),
                pd.DataFrame([{
                    "Periodo": p,
                    "Pago Mensual": round((pago_mensual := (monto * tasa_mensual * (1 + tasa_mensual) ** periodos) /
                                          ((1 + tasa_mensual) ** periodos - 1)), 2),
                    "Interés": round(saldo * tasa_mensual, 2),
                    "Abono a Capital": round(pago_mensual - saldo * tasa_mensual, 2),
                    "Saldo Restante": round((saldo := saldo - (pago_mensual - saldo * tasa_mensual)), 2)
                } for p in range(1, periodos + 1)]) if periodos else f"Crédito inválido: Monto={monto}, Tasa={tasa_anual}, Periodos={periodos}"
            ))()[1]
            for monto, tasa_anual, periodos in creditos
        ]
        for producto, creditos in productos.items()
    }

    duraciones = {
        producto: [
            (
                lambda tabla: (
                    round((sum(tabla["Pago Mensual"] * (tabla["Periodo"] / 12)) / tabla["Pago Mensual"].sum()), 2)
                    if isinstance(tabla, pd.DataFrame) else tabla
                )
            )(tabla)
            for tabla in tablas
        ]
        for producto, tablas in tablas_amortizacion.items()
    }

    if accion == 0:
        return tablas_amortizacion
    elif accion == 1:
        return duraciones
    elif accion == 2:
        return {"duraciones": duraciones, "amortizacion": tablas_amortizacion}
    else:
        raise ValueError("Acción no válida. Usa 0, 1 o 2.")

productos = {
    "Producto 1": [(1000, 0.10, 24), (3000, 0.14, 24), (2000, 0.12, 36)],
    "Producto 2": [(5000, 0.08, 12), (7000, 0.16, 18), (6000, 0.12, None)],
    "Producto 3": [(11000, 0.06, 24), (9000, 0.17, 24)],
}

while True:
    print("\nSeleccione una opción:")
    print("0: Ver tablas de amortización")
    print("1: Ver duración de los créditos")
    print("2: Ver ambas")

    try:
        accion = int(input("Ingrese su elección (0, 1 o 2): "))
        if accion not in [0, 1, 2]:
            raise ValueError("Opción fuera de rango. Debe ser 0, 1 o 2.")
        
        resultado = procesar_creditos(productos, accion)

        if accion == 0:
            print("\nTablas de amortización:")
            for producto, tablas in resultado.items():
                print(f"\nTablas de amortización para {producto}:")
                for i, tabla in enumerate(tablas):
                    print(f"\nCrédito {i + 1}:\n{tabla}" if isinstance(tabla, pd.DataFrame) else tabla)
        elif accion == 1:
            print("\nDuraciones de los créditos:")
            for producto, duraciones in resultado.items():
                print(f"\nDuraciones para {producto}:")
                for i, duracion in enumerate(duraciones):
                    if isinstance(duracion, (float, int)):
                        print(f"Crédito {i + 1}: {duracion} años")
                    else:
                        print(f"Crédito {i + 1}: {duracion}")
        elif accion == 2:
            print("\nDuraciones:")
            for producto, duraciones in resultado["duraciones"].items():
                print(f"\nDuraciones para {producto}:")
                for i, duracion in enumerate(duraciones):
                    if isinstance(duracion, (float, int)):
                        print(f"Crédito {i + 1}: {duracion} años")
                    else:
                        print(f"Crédito {i + 1}: {duracion}")
            print("\nTablas de amortización:")
            for producto, tablas in resultado["amortizacion"].items():
                print(f"\nTablas de amortización para {producto}:")
                for i, tabla in enumerate(tablas):
                    print(f"\nCrédito {i + 1}:\n{tabla}" if isinstance(tabla, pd.DataFrame) else tabla)
        break
    except ValueError as e:
        print(f"Error: {e}. Por favor, inténtelo de nuevo.")

Problema 3

I) Diseña una función en Python que, dado un arreglo de enteros (puede incluir númerosnegativos), encuentre el subarreglo contiguo con la suma más alta. Usa el siguiente algoritmo para optimizar su función:

𝑚𝑎𝑥𝑡(𝑖) = 𝑚𝑎𝑥(𝐴[𝑖], 𝑚𝑎𝑥𝑡(𝑖−1) + 𝐴[𝑖])

En dónde 𝑚𝑎𝑥 es la suma máxima del subarreglo que termina en el índice 𝑖 en el tiempo 𝑡 y 𝐴[𝑖] es el valor actual del arreglo.

Ejemplo: 𝐴 = [− 2, 1, − 3, 4, − 1, 2, 1, − 5, 4]

Inicializando tenemos que 𝑚𝑎𝑥𝑡(𝑖) =− 2 por tanto el máximo actual es -2.

Luego, hacemos 𝑚𝑎𝑥𝑡(𝑖) = 𝑚𝑎𝑥(1, − 2 + 1) = 𝑚𝑎𝑥(1, − 1) = 1 máximo hasta esta iteración: 1

Ahora, para el índice 2 cuyo valor es -3: 𝑚𝑎𝑥𝑡(𝑖) = 𝑚𝑎𝑥(− 3, 1 + (− 3)) = 𝑚𝑎𝑥(− 3, − 2) =− 2 máximo hasta esta iteración: 1

Y así sucesivamente para cada índice. Al final, el resultado es la suma máxima de un subarreglo contiguo.

def max_subarray_sum(arr):
    max_current = arr[0]
    max_global = arr[0]

    for i in range(1, len(arr)):
        max_current = max(arr[i], max_current + arr[i])
        max_global = max(max_global, max_current)

    return max_global

A = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
resultado = max_subarray_sum(A)
print(f"La suma máxima de un subarreglo contiguo es: {resultado}")

II) Crea una función o clase en Python que reciba una lista de montos de créditos solicitados por los clientes y un capital disponible total del banco. La función o clase debe encontrar la mayor cantidad de créditos que se pueden aprobar sin exceder el capital disponible.