-
Notifications
You must be signed in to change notification settings - Fork 33
Add tabular preprocessing #1094
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
58edf2b
8aaf957
32e02cb
ced7768
a6f86f3
16c6393
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,10 @@ | ||
| import { List } from "immutable"; | ||
|
|
||
| export type StandardizationStats = { | ||
| means: Record<string, number>; | ||
| stds: Record<string, number>; | ||
| }; | ||
|
|
||
| /** | ||
| * Convert a string to a number | ||
| * | ||
|
|
@@ -38,3 +43,104 @@ export function indexInList( | |
| if (ret === -1) throw new Error(`${element} not found in list`); | ||
| return ret; | ||
| } | ||
|
|
||
| /** | ||
| * Return the mean, std value of each column | ||
| */ | ||
| export function computeStandardizationStats( | ||
| rows: Array<Partial<Record<string, string>>>, | ||
| columns: Array<string>, | ||
| ): StandardizationStats{ | ||
| const means: Record<string, number> = {}; | ||
| const stds: Record<string, number> = {}; | ||
|
|
||
| for (const col of columns){ | ||
| const values = rows.map((row)=> { | ||
| const rawValue = extractColumn(row, col); | ||
| return convertToNumber(rawValue !== "" ? rawValue : "0"); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note to self: prompt users to choose missing data imputation method |
||
| }); | ||
| const mean = values.reduce((a, b)=> a+b, 0) / values.length; | ||
| const variance = values.reduce((acc, val) => acc + (val-mean)**2, 0) / values.length; | ||
|
|
||
| const std = Math.sqrt(variance); | ||
|
|
||
| means[col] = mean; | ||
| stds[col] = std; | ||
| } | ||
|
|
||
| return {means, stds}; | ||
| } | ||
|
|
||
| /** | ||
| * Apply standardization for a single value | ||
| */ | ||
| export function standardizeValue( | ||
| value: number, | ||
| mean: number, | ||
| std: number, | ||
| ): number{ | ||
| if (std == 0) return 0; // avoid divide by 0 | ||
| return (value - mean) / std; | ||
| } | ||
|
|
||
| /** | ||
| * Apply one hot encoding for a row | ||
| * | ||
| * One hot encoding function is called for each row in dataset | ||
| */ | ||
| export function oneHotEncode( | ||
| value: string, | ||
| categories: Array<string>, | ||
| ): Array<number> { | ||
| // Get the index of the value among the possible categories | ||
| const index = categories.indexOf(value); | ||
|
|
||
| // If the value does not exist, raise an error | ||
| if (index === -1) { | ||
| throw new Error(`"${value}" is not a valid category for this column`); | ||
| } | ||
|
|
||
| return categories.map((_, categoryIndex) => | ||
| categoryIndex === index ? 1 : 0 | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Apply standardization for numerical columns and | ||
| * apply one hot encoding for categorical columns and return the final row | ||
| */ | ||
| export function encodeTabularRow( | ||
| row: Partial<Record<string, string>>, | ||
| inputColumns: Array<string>, | ||
| categoricalColumns: Record<string, Array<string>>, | ||
| stats?: StandardizationStats, | ||
| ): Array<number> { | ||
| const outputRow = inputColumns.flatMap((column) => { | ||
| const raw = extractColumn(row, column); | ||
| const categories = categoricalColumns[column]; | ||
|
|
||
| // If the column exists in the list of categorical columns, apply one hot encoding | ||
| if (categories !== undefined){ | ||
| return oneHotEncode(raw, categories); | ||
| } | ||
|
|
||
| // If the column is numerical column, apply standardization | ||
| const value = convertToNumber(raw !== "" ? raw : "0"); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. default missing data imputation |
||
|
|
||
| if (stats === undefined) { | ||
| return [value]; | ||
| } | ||
|
|
||
| const mean = stats.means[column]; | ||
| const std = stats.stds[column]; | ||
|
|
||
| // Raise an error when stats is not defined | ||
| if (mean === undefined || std === undefined){ | ||
| throw new Error(`Standardization statistics is not defined for column ${column}`); | ||
| } | ||
|
|
||
| return [standardizeValue(value, mean, std)]; | ||
| }); | ||
|
|
||
| return outputRow; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| import type tf from '@tensorflow/tfjs' | ||
|
|
||
| import type { DataType, Model } from '../index.js' | ||
| import type { DataType, Model, ModelMetadata } from '../index.js' | ||
| import { models, serialization } from '../index.js' | ||
| import { GPTConfig } from '../models/index.js' | ||
|
|
||
|
|
@@ -41,11 +41,11 @@ export async function decode(encoded: Encoded): Promise<Model<DataType>> { | |
| const rawModel = raw[1] as unknown | ||
| switch (type) { | ||
| case Type.TFJS: { | ||
| if (raw.length !== 3) | ||
| if (raw.length !== 3 && raw.length !== 4) | ||
| throw new Error( | ||
| "invalid TFJS model encoding: should be an array of length 3", | ||
| "invalid TFJS model encoding: should be an array of length 3 or 4", | ||
| ); | ||
| const [rawDatatype, rawModel] = raw.slice(1) as unknown[]; | ||
| const [rawDatatype, rawModel, rawMetadata] = raw.slice(1) as unknown[]; | ||
|
|
||
| let datatype; | ||
| switch (rawDatatype) { | ||
|
|
@@ -63,6 +63,8 @@ export async function decode(encoded: Encoded): Promise<Model<DataType>> { | |
| datatype, | ||
| // TODO totally unsafe casting | ||
| rawModel as tf.io.ModelArtifacts, | ||
| // metadata for tabular task standardization | ||
| rawMetadata as ModelMetadata, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implement more checks before casting. msgpack potentially returns null instead of undefined when the field is missing |
||
| ]); | ||
| } | ||
| case Type.GPT: { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extractToNumbers is not used anymore