danfojs
Version:
JavaScript library providing high performance, intuitive, and easy to use data structures for manipulating and processing structured data.
846 lines (844 loc) • 27.5 kB
JavaScript
;
/**
* @license
* Copyright 2022 JsData. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ==========================================================================
*/
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var defaults_1 = require("./defaults");
var config_1 = __importDefault(require("./config"));
var __1 = require("../");
var __2 = require("../");
var errors_1 = __importDefault(require("../shared/errors"));
var config = new config_1.default(defaults_1.BASE_CONFIG);
/**
* General Utility class
*/
var Utils = /** @class */ (function () {
function Utils() {
}
/**
* Removes an element from a 1D array
*
* ```js
*
* ```
* @param arr The array to filter.
* @param index The index to filter by.
*/
Utils.prototype.removeElementFromArray = function (arr, index) {
var newArr = arr.filter(function (_, i) { return i != index; });
return newArr;
};
/**
* Check if value is a string.
* @param value The value to check.
* @returns
*/
Utils.prototype.isString = function (value) {
return typeof value === "string";
};
/**
* Checks if value is a number.
* @param value The value to check.
* @returns
*/
Utils.prototype.isNumber = function (value) {
return typeof value === "number" && isFinite(value);
};
/**
* Checks if value is an object.
* @param value The value to check.
* @returns
*/
Utils.prototype.isObject = function (value) {
return value && typeof value === "object" && value.constructor && value.constructor.name === "Object";
};
/**
* Checks if a value is null
* @param value The value to check.
* @returns
*/
Utils.prototype.isNull = function (value) {
return value === null;
};
/**
* Checks if a value is undefined
* @param value The value to check.
* @returns
*/
Utils.prototype.isUndefined = function (value) {
return typeof value === "undefined";
};
/**
* Checks if a value is empty. Empty means it's either null, undefined or NaN.
* Empty strings are NOT considered empty.
* @param value The value to check.
* @returns boolean indicating if the value is empty
*/
Utils.prototype.isEmpty = function (value) {
if (value === undefined || value === null) {
return true;
}
if (typeof value === 'bigint') {
return false; // BigInt values are never considered empty
}
if (typeof value === 'number') {
return isNaN(value);
}
return false; // All other types (strings, objects, arrays, etc) are not considered empty
};
/**
* Checks if a value is a date object
* @param value A date object
* @returns boolean
*/
Utils.prototype.isDate = function (value) {
return value instanceof Date;
};
/**
* Generates an array of integers between specified range
* @param start The starting number.
* @param end The ending number.
*/
Utils.prototype.range = function (start, end) {
if (end < start) {
throw new Error("ParamError: end must be greater than start");
}
if (start === end) {
return [start];
}
var arr = [];
for (var i = start; i <= end; i++) {
arr.push(i);
}
return arr;
};
/**
* Checks if object has the specified key
* @param obj The object to check.
* @param key The key to find.
*/
Utils.prototype.keyInObject = function (obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
};
/**
* Transposes an array of array
* @param obj The object to check.
* @param key The key to find.
*/
Utils.prototype.transposeArray = function (arr) {
if (arr.length === 0)
return arr;
var rowLen = arr.length;
if (Array.isArray(arr[0])) {
var colLen = arr[0].length;
var newArr = [];
for (var i = 0; i <= colLen - 1; i++) {
var temp = [];
for (var j = 0; j < rowLen; j++) {
var _elem = arr[j][i];
temp.push(_elem);
}
newArr.push(temp);
}
return newArr;
}
else {
return arr;
}
};
/**
* Retrieve row array and column names from an object of the form {a: [1,2,3,4], b: [30,20, 30, 20]}
* @param obj The object to retrieve rows and column names from.
*/
Utils.prototype.getRowAndColValues = function (obj) {
var colNames = Object.keys(obj);
var colData = Object.values(obj);
var firstColLen = colData[0].length;
colData.forEach(function (cdata) {
if (cdata.length != firstColLen) {
throw Error("Length Error: Length of columns must be the same!");
}
});
var rowsArr = this.transposeArray(colData);
return [rowsArr, colNames];
};
/**
* Converts a 2D array of array to 1D array for Series Class
* @param arr The array to convert.
*/
Utils.prototype.convert2DArrayToSeriesArray = function (arr) {
var _this = this;
var newArr = arr.map(function (val) {
if (_this.isObject(val)) {
return JSON.stringify(val);
}
else {
return "" + val;
}
});
return newArr;
};
/**
* Replaces all missing values with NaN. Missing values are undefined, Null and Infinity
* @param arr The array
* @param isSeries Whether the arr is a series or not
*/
Utils.prototype.replaceUndefinedWithNaN = function (arr, isSeries) {
if (arr.length === 0)
return arr;
if (isSeries && Array.isArray(arr)) {
var newArr = arr.map(function (ele) {
if (typeof ele === "undefined") {
return NaN;
}
if (typeof ele === "number" && (isNaN(ele) || ele == Infinity)) {
return NaN;
}
if (ele == null) {
return NaN;
}
return ele;
});
return newArr;
}
else {
var newArr = [];
if (Array.isArray(arr)) {
for (var i = 0; i < arr.length; i++) {
var innerArr = arr[i];
var temp = innerArr.map(function (ele) {
if (typeof ele === "undefined") {
return NaN;
}
if (typeof ele === "number" && (isNaN(ele) || ele == Infinity)) {
return NaN;
}
if (ele == null) {
return NaN;
}
return ele;
});
newArr.push(temp);
}
}
return newArr;
}
};
/**
* Infer data type from an array or array of arrays
* @param arr An array or array of arrays
*/
Utils.prototype.inferDtype = function (arr) {
var self = this;
if (this.is1DArray(arr)) {
return [this.$typeChecker(arr)];
}
else {
var arrSlice = this.transposeArray(arr.slice(0, config.getDtypeTestLim));
var dtypes = arrSlice.map(function (innerArr) {
return self.$typeChecker(innerArr);
});
return dtypes;
}
};
/**
* Private type checker used by inferDtype function
* @param arr The array
*/
Utils.prototype.$typeChecker = function (arr) {
var dtypes;
var lim;
var intTracker = [];
var floatTracker = [];
var stringTracker = [];
var boolTracker = [];
var dateTracker = [];
if (arr.length < config.getDtypeTestLim) {
lim = arr.length;
}
else {
lim = config.getDtypeTestLim;
}
var arrSlice = arr.slice(0, lim);
for (var i = 0; i < lim; i++) {
var ele = arrSlice[i];
if (typeof ele == "boolean") {
floatTracker.push(false);
intTracker.push(false);
stringTracker.push(false);
boolTracker.push(true);
dateTracker.push(false);
}
else if (this.isEmpty(ele)) {
floatTracker.push(true);
intTracker.push(false);
stringTracker.push(false);
boolTracker.push(false);
dateTracker.push(false);
}
else if (this.isDate(ele)) {
floatTracker.push(false);
intTracker.push(false);
stringTracker.push(false);
boolTracker.push(false);
dateTracker.push(true);
}
else if (!isNaN(Number(ele))) {
if (ele.toString().includes(".")) {
floatTracker.push(true);
intTracker.push(false);
stringTracker.push(false);
boolTracker.push(false);
dateTracker.push(false);
}
else {
floatTracker.push(false);
intTracker.push(true);
stringTracker.push(false);
boolTracker.push(false);
dateTracker.push(false);
}
}
else {
floatTracker.push(false);
intTracker.push(false);
stringTracker.push(true);
boolTracker.push(false);
dateTracker.push(false);
}
}
var even = function (ele) { return ele == true; };
if (stringTracker.some(even)) {
dtypes = "string";
}
else if (floatTracker.some(even)) {
dtypes = "float32";
}
else if (intTracker.some(even)) {
dtypes = "int32";
}
else if (boolTracker.some(even)) {
dtypes = "boolean";
}
else if (dateTracker.some(even)) {
dtypes = "datetime";
}
else {
dtypes = "undefined";
}
return dtypes;
};
/**
* Returns the unique values in an 1D array
* @param arr The array
*/
Utils.prototype.unique = function (arr) {
var uniqueArr = new Set(arr);
return Array.from(uniqueArr);
};
/**
* Checks if array is 1D
* @param arr The array
*/
Utils.prototype.is1DArray = function (arr) {
if (typeof arr[0] == "number" ||
typeof arr[0] == "string" ||
typeof arr[0] == "boolean" ||
arr[0] === null) {
return true;
}
else {
return false;
}
};
/**
* Converts an array to an object using array index as object keys
* @param arr The array
*/
Utils.prototype.convertArrayToObject = function (arr) {
var arrObj = {};
for (var i = 0; i < arr.length; i++) {
arrObj[i] = arr[i];
}
return arrObj;
};
/**
* Count the NaN and non-NaN values present in an array
* @param arr Array object
* @param val whether to return the value count instead of the null count
* @param isSeries Whether the array is of type series or not
*/
Utils.prototype.countNaNs = function (arr, returnVal, isSeries) {
if (returnVal === void 0) { returnVal = true; }
if (isSeries) {
var nullCount = 0;
var valCount = 0;
for (var i = 0; i < arr.length; i++) {
var ele = arr[i];
if (Number.isNaN(ele)) {
nullCount = nullCount + 1;
}
else {
valCount = valCount + 1;
}
}
if (returnVal) {
return valCount;
}
else {
return nullCount;
}
}
else {
var resultArr = [];
for (var i = 0; i < arr.length; i++) {
var innerArr = arr[i];
var nullCount = 0;
var valCount = 0;
for (var i_1 = 0; i_1 < innerArr.length; i_1++) {
var ele = innerArr[i_1];
if (Number.isNaN(ele)) {
nullCount = nullCount + 1;
}
else {
valCount = valCount + 1;
}
}
if (returnVal) {
resultArr.push(valCount);
}
else {
resultArr.push(nullCount);
}
}
return resultArr;
}
};
/**
* Round elements of an array or array of arrays to specified dp
* @param arr The Array to round
* @param dp The number of dp to round to
* @param isSeries Whether the array is of type Series or not
*/
Utils.prototype.round = function (arr, dp, isSeries) {
if (dp === void 0) { dp = 1; }
if (dp < 0) {
dp = 1;
}
if (isSeries) {
var newArr = [];
for (var i = 0; i < arr.length; i++) {
var ele = arr[i];
if (typeof ele == "number" && !isNaN(ele) && ele !== undefined && ele !== null) {
newArr.push(Number((ele).toFixed(dp)));
}
else {
newArr.push(ele);
}
}
return newArr;
}
else {
var resultArr = [];
for (var i = 0; i < arr.length; i++) {
var innerVal = arr[i];
var newArr = [];
if (Array.isArray(innerVal)) {
for (var i_2 = 0; i_2 < innerVal.length; i_2++) {
var ele = innerVal[i_2];
if (typeof ele == "number" && !isNaN(ele) && ele !== undefined && ele !== null) {
newArr.push(Number((ele).toFixed(dp)));
}
else {
newArr.push(ele);
}
}
resultArr.push(newArr);
}
else {
if (typeof innerVal == "number" && !isNaN(innerVal) && innerVal !== undefined && innerVal !== null) {
newArr.push(Number((innerVal).toFixed(dp)));
}
else {
newArr.push(innerVal);
}
}
}
return resultArr;
}
};
/**
* Checks if a func is a function
* @param func
*/
Utils.prototype.isFunction = function (func) {
return typeof func == "function";
};
/**
* Generates n random numbers between start and end.
* @param start
* @param end
* @param size
*/
Utils.prototype.randNumberGenerator = function (start, end, size) {
var genNum = [];
function randi(a, b) {
return Math.floor(Math.random() * (b - a) + a);
}
function recursive(val, arr) {
if (!arr.includes(val)) {
return val;
}
val = randi(start, end);
recursive(val, arr);
}
for (var i = 0; i < size; i++) {
var genVal = randi(start, end);
var recursiveVal = recursive(genVal, genNum);
genNum.push(recursiveVal);
}
return genNum;
};
/**
* Throws error when a required parameter is missing.
* @param paramsObject The parameters passed to the function
* @param paramsNeeded The required parameters in the function
*/
Utils.prototype.throwErrorOnWrongParams = function (paramsObject, paramsNeeded) {
var keys = Object.keys(paramsObject);
var bool = [];
for (var i = 0; i < keys.length; i++) {
if (paramsNeeded.includes(keys[i])) {
bool.push(true);
}
else {
bool.push(false);
}
}
var truthy = function (element) { return element == false; };
if (bool.some(truthy)) {
throw Error("Params Error: Required parameter not found. Your params must include the following [" + paramsNeeded + "]");
}
};
/**
* Maps integer values (0, 1) to boolean (false, true)
* @param arr The array of integers
* @param dim The dimension of the array
*/
Utils.prototype.mapIntegersToBooleans = function (arr, dim) {
if (dim == 2) {
var newArr_1 = [];
arr.map(function (innerArr) {
var temp = [];
innerArr.map(function (val) { return temp.push(val == 1); });
newArr_1.push(temp);
});
return newArr_1;
}
else {
var newArr_2 = [];
arr.map(function (val) { return newArr_2.push(val == 1); });
return newArr_2;
}
};
/**
* Maps boolean values (false, true) to integer equivalent (0, 1)
* @param arr The array of booleans
* @param dim The dimension of the array
*/
Utils.prototype.mapBooleansToIntegers = function (arr, dim) {
if (dim == 2) {
var newArr_3 = [];
arr.map(function (innerArr) {
var temp = [];
innerArr.map(function (val) { return temp.push(val ? 1 : 0); });
newArr_3.push(temp);
});
return newArr_3;
}
else {
var newArr_4 = [];
arr.map(function (val) { return newArr_4.push(val ? 1 : 0); });
return newArr_4;
}
};
/**
* Generates an array of dim (row x column) with inner values set to zero
* @param row
* @param column
*/
Utils.prototype.zeros = function (row, column) {
var zeroData = [];
for (var i = 0; i < row; i++) {
var colData = Array(column);
for (var j = 0; j < column; j++) {
colData[j] = 0;
}
zeroData.push(colData);
}
return zeroData;
};
/**
* Shuffles and returns a random slice of an array
* @param num
* @param array
*/
Utils.prototype.shuffle = function (array, num) {
var i = array.length;
var j = 0;
var temp;
while (i--) {
j = Math.floor(Math.random() * (i + 1));
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array.slice(0, num);
};
/**
* Sorts an array in specified order
* @param arr
* @param ascending
* @returns
*/
Utils.prototype.sort = function (arr, ascending) {
if (ascending === void 0) { ascending = true; }
var sorted = __spreadArray([], arr, true);
return sorted.sort(function (a, b) {
if (ascending) {
if (typeof a === "string" && typeof b === "string") {
return a.charCodeAt(0) - b.charCodeAt(0);
}
else {
return a - b;
}
}
else {
if (typeof a === "string" && typeof b === "string") {
return b.charCodeAt(0) - a.charCodeAt(0);
}
else {
return b - a;
}
}
});
};
/**
* Checks if current environment is Browser
*/
Utils.prototype.isBrowserEnv = function () {
var isBrowser = new Function("try {return this===window;}catch(e){ return false;}");
return isBrowser();
};
/**
* Checks if current environment is Node
*/
Utils.prototype.isNodeEnv = function () {
var isNode = new Function("try {return this===global;}catch(e){return false;}");
return isNode();
};
/**
* Remove NaN values from 1D array
* @param arr
*/
Utils.prototype.removeMissingValuesFromArray = function (arr) {
var _this = this;
var values = arr.filter(function (val) {
return !(_this.isEmpty(val));
});
return values;
};
/**
* Replace NaN with null before tensor operations
* @param arr
*/
Utils.prototype.replaceNanWithNull = function (arr) {
var values = arr.map(function (val) {
if (isNaN(val)) {
return null;
}
else {
return val;
}
});
return values;
};
/**
* Get duplicate values in a array
* @param arr
*/
Utils.prototype.getDuplicate = function (arr) {
var tempObj = {};
var resultObj = {};
for (var i = 0; i < arr.length; i++) {
var val = arr[i];
if (this.keyInObject(tempObj, val)) {
tempObj[val]["count"] += 1;
tempObj[val]["index"].push(i);
}
else {
tempObj[val] = {};
tempObj[val]["count"] = 1;
tempObj[val]["index"] = [i];
}
}
for (var key in tempObj) {
if (tempObj[key]["count"] >= 2) {
resultObj[key] = {};
resultObj[key]["count"] = tempObj[key]["count"];
resultObj[key]["index"] = tempObj[key]["index"];
}
}
return resultObj;
};
/**
* Returns the index of a sorted array
* @param arr1 The first array
* @param arr2 The second array
* @param dtype The data type of the arrays
*
* @returns sorted index
*/
Utils.prototype.sortArrayByIndex = function (arr1, arr2, dtype) {
var sortedIdx = arr1.map(function (item, index) {
return [arr2[index], item];
});
if (dtype == "string") {
sortedIdx.sort();
}
else {
sortedIdx.sort(function (_a, _b) {
var arg1 = _a[0];
var arg2 = _b[0];
return arg2 - arg1;
});
}
return sortedIdx.map(function (_a) {
var item = _a[1];
return item;
});
};
/**
* Returns a new series with properties of the old series
*
* @param series The series to copy
*/
Utils.prototype.createNdframeFromNewDataWithOldProps = function (_a) {
var ndFrame = _a.ndFrame, newData = _a.newData, isSeries = _a.isSeries;
if (isSeries) {
return new __1.Series(newData, {
index: __spreadArray([], ndFrame.index, true),
columns: __spreadArray([], ndFrame.columns, true),
dtypes: __spreadArray([], ndFrame.dtypes, true),
config: __assign({}, ndFrame.config)
});
}
else {
return new __2.DataFrame(newData, {
index: __spreadArray([], ndFrame.index, true),
columns: __spreadArray([], ndFrame.columns, true),
dtypes: __spreadArray([], ndFrame.dtypes, true),
config: __assign({}, ndFrame.config)
});
}
};
/**
* Checks if two series are compatible for a mathematical operation
* @param object
*
* firstSeries ==> First Series object
*
* secondSeries ==> Second Series object to comapre with
*
* operation ==> The mathematical operation
*/
Utils.prototype.checkSeriesOpCompactibility = function (_a) {
var firstSeries = _a.firstSeries, secondSeries = _a.secondSeries, operation = _a.operation;
if (firstSeries.shape[0] != secondSeries.shape[0]) {
errors_1.default.throwSeriesMathOpLengthError(firstSeries, secondSeries);
}
if (firstSeries.dtypes[0] == 'string' || secondSeries.dtypes[0] == 'string') {
errors_1.default.throwStringDtypeOperationError(operation);
}
};
/**
* Custom sort for an array of index and values
* @param arr The array of objects to sort
* @param ascending Whether to sort in ascending order or not
*/
Utils.prototype.sortObj = function (arr, ascending) {
var sortedValues = arr.sort(function (obj1, obj2) {
var a = obj2.value;
var b = obj1.value;
if (!ascending) {
if (typeof a === "string" && typeof b === "string") {
a = a.toUpperCase();
b = b.toUpperCase();
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
}
else {
return Number(a) - Number(b);
}
}
else {
if (typeof a === "string" && typeof b === "string") {
a = a.toUpperCase();
b = b.toUpperCase();
if (a > b) {
return -1;
}
if (a < b) {
return 1;
}
return 0;
}
else {
return Number(b) - Number(a);
;
}
}
});
return sortedValues;
};
return Utils;
}());
exports.default = Utils;