Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,001 changes: 1,001 additions & 0 deletions data/raw/crocodile_dataset.csv

Large diffs are not rendered by default.

Binary file added models/decision_tree_common_name_model.pkl
Binary file not shown.
Binary file added models/decision_tree_genus_model.pkl
Binary file not shown.
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ scikit-learn
seaborn>=0.12.2
sqlalchemy>=2.0.38
sympy>=1.10.1
xgboost
xgboost
flask
40 changes: 37 additions & 3 deletions src/app.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,38 @@
from utils import db_connect
engine = db_connect()
import flask
from flask import Flask, render_template, request
import numpy as np
from utils import predict_with_dt, category_mapping, get_keys_from_value
from pickle import load

# your code here
app = Flask(__name__)

# Load the models
dt_genus = load(open('../models/decision_tree_genus_model.pkl', "rb"))
dt_common_name = load(open('../models/decision_tree_common_name_model.pkl', "rb"))


# Define routes

@app.route('/', methods=['GET', 'POST'])
def predict():
if request.method == 'POST':
try:
length = float(request.form['length'])
weight = float(request.form['weight'])
age_class = request.form['age_class']
sex = request.form['sex']
habitat_type = request.form['habitat_type']
country_region = request.form['country_region']

genus, common_name = predict_with_dt(length, weight, age_class, sex, habitat_type, country_region, dt_genus, dt_common_name, category_mapping)

return render_template('index.html', genus=genus, common_name=common_name)

except Exception as e:
return render_template('index.html', error=str(e))
#correr otro html de error

return render_template('index.html', genus=None, common_name=None)

if __name__ == '__main__':
app.run(debug=True, port=5000)
696 changes: 686 additions & 10 deletions src/explore.ipynb

Large diffs are not rendered by default.

194 changes: 194 additions & 0 deletions src/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Aplicación de Predicción</title>
<!-- Incluye el CDN de Tailwind CSS para un estilo rápido y moderno -->
<script src="https://cdn.tailwindcss.com"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Inter', sans-serif;
background-color: #f3f4f6;
}
</style>
</head>
<body class="flex items-center justify-center min-h-screen">

<div class="bg-white p-8 rounded-2xl shadow-xl max-w-md w-full mx-4">
<div class="text-center">
<h1 class="text-3xl font-bold text-gray-800 mb-2">Predictor de Especies</h1>
<p class="text-gray-600 mb-6">Introduce los datos para obtener una predicción.</p>
</div>

<!-- Formulario para la entrada de datos -->
<form action="/" method="post" class="space-y-4">

<!-- Campo de entrada para 'length' -->
<div>
<label for="length" class="block text-sm font-medium text-gray-700">Longitud (cm)</label>
<input type="number" id="length" name="length" placeholder="Ej: 20" step="0.5" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm">
</div>

<!-- Campo de entrada para 'weight' -->
<div>
<label for="weight" class="block text-sm font-medium text-gray-700">Peso (kg)</label>
<input type="number" id="weight" name="weight" placeholder="Ej: 150" step="0.5" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm">
</div>

<!-- Selector para 'age_class' -->
<div>
<label for="age_class" class="block text-sm font-medium text-gray-700">Clase de Edad</label>
<select id="age_class" name="age_class" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm">
<option value="" disabled selected>Seleccionar clase de edad</option>
<option value="Adult">Adulto</option>
<option value="Hatchling">Cría</option>
<option value="Juvenile">Juvenil</option>
<option value="Subadult">Subadulto</option>
</select>
</div>

<!-- Selector para 'sex' -->
<div>
<label for="sex" class="block text-sm font-medium text-gray-700">Género</label>
<select id="sex" name="sex" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm">
<option value="" disabled selected>Seleccionar género</option>
<option value="Female">Femenino</option>
<option value="Male">Masculino</option>
<option value="Unknown">Desconocido</option>
</select>
</div>

<!-- Selector para 'habitat_type' -->
<div>
<label for="habitat_type" class="block text-sm font-medium text-gray-700">Tipo de Hábitat</label>
<select id="habitat_type" name="habitat_type" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm">
<option value="" disabled selected>Seleccionar hábitat</option>
<option value="Billabongs">Billabongs</option>
<option value="Brackish Rivers">Ríos de Agua Salobre</option>
<option value="Coastal Lagoons">Lagunas Costeras</option>
<option value="Coastal Wetlands">Humedales Costeros</option>
<option value="Estuaries">Estuarios</option>
<option value="Estuarine Systems">Sistemas Estuarinos</option>
<option value="Flooded Savannas">Sabanas Inundadas</option>
<option value="Forest Rivers">Ríos Forestales</option>
<option value="Forest Swamps">Pantanos Forestales</option>
<option value="Freshwater Marshes">Marismas de Agua Dulce</option>
<option value="Freshwater Rivers">Ríos de Agua Dulce</option>
<option value="Freshwater Wetlands">Humedales de Agua Dulce</option>
<option value="Gorges">Gargantas</option>
<option value="Lagoons">Lagunas</option>
<option value="Lakes">Lagos</option>
<option value="Large Rivers">Grandes Ríos</option>
<option value="Mangroves">Manglares</option>
<option value="Marshes">Marismas</option>
<option value="Oases">Oasis</option>
<option value="Oxbow Lakes">Lagos de Meandro</option>
<option value="Ponds">Estanques</option>
<option value="Reservoirs">Embalses</option>
<option value="Rivers">Ríos</option>
<option value="Shaded Forest Rivers">Ríos Forestales Sombreados</option>
<option value="Slow Rivers">Ríos de Flujo Lento</option>
<option value="Slow Streams">Arroyos de Flujo Lento</option>
<option value="Small Streams">Pequeños Arroyos</option>
<option value="Swamps">Pantanos</option>
<option value="Tidal Rivers">Ríos de Marea</option>
</select>
</div>

