@modelx/jsonm
Version:
Construct AI & ML models with JSON using Typescript & Tensorflow
152 lines (140 loc) • 6.16 kB
text/typescript
import { Data, } from '@modelx/data/src/DataSet';
import { dimensionDates, } from './features';
import { Dimensions, } from './constants';
import { DataSets, } from './dataset';
// import Promisie from 'promisie';
import * as Luxon from 'luxon';
import { dataset0 } from './util';
// const _pipe = (a, b) => (arg) => b(a(arg));
// const pipe = (...ops) => ops.reduce(_pipe);
export type CombineDatasetOptions = {
datasets?: DataSets;
field?: string;
defaultObject?: any;
includeEmptyDates?: boolean;
dateFormat?: string;
date_field?: string;
time_zone?:string;
dimension?:Dimensions;
start_date?:string;
end_date?:string;
};
/**
* Returns first dataset in datasets object passed to reducer functions
* @example
const datasets = {
dataset_1:[{some:'data',}],
dataset_2:[{some_two:'data',}],
dataset_3:[{some_three:'data',}],
}
getFirstDataset(datasets) //=> [{some:'data',}]
*/
export function getFirstDataset(datasets:DataSets = {}):Data {
return datasets[Object.keys(datasets)[0]] || [];
}
/**
* sets a dates dataset based on a date range
*/
export function _helper_setEmptyDates({ dimension, start_date, end_date, time_zone, defaultObject, datasetsProperties, datasets, field, }: { dimension: Dimensions; start_date: string; end_date: string; time_zone: string; defaultObject?: any; datasetsProperties: string[]; datasets: DataSets; field: string; }){
const dates = dimensionDates[ dimension ]({ start: start_date, end: end_date, time_zone, }).map(date => {
return Object.assign({}, defaultObject, {
date,
});
});
datasets = Object.keys(datasets).reduce((updatedDatasetData, datasetDataProperty) => {
updatedDatasetData[ datasetDataProperty ] = datasets[ datasetDataProperty ].map(datum => {
if (datum[field]) {
const ISODateField = datum[ field ];
const updatedField = { [ field ]: Luxon.DateTime.fromISO(ISODateField, { zone: time_zone ||datum.time_zone, }).toJSDate(), };
// console.log(datum._id, 'datum[ field ]', datum[field], { ISODateField, datasetDataProperty, updatedField, datum });
return {
...datum,
...updatedField
};
} else {
return datum;
}
});
return updatedDatasetData;
}, {});
// console.log('post dates', dates);
datasets.dates = dates;
datasetsProperties.splice(0, 0, 'dates');
return dates;
}
/**
* Mutates combined dataset to formate date field based on Luxon dateFormat
*/
export function _helper_formatDateField({ combined, date_field, dateFormat }: { combined: Data; date_field: string; dateFormat: string;}) {
const isJSDate = (combined[0][date_field] instanceof Date);
for (let i = 0; i < combined.length; i++){
combined[i][date_field] = (isJSDate)
? Luxon.DateTime.fromJSDate(combined[i][date_field]).toFormat(dateFormat)
: Luxon.DateTime.fromISO(combined[i][date_field]).toFormat(dateFormat);
}
}
/**
* Returns the first dataset that contains the field to combine on as the base dataset
*/
export function _helper_getBaseDataset({datasetsProperties, field, datasets}) {
let baseDataset = [];
let baseDatasetPropertyName;
datasetsProperties.some((datasetsProperty) => {
let datasetDatum = datasets[datasetsProperty];
if (datasetDatum.filter(dataSetDatumRow => typeof dataSetDatumRow[ field ] !== 'undefined').length) {
baseDataset = datasetDatum;
baseDatasetPropertyName = datasetsProperty;
return datasetsProperty;
}
});
return { baseDataset, baseDatasetPropertyName, };
}
export function combineDatasetsOnField({ datasets, field, defaultObject = {}, includeEmptyDates = false, dateFormat, date_field, time_zone, dimension, start_date, end_date, }:CombineDatasetOptions ={}) {
if (!field) throw ReferenceError('In order to combine datasets, a field parameter is required');
// let datasets = datasets;
const datasetsProperties = Object.keys(datasets);
const { baseDataset, baseDatasetPropertyName, } = _helper_getBaseDataset({ datasetsProperties, field, datasets });
if (includeEmptyDates) {
const dates = _helper_setEmptyDates({ dimension, start_date, end_date, time_zone, defaultObject, datasetsProperties, datasets, field, });
datasets.dates = dates;
}
let maxObjKeysLength = (baseDataset && baseDataset.length && typeof baseDataset[ 0 ] === 'object') ? Object.keys(baseDataset[ 0 ]).length : 0;
let maxObjKeysLengthIndex = 0;
const combined = baseDataset.reduce((combinedDataset, row, rowIndex) => {
let combinedRow = {
...defaultObject,
...row,
};
datasetsProperties.filter(datasetsPropertyName => datasetsPropertyName !== baseDatasetPropertyName).forEach(datasetsPropertyName => {
const matchingRow = datasets[ datasetsPropertyName ].find(dsRow => {
return (dsRow[field] === row[field] ||
(dsRow[field] && row[field] && dsRow[field].toString() === row[field].toString()));
});
if (matchingRow) {
Object.keys(matchingRow).reduce((result, key) => {
if (typeof matchingRow[key] !== 'undefined') {
result[key] = matchingRow[key];
}
return result;
}, combinedRow);
// Object.assign(combinedRow,matchingRow)
}
});
if (Object.keys(combinedRow).length > maxObjKeysLength) {
maxObjKeysLength = Object.keys(combinedRow).length;
maxObjKeysLengthIndex = rowIndex;
}
combinedDataset.push(combinedRow);
return combinedDataset;
}, []);
// console.log('combined',combined);
if (maxObjKeysLengthIndex !== 0) {//fix first data row to have all data properties for table display
const emtpyObject = Object.keys(combined[ maxObjKeysLengthIndex ]).reduce((blankObj, prop) => {
blankObj[ prop ] = undefined;
return blankObj;
}, {});
combined[ 0 ] = Object.assign({}, emtpyObject, combined[ 0 ]);
}
if (date_field && dateFormat) _helper_formatDateField({ combined, date_field, dateFormat });
return combined;
}