Download parallel_v6/src/lrfeat2.py from Eric-Yyvuw/yeepee-ctr: direct link, hf CLI and curl.
- Browser
- Download file 4.46 kB
-
https://huggingface.co/Eric-Yyvuw/yeepee-ctr/resolve/main/parallel_v6/src/lrfeat2.py
- Command line
-
hf download hf://Eric-Yyvuw/yeepee-ctr/parallel_v6/src/lrfeat2.py
-
curl -L -o lrfeat2.py https://huggingface.co/Eric-Yyvuw/yeepee-ctr/resolve/main/parallel_v6/src/lrfeat2.py
4.46 kB
| """F1 (data_dig_v1): history-centroid cosine in an exact low-rank SVD space. Train-only, rebuilt at each fold cutoff C. | |
| Matrix: users x items, binary, rows = each user's last N distinct history clicks (from train events with ts < C), | |
| columns scaled by 1/sqrt(pop+5); exact svds (ARPACK) k=17; item vectors = comps 2..K+1 (popularity comp dropped) * s. | |
| Feature: cos(candidate vector, sum of own-history normalised vectors). Within-event _z and _dmax. Eval: fitted at J27 on train only. | |
| Usage: python lrfeat.py NAME... -> feat_lr/NAME.parquet (rowid, lr{K}_cos/_z/_dmax for K in 10,12,16)""" | |
| import sys, os, time, numpy as np, polars as pl, scipy.sparse as sp | |
| from scipy.sparse.linalg import svds | |
| sys.path.insert(0, '/workspace/huawei/v3') | |
| from features import load | |
| from split import J20, DAY, first_events | |
| TE, TR, EE, ER, NI, NU = load('/workspace/huawei/v3/data') | |
| N = int(os.environ.get('LR_N', 40)); OUT = os.environ.get('LR_OUT', '/workspace/huawei/v2work/feat_lr2'); os.makedirs(OUT, exist_ok=True) | |
| KS = tuple(int(x) for x in os.environ.get('LR_KS', '10,12,16').split(',')) | |
| CON = int(os.environ.get('LR_CON', 0)) | |
| SPEC = {**{f'f{k}': (J20 + k * DAY, DAY) for k in range(1, 7)}, 'val25': (J20 + 5 * DAY, None), 'val26': (J20 + 6 * DAY, None)} | |
| _V = {} | |
| def vecs(C): | |
| if C in _V: return _V[C] | |
| h = (TE.filter(pl.col('ts') < C).select('u', 'h', 'h_ts').explode(['h', 'h_ts']).drop_nulls('h') | |
| .select('u', pl.col('h').cast(pl.Int32).alias('ii'), pl.col('h_ts').cast(pl.Int64).alias('t')).unique().sort('u', 't', 'ii')) | |
| h = h.with_columns(pl.int_range(pl.len()).over('u').alias('p'), pl.len().over('u').alias('L')).filter(pl.col('L') - pl.col('p') <= N).unique(['u', 'ii']) | |
| M = sp.csr_matrix((np.ones(h.height, np.float32), (h['u'].to_numpy(), h['ii'].to_numpy())), shape=(NU, NI)) | |
| pop = np.asarray(M.sum(0)).ravel(); M = M.multiply(1 / np.sqrt(pop + 5)).tocsr() | |
| _, s, vt = svds(M, k=max(max(KS) + 1, 17), random_state=0); o = np.argsort(-s); s, vt = s[o], vt[o] | |
| print(time.strftime('%T'), 'C', C, 'pairs', h.height, 'sv', np.round(s[:15], 2), flush=True) | |
| _V[C] = (s, vt); return _V[C] | |
| def build(C, T_ev, T_rows): | |
| s, vt = vecs(C) | |
| E = T_ev.select('eid', 'h').with_row_index('k'); kk = E.select('eid', 'k') | |
| H = E.select('k', 'h').explode('h').drop_nulls('h'); hk = H['k'].to_numpy(); hi = H['h'].to_numpy().astype(np.int64) | |
| R = T_rows.select('rowid', 'eid', 'ii').join(kk, on='eid', how='left'); rk = R['k'].to_numpy(); ri = R['ii'].to_numpy().astype(np.int64) | |
| F = {} | |
| if CON: | |
| P_ev = TE.filter(pl.col('ts') < C).select('eid', 'u') | |
| ng = TR.filter(pl.col('clicked') == 0).join(P_ev, on='eid', how='inner').select('u', 'ii').unique() | |
| ue = T_ev.select('u').with_row_index('k').join(ng, on='u', how='inner'); nk = ue['k'].to_numpy(); ni = ue['ii'].to_numpy().astype(np.int64) | |
| for K in KS: | |
| V = (vt[1:K + 1].T * s[1:K + 1]); V = V / (np.linalg.norm(V, axis=1, keepdims=True) + 1e-9) | |
| hc = np.zeros((E.height, K)); np.add.at(hc, hk, V[hi]) | |
| hcr = hc[rk]; nr = np.linalg.norm(hcr, axis=1) | |
| x = np.where(nr > 0, (V[ri] * hcr).sum(1) / (nr + 1e-9), np.nan) | |
| F[f'lr{K}_cos'] = x.astype(np.float32) | |
| if CON: | |
| nc = np.zeros((E.height, K)); np.add.at(nc, nk, V[ni]) | |
| hn = hc / (np.linalg.norm(hc, axis=1, keepdims=True) + 1e-9); nn = nc / (np.linalg.norm(nc, axis=1, keepdims=True) + 1e-9) | |
| for al, nm in ((0.5, '05'), (1.0, '1')): | |
| d = (hn - al * nn)[rk]; dn = np.linalg.norm(d, axis=1) | |
| F[f'lr{K}_con{nm}'] = np.where(dn > 0, (V[ri] * d).sum(1) / (dn + 1e-9), np.nan).astype(np.float32) | |
| R = R.select('rowid', 'eid').with_columns([pl.Series(c, v).fill_nan(None) for c, v in F.items()]) | |
| R = R.with_columns([((pl.col(c) - pl.col(c).mean().over('eid')) / (pl.col(c).std().over('eid') + 1e-6)).alias(c.replace('_cos', '_z') if c.endswith('_cos') else c + '_z') for c in F] + | |
| [(pl.col(c) - pl.col(c).max().over('eid')).alias(c.replace('_cos', '_dmax') if c.endswith('_cos') else c + '_dmax') for c in F]) | |
| return R.drop('eid') | |
| for n in sys.argv[1:]: | |
| t0 = time.time() | |
| if n == 'eval': R = build(J20 + 7 * DAY, EE, ER) | |
| else: | |
| C, W = SPEC[n]; T_ev = first_events(TE, C, W); R = build(C, T_ev, TR.join(T_ev.select('eid'), on='eid', how='semi')) | |
| R.write_parquet(f'{OUT}/{n}.parquet'); print(n, R.shape, f'{time.time()-t0:.0f}s', flush=True) | |