<!-- Selector para 'country_region' -->
<div>
<label for="country_region" class="block text-sm font-medium text-gray-700">País/Región</label>
<select id="country_region" name="country_region" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm">
<option value="" disabled selected>Seleccionar país/región</option>
<option value="Australia">Australia</option>
<option value="Belize">Belice</option>
<option value="Cambodia">Camboya</option>
<option value="Cameroon">Camerún</option>
<option value="Central African Republic">República Centroafricana</option>
<option value="Chad">Chad</option>
<option value="Colombia">Colombia</option>
<option value="Congo (DRC)">Congo (RDC)</option>
<option value="Congo Basin Countries">Países de la Cuenca del Congo</option>
<option value="Costa Rica">Costa Rica</option>
<option value="Cuba">Cuba</option>
<option value="Côte d'Ivoire">Costa de Marfil</option>
<option value="Egypt">Egipto</option>
<option value="Gabon">Gabón</option>
<option value="Ghana">Ghana</option>
<option value="Guatemala">Guatemala</option>
<option value="Guinea">Guinea</option>
<option value="India">India</option>
<option value="Indonesia">Indonesia</option>
<option value="Indonesia (Borneo)">Indonesia (Borneo)</option>
<option value="Indonesia (Papua)">Indonesia (Papúa)</option>
<option value="Iran (historic)">Irán (histórico)</option>
<option value="Kenya">Kenia</option>
<option value="Laos">Laos</option>
<option value="Liberia">Liberia</option>
<option value="Malaysia">Malasia</option>
<option value="Malaysia (Borneo)">Malasia (Borneo)</option>
<option value="Mali">Mali</option>
<option value="Mauritania">Mauritania</option>
<option value="Mexico">México</option>
<option value="Nepal">Nepal</option>
<option value="Niger">Níger</option>
<option value="Nigeria">Nigeria</option>
<option value="Pakistan">Pakistán</option>
<option value="Papua New Guinea">Papúa Nueva Guinea</option>
<option value="Philippines">Filipinas</option>
<option value="Senegal">Senegal</option>
<option value="Sierra Leone">Sierra Leona</option>
<option value="South Africa">Sudáfrica</option>
<option value="Sri Lanka">Sri Lanka</option>
<option value="Sudan">Sudán</option>
<option value="Tanzania">Tanzania</option>
<option value="Thailand">Tailandia</option>
<option value="USA (Florida)">EE.UU. (Florida)</option>
<option value="Uganda">Uganda</option>
<option value="Venezuela">Venezuela</option>
<option value="Vietnam">Vietnam</option>
</select>
</div>

<!-- Botón de envío del formulario -->
<button type="submit"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
Predecir
</button>
</form>

<!-- Sección para mostrar los resultados de la predicción -->
{% if genus and common_name %}
<div class="mt-6 p-4 bg-green-50 border-l-4 border-green-400 rounded-md">
<h2 class="text-lg font-bold text-green-800">Resultados de la Predicción:</h2>
<p class="mt-1 text-sm text-green-700">
<span class="font-semibold">Género:</span> {{ genus }}
</p>
<p class="mt-1 text-sm text-green-700">
<span class="font-semibold">Nombre Común:</span> {{ common_name }}
</p>
</div>
{% endif %}

<!-- Sección para mostrar los errores -->
{% if error %}
<div class="mt-6 p-4 bg-red-50 border-l-4 border-red-400 rounded-md">
<h2 class="text-lg font-bold text-red-800">¡Error!</h2>
<p class="mt-1 text-sm text-red-700">{{ error }}</p>
</div>
{% endif %}

</div>

</body>
</html>
51 changes: 46 additions & 5 deletions src/utils.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,54 @@
from dotenv import load_dotenv
from sqlalchemy import create_engine
import numpy as np
import pandas as pd

# load the .env file variables
load_dotenv()
from sqlalchemy import create_engine


def db_connect():
import os
engine = create_engine(os.getenv('DATABASE_URL'))
engine.connect()
return engine

def get_keys_from_value(dictionary, value_to_find):
return [key for key, val in dictionary.items() if val == value_to_find]

