11const dataForm = document . getElementById ( 'data-form' )
22const inputFile = document . getElementById ( 'input-file' )
33const fileName = document . getElementById ( 'file-name' )
4+
45const btnPreviewData = document . getElementById ( 'btn-preview-data' )
56const previewData = document . getElementById ( 'preview-data-container' )
67
8+ const btnPrev = document . getElementById ( 'btn-prev' )
9+ const btnNext = document . getElementById ( 'btn-next' )
10+
11+ const sections = document . querySelectorAll ( 'section' )
712
813
14+ const modelForm = document . getElementById ( 'model-form' )
15+ const modelSelection = document . getElementById ( 'model-selection' )
16+ const featureCheckboxContainer = document . getElementById ( 'feature-checkbox-container' )
17+ const featureCheckbox = document . getElementById ( 'feature-checkbox' )
18+ const featureSelectionContainer = document . getElementById ( 'feature-selection-container' )
19+ const featureSelect = document . getElementById ( 'feature-select' )
20+ const labelSelectionContainer = document . getElementById ( 'label-selection-container' )
21+ const labelSelect = document . getElementById ( 'label-select' )
922
23+ const equationResult = document . getElementById ( 'equation-result' )
24+ /**
25+ * Linear equation result based on data processing
26+ *
27+ * @param {number } x - a feature data
28+ * @returns {number } a label/target/`y` value result
29+ */
30+ let equation = null
31+
32+ // Global data
1033let currentSection = 1
34+ let fileData = null
35+
36+
37+
38+ btnPrev . addEventListener ( 'click' , ( ) => {
39+ sections [ currentSection - 1 ] . classList . toggle ( 'hidden' )
40+ currentSection --
41+ sections [ currentSection - 1 ] . classList . toggle ( 'hidden' )
42+ if ( currentSection == 1 ) {
43+ btnPrev . classList . toggle ( 'invisible' )
44+ }
45+ } )
46+
47+ btnNext . addEventListener ( 'click' , ( ) => {
48+ sections [ currentSection - 1 ] . classList . toggle ( 'hidden' )
49+ currentSection ++
50+ sections [ currentSection - 1 ] . classList . toggle ( 'hidden' )
51+ if ( currentSection > 1 ) {
52+ if ( btnPrev . classList . contains ( 'invisible' ) ) {
53+ btnPrev . classList . remove ( 'invisible' )
54+ }
55+ }
56+ } )
57+
58+
59+
1160
61+ //////////////////////////////////////////////////
62+ //// FIRST SECTION SCRIPT
63+ //////////////////////////////////////////////////
1264
1365dataForm . addEventListener ( 'submit' , function ( e ) {
1466 e . preventDefault ( )
@@ -28,38 +80,64 @@ dataForm.addEventListener('submit', function(e) {
2880
2981 reader . onload = ( e ) => {
3082 const fileContent = e . target . result
31- const rows = fileContent . split ( / [ \r \n ] + / ) . map ( row => row . split ( ',' ) )
83+ fileData = fileContent
84+ . split ( / [ \r \n ] + / )
85+ . map ( row => row . split ( ',' ) )
86+ . map ( ( val , index , array ) => {
87+ if ( index == 0 ) return
88+
89+ const obj = { }
90+
91+ for ( let i = 0 ; i < array [ 0 ] . length ; i ++ ) {
92+ obj [ array [ 0 ] [ i ] ] = val [ i ]
93+ }
94+ return obj
95+ } )
96+ fileData . shift ( )
97+
3298
3399 let previewedTable = `
34100 <table class="min-w-full bg-white border border-gray-200 rounded-lg">
35101 <thead>
36102 <tr class="bg-gray-100 border-b border-gray-200">
37103 `
38104
39- for ( const item of rows . shift ( ) ) {
40- previewedTable += `<td class="py-2 px-4 text-left text-sm font-medium text-gray-600">${ item } </td>`
105+ for ( const key in fileData [ 0 ] ) {
106+ previewedTable += `<td class="py-2 px-4 text-left text-sm font-medium text-gray-600">${ key } </td>`
41107 }
42108
43109 previewedTable += `
44110 </tr>
45111 </thead>
112+ <tbody>
46113 `
47114
48- for ( const row of rows ) {
115+ for ( const row of fileData ) {
49116 previewedTable += `<tr class="border-b hover:bg-gray-50">`
50- for ( const item of row ) {
117+ for ( const item of Object . values ( row ) ) {
51118 previewedTable += `<td class="py-2 px-4 text-sm text-gray-700">${ item } </td>`
52119 }
53120 previewedTable += `</tr>`
54-
55121 }
122+ previewedTable += `</tbody>`
56123
57124 previewData . innerHTML = previewedTable
125+
126+ for ( const key in fileData [ 0 ] ) {
127+ featureSelect . innerHTML += `<option value="${ key } ">${ key } </option>`
128+ labelSelect . innerHTML += `<option value="${ key } ">${ key } </option>`
129+ featureCheckbox . innerHTML += `
130+ <label class="flex items-center text-gray-700">
131+ <input type="checkbox" name="features" class="mr-2 leading-tight">
132+ ${ key }
133+ </label>`
134+ }
58135 }
59136
60137 reader . readAsText ( file )
61138
62139 btnPreviewData . setAttribute ( 'disabled' , true )
140+ btnNext . removeAttribute ( 'disabled' )
63141 this . reset ( )
64142} )
65143
@@ -72,4 +150,123 @@ inputFile.addEventListener('change', function() {
72150 }
73151
74152 btnPreviewData . removeAttribute ( 'disabled' )
75- } )
153+ } )
154+
155+
156+
157+
158+
159+ //////////////////////////////////////////////////
160+ //// SECOND SECTION SCRIPT
161+ //////////////////////////////////////////////////
162+
163+
164+ modelSelection . addEventListener ( 'change' , function ( e ) {
165+ const model = e . target . value
166+
167+ switch ( model ) {
168+ case 'single' : showSingleFeatureForm ( ) ; break ;
169+ case 'multi' : showMultiFeatureForm ( ) ; break ;
170+ default : alert ( 'Invalid model type!' ) ; break ;
171+ }
172+ } )
173+
174+
175+ function showSingleFeatureForm ( ) {
176+ if ( featureCheckboxContainer . classList . contains ( 'flex' ) ) {
177+ featureCheckboxContainer . classList . remove ( 'flex' )
178+ featureCheckboxContainer . classList . add ( 'hidden' )
179+
180+ featureCheckbox . querySelectorAll ( 'input[type="checkbox"' )
181+ . forEach ( checkbox => {
182+ checkbox . disabled = true
183+ } )
184+ }
185+
186+ featureSelectionContainer . classList . remove ( 'hidden' )
187+ featureSelectionContainer . classList . add ( 'block' )
188+ featureSelect . disabled = false
189+
190+ labelSelectionContainer . classList . remove ( 'hidden' )
191+ }
192+
193+
194+ function showMultiFeatureForm ( ) {
195+ if ( featureSelectionContainer . classList . contains ( 'block' ) ) {
196+ featureSelectionContainer . classList . remove ( 'block' )
197+ featureSelectionContainer . classList . add ( 'hidden' )
198+ featureSelect . disabled = true
199+ }
200+
201+ featureCheckboxContainer . classList . remove ( 'hidden' )
202+ featureCheckboxContainer . classList . add ( 'flex' )
203+ featureCheckbox . querySelectorAll ( 'input[type="checkbox"' )
204+ . forEach ( checkbox => {
205+ checkbox . disabled = false
206+ } )
207+
208+ labelSelectionContainer . classList . remove ( 'hidden' )
209+ }
210+
211+
212+ modelForm . addEventListener ( 'submit' , function ( e ) {
213+ e . preventDefault ( )
214+
215+ const formData = new FormData ( this )
216+
217+ const model = formData . get ( 'model' )
218+ const label = formData . get ( 'label' )
219+ const feature = formData . get ( 'features' ) || formData . get ( 'feature' )
220+
221+ switch ( model ) {
222+ case 'single' :
223+ singleFeatureProcess ( feature , label )
224+ break
225+ case 'multi' : multiFeatureProcess ( feature , label ) ; break ;
226+ default : alert ( 'Invalid model type!' ) ; break ;
227+ }
228+ } )
229+
230+
231+ /**
232+ * Process linear regression with single feature
233+ *
234+ * Formula
235+ * `y = β0 + β1x1`
236+ *
237+ * @param {string } feature
238+ * @param {string } label
239+ */
240+ function singleFeatureProcess ( feature , label ) {
241+ const sumX = fileData . reduce ( ( sum , val ) => sum + parseFloat ( val [ feature ] ) , 0 )
242+ const sumY = fileData . reduce ( ( sum , val ) => sum + parseFloat ( val [ label ] ) , 0 )
243+ const sumXY = fileData . reduce ( ( sum , val ) => sum + ( parseFloat ( val [ feature ] ) * parseFloat ( val [ label ] ) ) , 0 )
244+ const sumXSquared = fileData . reduce ( ( sum , val ) => sum + parseFloat ( val [ feature ] ) ** 2 , 0 )
245+ const sumXTimesSumY = sumX * sumY
246+
247+ const b = (
248+ ( ( fileData . length * sumXY ) - sumXTimesSumY ) /
249+ ( ( fileData . length * sumXSquared ) - ( sumX ** 2 ) )
250+ )
251+
252+ const a = ( sumY / fileData . length ) - ( b * ( sumX / fileData . length ) )
253+
254+ equation = ( x ) => a + ( b * x )
255+
256+ equationResult . textContent = `Equation result: y = ${ a } + ${ b } x`
257+ }
258+
259+
260+ /**
261+ * Process linear regression with multi feature
262+ *
263+ * Formula
264+ * `y = β0 + β1x1 + β2x2 + ... + βnxn`
265+ *
266+ * @param {string[] } features
267+ * @param {string } label
268+ */
269+ function multiFeatureProcess ( features , label ) {
270+ console . log ( 'hey its me multi' )
271+ console . log ( fileData )
272+ }
0 commit comments