|
1 | | -import { confirm } from '@inquirer/prompts' |
| 1 | +import process from 'process' |
| 2 | +import chalk from 'chalk' |
| 3 | +import inquirer from 'inquirer' |
| 4 | +import { input, confirm } from '@inquirer/prompts' |
2 | 5 |
|
3 | 6 |
|
| 7 | + |
| 8 | +// Simplify std out from `console.log` into `print` |
4 | 9 | const print = console.log; |
5 | 10 |
|
6 | 11 |
|
7 | | -export default async function multiFeatureProcess() { |
8 | | - print('Multi feature process') |
9 | 12 |
|
10 | | - if (await confirm({ message: 'Show visualization?'})) { |
11 | | - visualization() |
| 13 | +/** |
| 14 | + * Process linear regression with multi feature |
| 15 | + * |
| 16 | + * Formula |
| 17 | + * y = a + bx |
| 18 | + * |
| 19 | + * @param {Array} data - the raw data |
| 20 | + */ |
| 21 | +export default async function multiFeatureProcess(data) { |
| 22 | + print('=====================================================\n') |
| 23 | + print(chalk.blue('MULTI FEATURE PROCESS\n')) |
| 24 | + |
| 25 | + const answers = await inquirer.prompt([ |
| 26 | + { |
| 27 | + type: 'checkbox', |
| 28 | + name: 'features', |
| 29 | + message: 'Choose independent variable', |
| 30 | + choices: Object.keys(data[0]) |
| 31 | + }, |
| 32 | + { |
| 33 | + type: 'list', |
| 34 | + name: 'label', |
| 35 | + message: 'Choose dependent variable', |
| 36 | + choices: Object.keys(data[0]) |
| 37 | + } |
| 38 | + ]) |
| 39 | + |
| 40 | + |
| 41 | + for (const feature of answers.features) { |
| 42 | + if (feature == answers.label) { |
| 43 | + print(chalk.redBright('\n[!] Feature and label can not be same')) |
| 44 | + |
| 45 | + if (await confirm({ message: 'Back?'})) return; |
| 46 | + } |
12 | 47 | } |
13 | | -} |
14 | 48 |
|
15 | 49 |
|
| 50 | + // const numberPattern = /^[+-]?\d+(\.\d+)?$/ |
| 51 | + // for (const item of data) { |
| 52 | + // if (!numberPattern.test(item[answers.features]) || !numberPattern.test(item[answers.label])) { |
| 53 | + // print(chalk.redBright('\n[!] Some data is not a number! Unable to process further!')) |
| 54 | + // await confirm({ message: 'Continue?'}) |
| 55 | + // return; |
| 56 | + // } |
| 57 | + // } |
| 58 | + |
| 59 | + |
| 60 | + /** |
| 61 | + * Calculate the value a and b to get equation y = a + bx |
| 62 | + */ |
| 63 | + const sumY = data.reduce((sum, val) => sum + parseInt(val[answers.label]), 0) |
| 64 | + |
| 65 | + const sumXi = [] |
| 66 | + const sumXiSquared = [] |
| 67 | + const sumXiYi = [] // ? how ? |
| 68 | + |
| 69 | + for (let i = 0; i < answers.features.length; i++) { |
| 70 | + sumXi.push(data.reduce((sum, val) => sum + parseInt(val[answers.features[i]]), 0)) |
| 71 | + sumXiSquared.push(data.reduce((sum, val) => sum + parseInt(val[answers.features[i]]) ** 2, 0)) |
| 72 | + } |
| 73 | + |
| 74 | + const sumAllXi = sumXi.reduce((sum, val) => sum * val) |
| 75 | + const sumAllXiSquared = sumXiSquared.reduce((sum, val) => sum * val) |
| 76 | + |
| 77 | + const slopes = [] |
| 78 | + for (let i = 0; i < answers.features.length; i++) { |
| 79 | + slopes.push( |
| 80 | + ((data.length * sumXiYi) - (sumAllXi * sumY)) / |
| 81 | + ((data.length * sumAllXiSquared) - (sumAllXi ** 2)) |
| 82 | + ) |
| 83 | + } |
| 84 | + |
| 85 | + let sumSlopeiXi = 0 |
| 86 | + for (let i = 0; i < slopes.length; i++) { |
| 87 | + sumSlopeiXi += slopes[i] * (sumXi[i] / data.length) |
| 88 | + } |
| 89 | + |
16 | 90 |
|
17 | | -function visualization() { |
18 | | - print('\n-----------------------------------------------------\n') |
19 | | - print('Visualization here!') |
20 | | - print('Graph, chart, or whatever...') |
| 91 | + /** |
| 92 | + * INSPECTION! |
| 93 | + */ |
| 94 | + print('sumY: ', sumY) |
| 95 | + print('sumXi: ', sumXi) |
| 96 | + print('slopes: ', slopes) |
| 97 | + print('sumXiSquare: ', sumXiSquared) |
| 98 | + print('sumAllXiSquared: ', sumAllXiSquared) |
| 99 | + print('sumXiYi: ', sumXiYi) |
| 100 | + |
| 101 | + const a = (sumY / data.length) - sumSlopeiXi |
| 102 | + |
| 103 | + // Equation result |
| 104 | + const y = (...x) => a + slopes.reduce((sum, val, index) => sum + (val * x[index])) |
| 105 | + |
| 106 | + |
| 107 | + // Print the equation |
| 108 | + process.stdout.write(chalk.blueBright(`\nEquation result: ${a} + `)) |
| 109 | + |
| 110 | + slopes.forEach((val, index) => { |
| 111 | + process.stdout.write(chalk.blueBright(`${val}x\u1d62`)) |
| 112 | + if (index != slopes.length - 1) process.stdout.write(chalk.blueBright(' + ')) |
| 113 | + }) |
| 114 | + |
| 115 | + |
| 116 | + |
| 117 | + if (await confirm({ message: 'Do you want to test?'})) { |
| 118 | + do { |
| 119 | + await testing(y, answers.feature, answers.label) |
| 120 | + } while (await confirm({ message: 'Do you want to test again?'})); |
| 121 | + } |
| 122 | + |
| 123 | + |
| 124 | + evaluation() |
| 125 | +} |
| 126 | + |
| 127 | + |
| 128 | +async function testing(y, feature, label) { |
| 129 | + const inputFeature = await input({message: `Input ${feature}`}) |
| 130 | + print(`Prediction ${label}: ${y(inputFeature)}`) |
| 131 | +} |
21 | 132 |
|
22 | 133 |
|
23 | | - // 7 |
24 | | - print('Show the prove of linear equation is actually match with user data') |
| 134 | +function evaluation() { |
| 135 | + print('Evaluation!') |
| 136 | + print('MSE, MAE, RMSE') |
25 | 137 | } |
0 commit comments