def predict_with_dt(length, weight, age_class, sex, habitat_type, country_region, model_genus, model_common_name, category_mapping):
"""
Predicts the Genus and Common Name of a crocodile using a pre-trained Decision Tree model.

Args:
length (float): Observed length of the crocodile in meters.
weight (float): Observed weight of the crocodile in kilograms.
age_class (str): Age class of the crocodile (e.g., 'Adult', 'Juvenile').
sex (str): Sex of the crocodile (e.g., 'Male', 'Female').
habitat_type (str): Type of habitat where the crocodile was observed (e.g., 'Rivers', 'Swamps').
country_region (str): Country or region where the crocodile was observed (e.g., 'Australia', 'Africa').
model_genus (DecisionTreeClassifier): Pre-trained Decision Tree model for Genus prediction.
model_common_name (DecisionTreeClassifier): Pre-trained Decision Tree model for Common Name prediction.
category_mapping (dict): Dictionary containing the mapping of categorical values to numerical codes.

Returns:
tuple: A tuple containing the predicted Genus and Common Name.
"""

# Convert input strings to numerical categories using the provided mapping
age_class_encoded = get_keys_from_value(category_mapping['Age Class'], age_class)[0]
sex_encoded = get_keys_from_value(category_mapping['Sex'],sex)[0]
habitat_type_encoded = get_keys_from_value(category_mapping['Habitat Type'],habitat_type)[0]
country_region_encoded = get_keys_from_value(category_mapping['Country/Region'],country_region)[0]


# Create a feature array from the input values
features = np.array([length, weight, age_class_encoded, sex_encoded, habitat_type_encoded, country_region_encoded]).reshape(1, -1)

# Predict the Genus and Common Name using the pre-trained models
genus_encoded = model_genus.predict(features)[0]
common_name_encoded = model_common_name.predict(features)[0]

genus = category_mapping['Genus'][genus_encoded]
common_name = category_mapping['Common Name'][common_name_encoded]

return genus, common_name


category_mapping = {'Age Class': {0: 'Adult', 1: 'Hatchling', 2: 'Juvenile', 3: 'Subadult'}, 'Sex': {0: 'Female', 1: 'Male', 2: 'Unknown'}, 'Genus': {0: 'Crocodylus', 1: 'Mecistops', 2: 'Osteolaemus'}, 'Common Name': {0: 'American Crocodile', 1: 'Borneo Crocodile (disputed)', 2: 'Central African Slender-snouted Crocodile', 3: 'Congo Dwarf Crocodile', 4: 'Cuban Crocodile', 5: "Freshwater Crocodile (Johnstone's)", 6: "Hall's New Guinea Crocodile", 7: "Morelet's Crocodile", 8: 'Mugger Crocodile (Marsh Crocodile)', 9: 'New Guinea Crocodile', 10: 'Nile Crocodile', 11: 'Orinoco Crocodile', 12: 'Philippine Crocodile', 13: 'Saltwater Crocodile', 14: 'Siamese Crocodile', 15: 'West African Crocodile', 16: 'West African Dwarf Crocodile', 17: 'West African Slender-snouted Crocodile'}, 'Habitat Type': {0: 'Billabongs', 1: 'Brackish Rivers', 2: 'Coastal Lagoons', 3: 'Coastal Wetlands', 4: 'Estuaries', 5: 'Estuarine Systems', 6: 'Flooded Savannas', 7: 'Forest Rivers', 8: 'Forest Swamps', 9: 'Freshwater Marshes', 10: 'Freshwater Rivers', 11: 'Freshwater Wetlands', 12: 'Gorges', 13: 'Lagoons', 14: 'Lakes', 15: 'Large Rivers', 16: 'Mangroves', 17: 'Marshes', 18: 'Oases', 19: 'Oxbow Lakes', 20: 'Ponds', 21: 'Reservoirs', 22: 'Rivers', 23: 'Shaded Forest Rivers', 24: 'Slow Rivers', 25: 'Slow Streams', 26: 'Small Streams', 27: 'Swamps', 28: 'Tidal Rivers'}, 'Country/Region': {0: 'Australia', 1: 'Belize', 2: 'Cambodia', 3: 'Cameroon', 4: 'Central African Republic', 5: 'Chad', 6: 'Colombia', 7: 'Congo (DRC)', 8: 'Congo Basin Countries', 9: 'Costa Rica', 10: 'Cuba', 11: "Côte d'Ivoire", 12: 'Egypt', 13: 'Gabon', 14: 'Ghana', 15: 'Guatemala', 16: 'Guinea', 17: 'India', 18: 'Indonesia', 19: 'Indonesia (Borneo)', 20: 'Indonesia (Papua)', 21: 'Iran (historic)', 22: 'Kenya', 23: 'Laos', 24: 'Liberia', 25: 'Malaysia', 26: 'Malaysia (Borneo)', 27: 'Mali', 28: 'Mauritania', 29: 'Mexico', 30: 'Nepal', 31: 'Niger', 32: 'Nigeria', 33: 'Pakistan', 34: 'Papua New Guinea', 35: 'Philippines', 36: 'Senegal', 37: 'Sierra Leone', 38: 'South Africa', 39: 'Sri Lanka', 40: 'Sudan', 41: 'Tanzania', 42: 'Thailand', 43: 'USA (Florida)', 44: 'Uganda', 45: 'Venezuela', 46: 'Vietnam'}}