code wiki / _hdl_build / nx_analyst_multi.nx

nx_analyst_multi.nx source

↩ module page · 102 lines · 4238 B

1// nx_analyst_multi.nx -- LIB: MULTI-COLUMN relationship analysis -- the "find patterns" half of the general 2// data analyst (rung 3). Integer Pearson correlation between two columns + a data-driven strength class + 3// a KEY-DRIVER finder (which of N candidate columns most correlates with a target). Composes nx_dataframe. 4// OVERFLOW-AWARE: uses CENTERED sums (subtract the integer mean first) so intermediates stay ~n*V^2 rather 5// than n^2*V^2 -- safe for moderate n*V (documented bound); i128/normalized scale = the follow-on for very 6// large streams. license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "_hdl_build/nx_dataframe.nx" 9 10const AM_R_DEGENERATE: i64 = 0 - 2000 // sentinel: a column has zero variance -> correlation undefined 11 12// Pearson correlation * 1000 (range -1000..1000). Centered on integer means. Returns AM_R_DEGENERATE if 13// either column is constant (zero variance). n must be > 1. 14func am_pearson_milli(x: *i64, y: *i64, n: i64) -> i64 { 15 if n < 2 { return AM_R_DEGENERATE } 16 let rem: *i64 = sys_mmap(8) as *i64 17 let mx: i64 = df_mean(x, n, rem) 18 let my: i64 = df_mean(y, n, rem) 19 var sxy: i64 = 0 20 var sxx: i64 = 0 21 var syy: i64 = 0 22 var i: i64 = 0 23 while i < n { 24 let dx: i64 = x[i] - mx 25 let dy: i64 = y[i] - my 26 sxy = sxy + dx * dy 27 sxx = sxx + dx * dx 28 syy = syy + dy * dy 29 i = i + 1 30 } 31 if sxx <= 0 { return AM_R_DEGENERATE } 32 if syy <= 0 { return AM_R_DEGENERATE } 33 // r = sxy / sqrt(sxx*syy). r_milli = sxy*1000 / isqrt(sxx*syy). 34 let denom: i64 = df_isqrt(sxx * syy) 35 if denom <= 0 { return AM_R_DEGENERATE } 36 var r: i64 = (sxy * 1000) / denom 37 if r > 1000 { r = 1000 } 38 if r < 0 - 1000 { r = 0 - 1000 } 39 return r 40} 41 42// covariance (centered, /n) -- the unnormalized relationship, for completeness. 43func am_covariance(x: *i64, y: *i64, n: i64) -> i64 { 44 if n < 1 { return 0 } 45 let rem: *i64 = sys_mmap(8) as *i64 46 let mx: i64 = df_mean(x, n, rem) 47 let my: i64 = df_mean(y, n, rem) 48 var s: i64 = 0 49 var i: i64 = 0 50 while i < n { s = s + (x[i] - mx) * (y[i] - my); i = i + 1 } 51 return s / n 52} 53 54// classify a correlation coefficient (r_milli) into words. |r| thresholds are the conventional social-science 55// bands (data-driven, named): >=800 very strong, >=500 strong, >=300 moderate, >=100 weak, else negligible. 56func am_class(r_milli: *u8, r: i64, out: *u8) -> i64 { 57 if r == AM_R_DEGENERATE { 58 var k: i64 = 0 59 let s: *u8 = "undefined (constant column)" as *u8 60 while s[k] != (0 as u8) { out[k] = s[k]; k = k + 1 } 61 out[k] = 0 as u8 62 return k 63 } 64 var a: i64 = r 65 if a < 0 { a = 0 - a } 66 var o: i64 = 0 67 if r < 0 { let neg: *u8 = "negative " as *u8; var j: i64 = 0; while neg[j] != (0 as u8) { out[o] = neg[j]; o = o + 1; j = j + 1 } } 68 if r > 0 { let pos: *u8 = "positive " as *u8; var j2: i64 = 0; while pos[j2] != (0 as u8) { out[o] = pos[j2]; o = o + 1; j2 = j2 + 1 } } 69 var band: *u8 = "negligible" as *u8 70 if a >= 100 { band = "weak" as *u8 } 71 if a >= 300 { band = "moderate" as *u8 } 72 if a >= 500 { band = "strong" as *u8 } 73 if a >= 800 { band = "very strong" as *u8 } 74 var b: i64 = 0 75 while band[b] != (0 as u8) { out[o] = band[b]; o = o + 1; b = b + 1 } 76 out[o] = 0 as u8 77 return o 78} 79 80// KEY-DRIVER: of `ncol` candidate columns (cols = array of column pointers), which most correlates (by |r|) 81// with `target`? Writes the winning column index to out_idx and its r_milli to out_r. Returns 1 if found. 82// NOTE the inline-cast-index gotcha: bind cols[c] to a local BEFORE indexing. 83func am_key_driver(target: *i64, cols: *i64, ncol: i64, n: i64, out_idx: *i64, out_r: *i64) -> i64 { 84 var best: i64 = 0 - 1 85 var best_abs: i64 = 0 - 1 86 var best_r: i64 = 0 87 var c: i64 = 0 88 while c < ncol { 89 let colc: *i64 = cols[c] as *i64 90 let r: i64 = am_pearson_milli(target, colc, n) 91 if r != AM_R_DEGENERATE { 92 var a: i64 = r 93 if a < 0 { a = 0 - a } 94 if a > best_abs { best_abs = a; best = c; best_r = r } 95 } 96 c = c + 1 97 } 98 if best < 0 { return 0 } 99 out_idx[0] = best 100 out_r[0] = best_r 101 return 1 102}