El Sistema de Ventas Integrado con Machine Learning de Análisis Predictivo esta diseñada para optimizar la gestión de ventas, inventarios y análisis predictivo en una sola solución. Esta herramienta avanzada utiliza algoritmos de Machine Learning para proporcionar predicciones precisas sobre ventas futuras, rotación de inventarios y rentabilidad de productos, ayudando a las empresas a tomar decisiones informadas y estratégicas.
Antes: 85 USD
Descuento: -40%
Ahora: 51 USD
A continuación te organizo la información más detallado acerca del sistema, los módulos que componen y sus características; asimismo de como ejecutarlo correctamente dicho sistema en el servidor local y otros detalles interesantes.
2. Capturas del sistema de sistema de ventas integrado con Machine Learning de análisis predictivo
Inicio del sistema
Tiene una interfaz y un diseño amigable tal como se muestra en la siguiente figura, y los menús en forma horizontal, un sistema bastante completo muy funcional y útil para lo que se requiere.

Módulo de situación actual
Este módulo permite mostrar los datos actuales de manera totalitaria mostrando la cantidad de compras y ventas segmentado por mes.

INFORMACIÓN DE DESARROLLO
1. Principios de Programación Web y Desarrollo de Software
- Separation of Concerns (SoC): El código PHP se encarga de la lógica de negocio y el manejo de datos, mientras que el JavaScript (con ApexCharts) se encarga de la presentación y la interacción del usuario.
- Uso de Librerías de Terceros: Utiliza ApexCharts para la visualización de datos, lo cual es una buena práctica en desarrollo de software ya que aprovecha soluciones probadas y robustas para tareas específicas, en este caso, gráficos interactivos.
2. Visualización de Datos
- Teoría de Visualización de Datos: La visualización de datos se basa en principios para presentar la información de manera clara y comprensible. Este script utiliza gráficos de barras, líneas, área y torta, cada uno adecuado para diferentes tipos de análisis de datos (comparación, tendencias, distribución).
3. Análisis de Datos
- Resumir y Agrupar Datos: La consulta SQL agrupa los datos por mes y año y los resume (usando
SUM
) para proporcionar una visión más manejable y significativa de los datos.
5. Principios de Usabilidad y Diseño de Interfaces
- Principios de Usabilidad: Proveer una interfaz clara y simple con un menú desplegable para seleccionar el tipo de gráfico mejora la usabilidad, permitiendo a los usuarios cambiar fácilmente la visualización según sus necesidades.
- Feedback Inmediato: La interactividad y la actualización dinámica del gráfico proporcionan un feedback inmediato al usuario, mejorando la experiencia de usuario.
Código
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script> <?php $base = Database::getInstance(); $con = $base->getConnection(); $query = "SELECT MONTH(fecha) AS mes, YEAR(fecha) AS anio, accion, SUM(cantidad) as cantidad_total FROM proceso GROUP BY anio, mes, accion"; $result = mysqli_query($con, $query); $data = array( 'compra' => array_fill(1, 12, 0), // Inicializa un array con 12 elementos con valor 0 'venta' => array_fill(1, 12, 0) // Inicializa un array con 12 elementos con valor 0 ); while ($row = mysqli_fetch_assoc($result)) { switch ($row['accion']) { case 1: $data['compra'][$row['mes']] = $row['cantidad_total']; break; case 2: $data['venta'][$row['mes']] = $row['cantidad_total']; break; } } ?> <div class="container"> <label for="chartType">Selecciona el tipo de gráfico:</label> <select id="chartType"> <option value="bar">Gráfico de Barras</option> <option value="line">Gráfico de Líneas</option> <option value="area">Gráfico de Área</option> <option value="pie">Gráfico de Torta</option> </select> <div id="chart"></div> </div> <script src="https://cdn.jsdelivr.net/npm/apexcharts"></script> <script> var chartTypeSelect = document.getElementById('chartType'); var chart; function renderChart(chartType) { if (chart) { chart.destroy(); } var options = { // Configuración del gráfico chart: { type: chartType, height: 400, toolbar: { show: false } }, // Datos del gráfico series: [{ name: 'Compras', data: <?= json_encode(array_values($data['compra'])) ?> }, { name: 'Ventas', data: <?= json_encode(array_values($data['venta'])) ?> }], // Configuración del eje X xaxis: { categories: <?= json_encode(array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic')) ?> }, // Configuración del eje Y yaxis: { title: { text: 'Cantidad', style: { color: '#333', fontSize: '16px' } }, labels: { style: { colors: '#333', fontSize: '14px' } } }, // Configuración de la leyenda legend: { position: 'top', horizontalAlign: 'center', offsetY: -20, labels: { colors: '#333', fontSize: '14px' } }, // Configuración de la cuadrícula grid: { borderColor: '#ccc' } }; if (chartType === 'pie') { // Configuración adicional para el gráfico de pie options.labels = <?= json_encode(array_keys($data['compra'])) ?>; options.chart.type = 'pie'; options.chart.sparkline = { enabled: true }; } // Crear el gráfico chart = new ApexCharts(document.querySelector("#chart"), options); chart.render(); } // Evento de cambio de selección del tipo de gráfico chartTypeSelect.addEventListener('change', function () { renderChart(this.value); }); // Renderizar el gráfico inicialmente renderChart(chartTypeSelect.value); </script>
Análisis y predicción de inventario y rentabilidad
En este módulo verificamos la variación de las ventas realizadas en meses anteriores y, de igual modo, tenemos los datos de los próximos meses. La cantidad predicha nos permite calcular si alcanzaremos buenos niveles de venta o no.

INFORMACIÓN DEL DESARROLLO
El script integra prácticas y metodologías sólidas de desarrollo web, visualización de datos y aprendizaje automático. Aplica principios y técnicas estándar en el procesamiento de datos, modelado predictivo y visualización interactiva, proporcionando una solución completa para el análisis y predicción de inventario y rentabilidad en el navegador.
1. Visualización de Datos
- Uso de Librerías de Visualización: Utiliza Chart.js para visualizar datos históricos de ventas en un gráfico de líneas. Esto sigue la práctica común de utilizar librerías especializadas para tareas específicas, permitiendo una visualización clara y comprensible de los datos.
- Interactividad: La capacidad de mostrar y actualizar datos en un gráfico interactivo mejora la experiencia del usuario y facilita la comprensión de los datos.
2. Preparación y Procesamiento de Datos
- Extracción y Transformación de Datos: Se realiza una consulta a la base de datos para obtener datos históricos de ventas, los cuales se transforman y agrupan por mes y artículo. Esta es una práctica común en el preprocesamiento de datos para análisis y visualización.
- Agrupación y Resumen de Datos: Los datos se agrupan y se cuentan por mes y artículo, lo cual es esencial para analizar tendencias temporales.
3. Aprendizaje Automático (Machine Learning)
- Uso de TensorFlow.js: Se utiliza TensorFlow.js para crear, entrenar y predecir con un modelo de aprendizaje automático directamente en el navegador. Esto permite llevar las capacidades de ML al cliente sin necesidad de un servidor backend para procesar los datos.
- Modelado Predictivo: Se construye un modelo de red neuronal para predecir futuras ventas. El modelo incluye capas densas (fully connected layers) y una capa de dropout para prevenir el sobreajuste.
- Capas Densas y Dropout: Estas son técnicas estándar en la construcción de redes neuronales para modelado predictivo.
- Optimización con Adam: El modelo se compila con el optimizador Adam, que es popular en el entrenamiento de redes neuronales debido a su eficiencia y buen rendimiento en muchas tareas.
4. Metodologías y Teorías Aplicadas
- Early Stopping: Utiliza callbacks de parada temprana (
earlyStopping
) para detener el entrenamiento del modelo si el rendimiento en la validación no mejora después de un cierto número de épocas. Esto es una técnica común para evitar el sobreajuste. - Separación de Entrenamiento y Validación: Divide los datos en entrenamiento y validación (
validationSplit: 0.2
) para evaluar el rendimiento del modelo de manera más robusta. - Predicción de Datos Futuros: Genera predicciones para los próximos seis meses y actualiza el gráfico con estas predicciones. Esto es una aplicación práctica del modelado predictivo para la toma de decisiones basada en datos.
5. Buenas Prácticas de Programación y Desarrollo Web
- Modularización del Código: El código está dividido en funciones que manejan diferentes tareas (preparación de datos, generación de colores aleatorios, renderización del gráfico), lo cual facilita la comprensión y el mantenimiento del código.
- Asincronía y Promesas: Utiliza
async/await
y promesas para manejar operaciones asincrónicas, como el entrenamiento del modelo y la predicción de datos futuros, garantizando una ejecución ordenada y evitando bloqueos en el navegador.
6. Pruebas y Depuración
- Uso de
console.log
: Se utilizan logs en la consola para verificar los datos en diferentes etapas del procesamiento y modelado, lo cual es útil para la depuración y aseguramiento de la calidad del código.
Código
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns"></script> <canvas id="salesChart" width="400" height="200"></canvas> <?php $base = Database::getInstance(); $conn = $base->getConnection(); $sql = " SELECT p.id, p.articulo, p.cantidad, p.precio, p.total, p.accion, p.fecha, a.nombre, a.categoria, a.marca, a.serie, a.modelo, a.estado, a.color FROM proceso p JOIN articulo a ON p.articulo = a.id WHERE p.accion = 2 "; $result = $conn->query($sql); $data = []; if ($result->num_rows > 0) { while($row = $result->fetch_assoc()) { $date = new DateTime($row['fecha']); $month = $date->format('Y-m'); $article = $row['articulo']; if (!isset($data[$month])) { $data[$month] = []; } if (!isset($data[$month][$article])) { $data[$month][$article] = 0; } $data[$month][$article]++; } } $conn->close(); echo "<script>console.log('Sales Data:', " . json_encode($data) . ");</script>"; echo "<script>var salesData = " . json_encode($data) . ";</script>"; ?> <script> function prepareData(data) { const labels = Object.keys(data).sort(); const articles = [...new Set(labels.flatMap(month => Object.keys(data[month])))]; const dataset = articles.map(article => { return { label: `Producto ${article}`, data: labels.map(month => data[month][article] || 0), fill: false, borderColor: getRandomColor(), tension: 0.1 }; }); return { labels, dataset }; } function getRandomColor() { const letters = '0123456789ABCDEF'; let color = '#'; for (let i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } return color; } console.log('Sales Data:', salesData); const { labels, dataset } = prepareData(salesData); console.log('Labels:', labels); console.log('Dataset:', dataset); const ctx = document.getElementById('salesChart').getContext('2d'); const salesChart = new Chart(ctx, { type: 'line', data: { labels: labels, datasets: dataset }, options: { scales: { x: { type: 'time', time: { unit: 'month' }, title: { display: true, text: 'Mes' } }, y: { ticks: { callback: function(value) { return Math.round(value); // Mostrar valores enteros } }, title: { display: true, text: 'Ventas' } } }, plugins: { tooltip: { callbacks: { label: function(context) { return `Producto: ${context.dataset.label.split(' ')[1]}, Ventas: ${Math.round(context.raw)}`; } } } } } }); async function generateFutureData() { const model = tf.sequential(); model.add(tf.layers.dense({units: 128, inputShape: [1], activation: 'relu'})); model.add(tf.layers.dense({units: 128, activation: 'relu'})); model.add(tf.layers.dropout({rate: 0.2})); model.add(tf.layers.dense({units: 64, activation: 'relu'})); model.add(tf.layers.dense({units: dataset.length})); model.compile({optimizer: tf.train.adam(), loss: 'meanSquaredError'}); const xs = tf.tensor2d(labels.map((_, i) => [i]), [labels.length, 1]); const ys = tf.tensor2d(labels.map((_, i) => dataset.map(d => d.data[i] || 0)), [labels.length, dataset.length]); await model.fit(xs, ys, { epochs: 2000, validationSplit: 0.2, callbacks: tf.callbacks.earlyStopping({monitor: 'val_loss', patience: 50}) }); const futureX = tf.tensor2d([...Array(6).keys()].map(i => [i + labels.length]), [6, 1]); const predictions = model.predict(futureX); predictions.array().then(preds => { const futureLabels = Array.from({length: 6}, (_, i) => { const date = new Date(labels[labels.length - 1]); date.setMonth(date.getMonth() + i + 1); return date.toISOString().substring(0, 7); }); const futureDataset = dataset.map((d, i) => ({ ...d, data: [...d.data, ...preds.map(p => Math.round(p[i]))] // Redondear predicciones a enteros })); salesChart.data.labels = [...labels, ...futureLabels]; salesChart.data.datasets = futureDataset; salesChart.update(); }); } generateFutureData(); </script>
Análisis y predicción de inventario y rentabilidad
Este módulo nos permite analizar y predecir la rotación del inventario y el tiempo de permanencia en el stock hasta su primera salida. Además, indica si el producto realiza su primera salida y evalúa si es rentable dentro del tiempo que ha permanecido en el inventario.

INFORMACIÓN DEL DESARROLLO
Para lograr el objetivo se integra prácticas y metodologías sólidas de desarrollo web, visualización de datos y aprendizaje automático. Aplica principios y técnicas estándar en el procesamiento de datos, modelado predictivo y visualización interactiva, proporcionando una solución completa para el análisis y predicción de inventario y rentabilidad en el navegador.
1. Visualización de Datos
- Uso de Chart.js: Utiliza Chart.js para visualizar datos en un gráfico de burbujas. Esto sigue la práctica común de utilizar librerías especializadas para la visualización de datos, lo que facilita la interpretación y análisis visual de la información.
- Visualización de Rentabilidad y Duración en Inventario: El gráfico de burbujas muestra la rentabilidad y la duración promedio en inventario de los artículos, lo cual es útil para identificar patrones y tendencias.
2. Preparación y Procesamiento de Datos
- Extracción y Transformación de Datos: Se realiza una consulta a la base de datos para obtener datos históricos de inventario y ventas, los cuales se transforman y agrupan según sea necesario. Esta es una práctica común en el preprocesamiento de datos para análisis y visualización.
- Agrupación y Resumen de Datos: Los datos se agrupan y se procesan para calcular la duración en inventario y la rentabilidad, lo cual es esencial para analizar el desempeño de los productos.
3. Aprendizaje Automático (Machine Learning)
- Uso de TensorFlow.js: Se utiliza TensorFlow.js para crear, entrenar y predecir con un modelo de aprendizaje automático directamente en el navegador. Esto permite llevar las capacidades de ML al cliente sin necesidad de un servidor backend para procesar los datos.
- Modelado Predictivo: Se construye un modelo de red neuronal para predecir futuras duraciones en inventario y rentabilidad. El modelo incluye capas densas (fully connected layers).
- Capas Densas: Estas son técnicas estándar en la construcción de redes neuronales para modelado predictivo.
- Optimización con SGD: El modelo se compila con el optimizador SGD (Stochastic Gradient Descent), que es popular en el entrenamiento de redes neuronales debido a su simplicidad y eficacia en ciertos tipos de problemas.
- Ajuste de Variabilidad en Predicciones: Se agrega un factor de variabilidad a las predicciones para simular un rango más realista de posibles resultados.
4. Metodologías y Teorías Aplicadas
- Promedios y Sumas: Para calcular la duración promedio en inventario y la rentabilidad total de los productos, se utilizan operaciones matemáticas básicas como promedios y sumas.
- Regresión Lineal: La estructura del modelo de red neuronal utilizada aquí es similar a una regresión lineal, donde se intenta encontrar una relación entre las características de entrada (duración en inventario) y la salida (rentabilidad).
- Predicción de Datos Futuros: Genera predicciones para los próximos seis meses y actualiza el gráfico con estas predicciones. Esto es una aplicación práctica del modelado predictivo para la toma de decisiones basada en datos.
Código
<?php $base = Database::getInstance(); $conn = $base->getConnection(); $sql = " SELECT p.id, p.articulo, p.cantidad, p.precio, p.total, p.accion, p.fecha, a.nombre, a.categoria, a.marca, a.serie, a.modelo, a.estado, a.color FROM proceso p JOIN articulo a ON p.articulo = a.id "; $result = $conn->query($sql); $inventory_duration = []; $profit_data = []; $sales_data = []; if ($result->num_rows > 0) { while($row = $result->fetch_assoc()) { $date = new DateTime($row['fecha']); $article = $row['articulo']; $quantity = $row['cantidad']; if ($row['accion'] == 1) { // Entrada if (!isset($inventory_duration[$article])) { $inventory_duration[$article] = []; } $inventory_duration[$article]['entrada'] = $date->getTimestamp(); } elseif ($row['accion'] == 2) { // Salida if (isset($inventory_duration[$article]['entrada'])) { $entrada = $inventory_duration[$article]['entrada']; $salida = $date->getTimestamp(); $duration = ($salida - $entrada) / (60 * 60 * 24); // Duración en días if (!isset($inventory_duration[$article]['duraciones'])) { $inventory_duration[$article]['duraciones'] = []; } $inventory_duration[$article]['duraciones'][] = $duration; } if (!isset($profit_data[$article])) { $profit_data[$article] = ['price' => 0, 'quantity' => 0]; } $profit_data[$article]['price'] = $row['precio']; $profit_data[$article]['quantity'] += $quantity; if (!isset($sales_data[$article])) { $sales_data[$article] = []; } $sales_data[$article][] = ['date' => $date->format('Y-m-d'), 'quantity' => $quantity]; } } } $conn->close(); echo "<script>console.log('Inventory Duration:', " . json_encode($inventory_duration) . ");</script>"; echo "<script>console.log('Profit Data:', " . json_encode($profit_data) . ");</script>"; echo "<script>console.log('Sales Data:', " . json_encode($sales_data) . ");</script>"; echo "<script>var inventoryDuration = " . json_encode($inventory_duration) . ";</script>"; echo "<script>var profitData = " . json_encode($profit_data) . ";</script>"; echo "<script>var salesData = " . json_encode($sales_data) . ";</script>"; ?> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns"></script> <canvas id="combinedChart" width="400" height="200"></canvas> <script> function calculateAverageDuration(data) { const result = {}; for (const article in data) { const durations = data[article].duraciones; if (durations && durations.length > 0) { result[article] = durations.reduce((a, b) => a + b, 0) / durations.length; } else { result[article] = 0; } } return result; } function prepareCombinedData(inventoryDuration, profitData) { const articles = Object.keys(inventoryDuration); const avgDurations = calculateAverageDuration(inventoryDuration); const dataset = articles.map(article => { const totalProfit = profitData[article]['price'] * profitData[article]['quantity']; return { label: `Artículo ${article}`, data: [{ x: avgDurations[article], y: totalProfit, r: 5 // Radio de la burbuja, se puede ajustar según sea necesario }], backgroundColor: totalProfit > 1000 ? 'rgba(75, 192, 192, 0.2)' : 'rgba(255, 99, 132, 0.2)', borderColor: totalProfit > 1000 ? 'rgba(75, 192, 192, 1)' : 'rgba(255, 99, 132, 1)', }; }); return dataset; } function checkRentability(profitData, salesData) { const rentability = {}; for (const article in profitData) { const totalQuantity = salesData[article].reduce((sum, sale) => sum + sale.quantity, 0); const price = profitData[article]['price']; rentability[article] = (totalQuantity > 20 && price > 10) ? 'Rentable' : 'No Rentable'; } return rentability; } async function predictData(inventoryDuration, profitData, salesData) { const avgDurations = calculateAverageDuration(inventoryDuration); const articles = Object.keys(avgDurations); const xData = []; const yData = []; articles.forEach(article => { xData.push(avgDurations[article]); yData.push(profitData[article]['price'] * profitData[article]['quantity']); }); const xTensor = tf.tensor2d(xData, [xData.length, 1]); const yTensor = tf.tensor2d(yData, [yData.length, 1]); const model = tf.sequential(); model.add(tf.layers.dense({inputShape: [1], units: 1})); model.compile({optimizer: 'sgd', loss: 'meanSquaredError'}); await model.fit(xTensor, yTensor, {epochs: 100}); const predictions = []; const currentDate = new Date(); for (let i = 1; i <= 6; i++) { const futureDate = new Date(currentDate); futureDate.setMonth(currentDate.getMonth() + i); const durationPrediction = await model.predict(tf.tensor2d([i * 30], [1, 1])).array(); const profitPrediction = await model.predict(tf.tensor2d([i * 30], [1, 1])).array(); // Ajuste para agregar variabilidad a las predicciones const variabilityFactor = Math.random() * 0.2 + 0.9; // Variabilidad entre 0.9 y 1.1 const adjustedProfitPrediction = profitPrediction[0][0] * variabilityFactor; predictions.push({ x: i * 30, y: adjustedProfitPrediction, r: 5, // Radio de la burbuja, se puede ajustar según sea necesario date: futureDate.toISOString().split('T')[0] // Formato de fecha ISO }); } return predictions; } async function main(predict = false) { const combinedDataset = prepareCombinedData(inventoryDuration, profitData); const rentability = checkRentability(profitData, salesData); const ctx = document.getElementById('combinedChart').getContext('2d'); const combinedChart = new Chart(ctx, { type: 'bubble', data: { datasets: combinedDataset }, options: { scales: { x: { title: { display: true, text: 'Duración Promedio en Inventario (días)' } }, y: { title: { display: true, text: 'Rentabilidad' } } }, plugins: { tooltip: { callbacks: { label: function(context) { const duration = Math.round(context.raw.x); const profit = Math.round(context.raw.y); const rentable = profit > 500 ? 'Rentable' : 'No Rentable'; const date = context.raw.date; const articleName = context.dataset.label; // Nombre del artículo return `Artículo: ${articleName}\nDuración: ${duration} días`; } } } } } }); if (predict) { const predictions = await predictData(inventoryDuration, profitData, salesData); const predictionDataset = { label: 'Predicciones', data: predictions.map(prediction => ({ x: prediction.x, y: prediction.y, r: prediction.r, date: prediction.date })), fill: false, borderColor: 'rgba(255, 99, 132, 1)', backgroundColor: 'rgba(255, 99, 132, 0.2)', hidden: true // Inicialmente oculto }; combinedChart.data.datasets.push(predictionDataset); combinedChart.update(); const predictionToggle = document.createElement('button'); predictionToggle.textContent = 'Mostrar/Ocultar Predicciones'; predictionToggle.onclick = () => { const dataset = combinedChart.data.datasets.find(ds => ds.label === 'Predicciones'); if (dataset) { dataset.hidden = !dataset.hidden; combinedChart.update(); } }; document.body.appendChild(predictionToggle); } } // Cambia el valor de "true" a "false" si no deseas hacer predicciones. main(true); </script>
Predicción de cantidades futuras de ventas de productos
Este módulo presenta una gráfica de la predicción de las cantidades de ventas futuras, lo que nos permite tomar decisiones de manera informada y saludable.

INFORMACIÓN DEL DESARROLLO
1. Preprocesamiento de Datos
- Normalización de Datos: Los datos de fechas, cantidades, meses, días de la semana y precios se normalizan para asegurar que todos los valores se encuentren en una escala similar, lo cual es una práctica común en machine learning para mejorar la convergencia del modelo.
- División del Conjunto de Datos: Se dividen los datos en conjuntos de entrenamiento y prueba para evaluar el rendimiento del modelo y evitar el sobreajuste (overfitting).
2. Arquitectura del Modelo
- Redes Neuronales: Se utiliza un modelo de red neuronal secuencial (
tf.sequential()
) con varias capas densas (tf.layers.dense
). Las capas densas son unidades fundamentales en redes neuronales donde cada neurona está conectada a todas las neuronas de la capa anterior. - Regularización: Se aplica regularización L2 (
kernelRegularizer: tf.regularizers.l2({ l2: 0.01 })
) para evitar el sobreajuste agregando una penalización al valor absoluto de los coeficientes. - Función de Activación: Se utiliza la función de activación
relu
(Rectified Linear Unit) para introducir no linealidad en el modelo y permitir que aprenda patrones complejos.
3. Entrenamiento del Modelo
- Optimización: Se usa el optimizador
adam
con una tasa de aprendizaje ajustada (tf.train.adam(0.0005)
) para actualizar los pesos del modelo durante el entrenamiento. - Función de Pérdida: Se emplea la función de pérdida de error cuadrático medio (
meanSquaredError
), que es adecuada para problemas de regresión donde se intenta minimizar la diferencia entre las predicciones y los valores reales. - Callback de Detención Temprana: Se implementa un callback de detención temprana (
tf.callbacks.earlyStopping
) para detener el entrenamiento si no hay mejoras en la pérdida de validación durante un número especificado de épocas, evitando el sobreajuste.
4. Predicción
- Predicción de Datos Futuros: Se realizan predicciones para fechas futuras, generando cantidades estimadas de ventas basadas en el modelo entrenado. Se añaden características adicionales como mes, día de la semana y precios promedio para enriquecer las predicciones.
5. Visualización
- Gráfico con Chart.js: Se utiliza la librería Chart.js para visualizar las predicciones en un gráfico de línea. Se diferencian los puntos según la rentabilidad (colores verde y rojo).
Resumen de Teorías y Metodologías
- Normalización y Preprocesamiento de Datos: Preparación de datos para mejorar el rendimiento del modelo.
- Redes Neuronales y Regularización: Construcción de un modelo con capas densas y aplicación de regularización para evitar el sobreajuste.
- Función de Activación Relu: Introducción de no linealidad en el modelo.
- Optimización con Adam: Uso de un algoritmo de optimización robusto y eficiente.
- Función de Pérdida de Error Cuadrático Medio: Minimización de la diferencia entre predicciones y valores reales.
- Detención Temprana: Mecanismo para detener el entrenamiento al alcanzar un punto de saturación en la mejora.
- Predicción y Visualización: Generación de predicciones y visualización de resultados para interpretar el rendimiento del modelo.
Código
<?php // Conectar a la base de datos $base = Database::getInstance(); $conn = $base->getConnection(); // Consulta para obtener los datos de salida de productos $query = " SELECT p.articulo, p.fecha, p.cantidad, p.precio AS precio_venta, a.nombre, a.categoria, a.marca, a.serie, a.modelo, a.estado, a.color, (SELECT AVG(pc.precio) FROM proceso pc WHERE pc.articulo = p.articulo AND pc.accion = 1) AS precio_promedio_compra, (SELECT AVG(pv.precio) FROM proceso pv WHERE pv.articulo = p.articulo AND pv.accion = 2) AS precio_promedio_venta FROM proceso p JOIN articulo a ON p.articulo = a.id WHERE p.accion = 2 "; $result = $conn->query($query); $salesData = []; if ($result->num_rows > 0) { while ($row = $result->fetch_assoc()) { $salesData[] = [ 'articulo' => $row['articulo'], 'fecha' => $row['fecha'], 'cantidad' => $row['cantidad'], 'precio_venta' => $row['precio_venta'], 'precio_promedio_compra' => $row['precio_promedio_compra'], 'precio_promedio_venta' => $row['precio_promedio_venta'], 'nombre' => $row['nombre'], 'categoria' => $row['categoria'], 'marca' => $row['marca'], 'serie' => $row['serie'], 'modelo' => $row['modelo'], 'estado' => $row['estado'], 'color' => $row['color'] ]; } } else { echo "No data found"; } $conn->close(); ?> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <canvas id="combinedChart"></canvas> <script> // Datos extraídos de la base de datos (por simplicidad, aquí se muestran como ejemplo) const salesData = <?php echo json_encode($salesData); ?>; // Crear una función para entrenar el modelo y generar predicciones async function trainAndPredictForArticle(articleData) { const dates = articleData.map(data => new Date(data.fecha)); const quantities = articleData.map(data => data.cantidad); const startDate = new Date(Math.min(...dates)); const normalizedDates = dates.map(date => Math.floor((date - startDate) / (1000 * 60 * 60 * 24))); // Convertir a días enteros const maxQuantity = Math.max(...quantities); const normalizedQuantities = quantities.map(qty => qty / maxQuantity); // Agregar características adicionales const months = dates.map(date => date.getMonth() + 1); // Mes del año const dayOfWeek = dates.map(date => date.getDay()); // Día de la semana const priceVentas = articleData.map(data => data.precio_venta); const avgCompra = articleData.map(data => data.precio_promedio_compra); const avgVenta = articleData.map(data => data.precio_promedio_venta); const maxMonth = Math.max(...months); const normalizedMonths = months.map(month => month / maxMonth); const maxDayOfWeek = Math.max(...dayOfWeek); const normalizedDayOfWeek = dayOfWeek.map(day => day / maxDayOfWeek); const maxPriceVenta = Math.max(...priceVentas); const normalizedPriceVentas = priceVentas.map(price => price / maxPriceVenta); const maxAvgCompra = Math.max(...avgCompra); const normalizedAvgCompra = avgCompra.map(price => price / maxAvgCompra); // Crear el dataset para TensorFlow.js const xs = tf.tensor2d(normalizedDates.map((date, i) => [date, normalizedMonths[i], normalizedDayOfWeek[i], normalizedPriceVentas[i], normalizedAvgCompra[i]])); const ys = tf.tensor2d(normalizedQuantities, [normalizedQuantities.length, 1]); // Dividir los datos en conjuntos de entrenamiento y prueba const splitIndex = Math.floor(xs.shape[0] * 0.8); const xsTrain = xs.slice([0, 0], [splitIndex, 5]); const ysTrain = ys.slice([0, 0], [splitIndex, 1]); const xsTest = xs.slice([splitIndex, 0], [xs.shape[0] - splitIndex, 5]); const ysTest = ys.slice([splitIndex, 0], [ys.shape[0] - splitIndex, 1]); // Crear el modelo const model = tf.sequential(); model.add(tf.layers.dense({ units: 64, activation: 'relu', inputShape: [5], kernelRegularizer: tf.regularizers.l2({ l2: 0.01 }) })); model.add(tf.layers.dense({ units: 64, activation: 'relu', kernelRegularizer: tf.regularizers.l2({ l2: 0.01 }) })); model.add(tf.layers.dense({ units: 32, activation: 'relu', kernelRegularizer: tf.regularizers.l2({ l2: 0.01 }) })); model.add(tf.layers.dense({ units: 1 })); model.compile({ optimizer: tf.train.adam(0.0005), // Ajustar la tasa de aprendizaje loss: 'meanSquaredError' }); // Callback para detener el entrenamiento si no hay mejora const earlyStoppingCallback = tf.callbacks.earlyStopping({ monitor: 'val_loss', patience: 15 }); // Entrenar el modelo await model.fit(xsTrain, ysTrain, { epochs: 300, // Aumentar el número de épocas validationData: [xsTest, ysTest], callbacks: [earlyStoppingCallback], onEpochEnd: (epoch, logs) => { console.log(`Epoch ${epoch}: loss = ${logs.loss}`); } }); // Obtener la última fecha en el conjunto de datos const lastDate = new Date(Math.max(...dates)); const futureDaysCount = 6; // Número de días futuros a predecir const futureDates = Array.from({ length: futureDaysCount }, (_, i) => { const futureDate = new Date(lastDate); futureDate.setDate(futureDate.getDate() + (i + 1) * 30); // para días return futureDate; }); const futureDays = futureDates.map(date => Math.floor((date - startDate) / (1000 * 60 * 60 * 24))); const futureMonths = futureDates.map(date => (date.getMonth() + 1) / maxMonth); const futureDayOfWeek = futureDates.map(date => date.getDay() / maxDayOfWeek); const futurePriceVenta = futureDates.map(date => articleData[0].precio_venta / maxPriceVenta); const futureAvgCompra = futureDates.map(date => articleData[0].precio_promedio_compra / maxAvgCompra); const futureData = futureDays.map((day, i) => [day, futureMonths[i], futureDayOfWeek[i], futurePriceVenta[i], futureAvgCompra[i]]); const futureDatesTensor = tf.tensor2d(futureData); const predictions = model.predict(futureDatesTensor); const predictedQuantities = await predictions.array(); // const labels = futureDates.map(date => date.toDateString()); const labels = futureDates.map(date => `${date.toLocaleString('default', { month: 'long' })} ${date.getFullYear()}`); // Calcular la rentabilidad y los colores de los puntos // const maxQuantity = Math.max(...quantities); const pointsColors = predictedQuantities.map((pred, index) => { const predictedQuantity = Math.round(pred[0] * maxQuantity); // Redondear a enteros const ganancia = predictedQuantity * (Math.round(articleData[0].precio_promedio_venta) - articleData[0].precio_promedio_compra); return ganancia > 500 ? 'green' : 'red'; }); predictedQuantities.forEach((pred, index) => { const predictedQuantity = Math.round(pred[0] * maxQuantity); // Redondear a enteros const futureDate = futureDates[index]; // Calcular la ganancia y determinar la rentabilidad const precioPromedioCompra = articleData[0].precio_promedio_compra; // Suponiendo que todos los productos tienen el mismo precio de compra const precioPromedioVenta = articleData[0].precio_venta; // Suponiendo que todos los productos tienen el mismo precio de venta // const ganancia = predictedQuantity * Math.round(articleData[0].precio_promedio_venta); const ganancia = predictedQuantity * (Math.round(articleData[0].precio_promedio_venta) - articleData[0].precio_promedio_compra); const rentable = ganancia > 500 ? 'Rentable' : 'No rentable'; console.log(`Producto: ${(articleData[0].articulo)}:`); console.log(`Prediction for ${futureDate.toDateString()}:`); console.log(`Cantidad: ${predictedQuantity}`); console.log(`Ganancia: ${ganancia.toFixed(2)}`); console.log(`Rentabilidad: ${rentable}`); console.log(`Precio Promedio Venta: ${Math.round(articleData[0].precio_promedio_venta)}`); }); // Retornar los datos predichos para este artículo return { article: articleData[0].nombre, labels: labels, predictedQuantities: predictedQuantities.map(pred => Math.round(pred[0] * maxQuantity)), pointsColors: pointsColors }; } // Función principal para ejecutar las predicciones y crear el gráfico async function main() { // Llamar a la función para cada artículo en salesData y combinar los resultados en un solo gráfico const articles = salesData.reduce((acc, item) => { (acc[item.articulo] = acc[item.articulo] || []).push(item); return acc; }, {}); const allPredictions = []; for (const article in articles) { const prediction = await trainAndPredictForArticle(articles[article]); allPredictions.push(prediction); } // Crear el gráfico combinado const ctx = document.getElementById('combinedChart').getContext('2d'); const datasets = allPredictions.map(prediction => ({ label: prediction.article, data: prediction.predictedQuantities, borderColor: `rgba(${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, 1)`, borderWidth: 1, fill: false, pointBackgroundColor: prediction.pointsColors })); new Chart(ctx, { type: 'line', data: { labels: allPredictions[0].labels, // Suponiendo que todas las predicciones tienen las mismas etiquetas datasets: datasets }, options: { scales: { y: { beginAtZero: true } } } }); } // Ejecutar la función principal main(); </script>
3. Video demostrativo del sistema de predicción de ventas
En el siguiente video se explica todo el funcionamiento del sistema de predicción de ventas de manera exhaustiva, módulo por módulo con todas sus características.
4. Puesta en marcha del sistema de predicción de ventas
Para instalar o configurar el sistema en un servidor local, los requisitos básicos a tener son los siguientes:
- Xampp, es un paquete de software gratuito y de código abierto que facilita la creación de un entorno de desarrollo local (no importa la versión).
- Editor de código, hay montón de programas. Puede ser Visual Studio Code, Sublime Text, Atom, etc.
Los pasos a seguir para instalar el sistema de manera correcta:
- Descargar e instalar XAMPP.
- Abrir el programa XAMPP.
- Iniciar los servicios Apache y MySQL.
- Extraer o descomprimir el sistema o proyecto.
- Copiar la carpeta del sistema extraído y pegar en la carpeta htdocs de XAMPP.
- Abrir phpMyAdmin desde XAMPP dando clic en Admin de Mysql.
- Importar el archivo SQL, la cual se encuentra dentro de la carpeta del sistema con el nombre database.sql, al importar automáticamente se creará la base de datos y sus tablas, "recuerda usted no debe crear la base de datos, debe dirigirse directamente a la opción de importar".
- Para abrir el sistema, en el navegador de Google escribe lo siguiente http://localhost/venta
Nota: Si tiene complicaciones en la instalación/configuración del sistema, te brindaremos la ayuda necesaria.
No te olvides...
Desarrollamos desde cero o a medida todo tipo de sistemas en diferentes lenguajes de programación y tecnologías más demandadas, asimismo realizamos actualizaciones de cualquier sistema. "Tú lo imaginas, nosotros lo creamos".