/** * 函数拟合工具 - 工具函数 */ /** * 从表格中获取数据点 * @returns {Array} 数据点数组,每个元素包含x和y属性 */ function getDataPointsFromTable() { // 检查是否使用Excel风格表格 const fitExcelTable = document.getElementById('fit-excel-table'); if (fitExcelTable) { // 使用Excel表格数据提取函数 return window.dataTable.getDataPointsFromExcelTable(fitExcelTable); } // 兼容旧版表格 const dataTable = document.getElementById('data-table'); if (!dataTable) return []; const rows = dataTable.querySelectorAll('tbody tr'); const dataPoints = []; rows.forEach(row => { const xInput = row.querySelector('.x-value'); const yInput = row.querySelector('.y-value'); if (xInput && yInput) { const x = parseFloat(xInput.value); const y = parseFloat(yInput.value); if (!isNaN(x) && !isNaN(y)) { dataPoints.push({ x, y }); } } }); return dataPoints; } /** * 格式化数字,保留指定小数位 * @param {number} value - 要格式化的数值 * @param {number} decimals - 小数位数 * @returns {string} 格式化后的数字字符串 */ function formatNumber(value, decimals = 4) { return Number(value).toFixed(decimals); } /** * 计算相关系数 (R²) * @param {Array} xValues - X值数组 * @param {Array} yValues - Y值数组 * @param {Function} predictFn - 预测函数,接收x返回预测的y * @returns {number} 相关系数 */ function calculateRSquared(xValues, yValues, predictFn) { if (xValues.length !== yValues.length || xValues.length === 0) { return 0; } // 计算y的平均值 const yMean = yValues.reduce((sum, y) => sum + y, 0) / yValues.length; // 计算总平方和(SST) const sst = yValues.reduce((sum, y) => sum + Math.pow(y - yMean, 2), 0); // 计算残差平方和(SSE) let sse = 0; for (let i = 0; i < xValues.length; i++) { const yPred = predictFn(xValues[i]); sse += Math.pow(yValues[i] - yPred, 2); } // 计算R² return 1 - (sse / sst); } /** * 计算均方根误差(RMSE) * @param {Array} xValues - X值数组 * @param {Array} yValues - Y值数组 * @param {Function} predictFn - 预测函数,接收x返回预测的y * @returns {number} RMSE值 */ function calculateRMSE(xValues, yValues, predictFn) { if (xValues.length !== yValues.length || xValues.length === 0) { return 0; } let sumSquaredError = 0; for (let i = 0; i < xValues.length; i++) { const yPred = predictFn(xValues[i]); sumSquaredError += Math.pow(yValues[i] - yPred, 2); } return Math.sqrt(sumSquaredError / xValues.length); } /** * 生成统计结果HTML * @param {Object} params - 统计参数 * @returns {string} HTML字符串 */ function generateStatsHTML(params) { const { coefficients, rSquared, rmse, formula, dataPoints } = params; let html = '
| 参数 | 值 |
|---|---|
| 数据点数量 | ${dataPoints} |
| 决定系数 (R²) | ${formatNumber(rSquared)} |
| 均方根误差 (RMSE) | ${formatNumber(rmse)} |
| 系数 | |
| ${coefName} | ${formatNumber(coef)} |
| ${key} | ${formatNumber(coefficients[key])} |