jandas
Version:
A very much Pandas-like JavaScript library for data science
960 lines (959 loc) • 37.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const util_1 = require("./util");
const cmm_1 = require("./cmm");
const df_lib_1 = require("./df_lib");
const util2_1 = require("./util2");
const Index_1 = require("./Index");
const Series_1 = require("./Series");
const stat = require("simple-statistics");
const _ = require("lodash");
const ranks = require("@stdlib/stats-ranks");
class DataFrame {
constructor(arr, options) {
if (_.isUndefined(options))
options = {};
let columns;
if (arr.length > 0 && !(0, util_1.isArr)(arr[0])) {
columns = Object.keys(arr[0]);
const _cols = columns;
arr = arr.map(obj => _cols.map(key => obj[key]));
// index = options && !_.isUndefined(options.index) ?
// options.index : null
options.columns = _cols;
}
let _arr = arr;
let _options = options;
_options = _.defaults(_options, { columns: _arr.length === 0 ? [] : _arr[0].map((_, i) => i),
index: _arr.map((_, i) => i) });
this._index = _options.index instanceof Index_1.default ?
_options.index : new Index_1.default(_options.index);
this._columns = _options.columns instanceof Index_1.default ?
_options.columns : new Index_1.default(_options.columns);
this.shape = [this.index.shape, this.columns.shape];
util_1.check.frame.index.set(_arr.length, this.shape[0]);
if (_arr.length > 0)
util_1.check.frame.index.set(_arr[0].length, this.shape[1]);
this.values = _arr;
}
// https://stackoverflow.com/questions/17428587/transposing-a-2d-array-in-javascript
__transpose(arr) { return arr[0].map((_, colIndex) => arr.map(row => row[colIndex])); }
_transpose(arr) {
if (arr.length === 0)
return [];
else
return this.__transpose(arr);
}
get tr() {
if (_.isUndefined(this._tr)) {
if (this.values.length > 0)
this._tr = this._transpose(this.values);
else {
this._tr = Array.from(Array(this.shape[1]).keys())
.map(_ => []);
// this.values = this._transpose(this.tr)
}
}
return this._tr;
}
set tr(vals) {
this._tr = vals;
}
get index() {
return this._index;
}
get columns() {
return this._columns;
}
_indexSetterEffect() {
// interface
// any side effects one may want to
// invoke when index is set
}
set index(vals) {
this._index = (0, cmm_1.setIndex)(vals, this.shape[0]);
this._indexSetterEffect();
}
set columns(vals) {
this._columns = (0, cmm_1.setIndex)(vals, this.shape[1]);
}
rename(labelMap, inplace = false) {
if (inplace) {
if (labelMap.index)
(0, cmm_1._rename)(this.index, labelMap.index, true);
if (labelMap.columns)
(0, cmm_1._rename)(this.columns, labelMap.columns, true);
}
else {
const [index, columns] = [this.index.cp(), this.columns.cp()];
if (labelMap.index)
(0, cmm_1._rename)(index, labelMap.index, true);
if (labelMap.columns)
(0, cmm_1._rename)(columns, labelMap.columns, true);
return new DataFrame((0, cmm_1.cp)(this.values), { index, columns });
}
}
_p() {
let lines = [];
const corner = `${this.index.name}|${this.columns.name}`;
lines.push(corner + '\t' + this.columns.values.map(x => x.toString()).join('\t'));
// lines.push('\t'+this.columns.values.map(_=>'-').join('-'))
const content = this.values.map((row, i) => {
let line = [];
line.push(this.index.values[i].toString());
line = line.concat(row.map(x => JSON.stringify(x)));
return line.join('\t');
});
lines = lines.concat(content);
console.log(lines.join('\n') + '\n' + 'DataFrame ' + `(${this.shape})`);
}
p() {
const corner = `${this.index.name}|${this.columns.name}`;
const df = this.reset_index(corner).reset_columns();
console.table(df.values);
console.log('DataFrame ' + `(${this.shape})`);
}
transpose(inplace = false) {
if (inplace) {
[this.values, this.tr] = [this.tr, this.values];
[this.shape[0], this.shape[1]] = [this.shape[1], this.shape[0]];
[this.index, this.columns] = [this.columns, this.index];
return this;
}
else {
return new DataFrame((0, cmm_1.cp)(this.tr), { index: this.columns.cp(), columns: this.index.cp() });
}
}
_iloc_asymmetric(v1, l1, l2, transpose, i1, i2) {
// // TODO study function union types
// type loc_fun_type = (a:T[] | T[][] | ns_arr, idx:boolean[] | number[]) => T[] | T[][] | ns_arr
switch (true) {
case (0, util_1.isNum)(i1) && i2 === undefined:
util_1.check.iloc.num(i1, l1.shape);
const i1x = i1;
return new Series_1.default((0, cmm_1.cp)(v1[i1x]), { index: l2.cp(), name: l1.values[i1x] });
case (0, util_1.isNum)(i1) && (0, util_1.isArr)(i2):
{
util_1.check.iloc.num(i1, l1.shape);
const i2x = i2;
const i1x = i1;
const vec = v1[i1x];
const [new_vec, new_idx] = (0, cmm_1.vec_loc2)(vec, l2.values, i2x);
const final_index = new Index_1.default(new_idx, l2.name);
return new Series_1.default(new_vec, { index: final_index, name: l1.values[i1x] });
}
case (0, util_1.isArr)(i1) && i2 === undefined:
{
const i1x = i1;
const [new_mat, new_idx] = (0, cmm_1.vec_loc2)(v1, l1.values, i1x);
const final_l1 = new Index_1.default(new_idx, l1.name);
const final_l2 = l2.cp();
const df = new DataFrame(new_mat, { index: final_l1, columns: final_l2 });
return transpose ? df.transpose(true) : df;
}
default:
return null;
}
}
// _iloc_symmetric(ir:number,ic:number):T
// _iloc_symmetric(ir?:number[]|boolean[],ic?:number[]|boolean[]):DataFrame<T>|null
_iloc_symmetric(ir, ic) {
switch (true) {
case ir == undefined && ic == undefined:
const vals = this.values.map(r => (0, cmm_1.cp)(r));
return new DataFrame(vals, { index: this.index.cp(),
columns: this.columns.cp() });
case (0, util_1.isNum)(ir) && (0, util_1.isNum)(ic):
util_1.check.iloc.num(ir, this.shape[0]);
util_1.check.iloc.num(ic, this.shape[1]);
return this.values[ir][ic];
case (0, util_1.isArr)(ir) && (0, util_1.isArr)(ic):
const irx = ir;
const icx = ic;
// inplace vec_loc for this.values
const sub_vals = (0, cmm_1.vec_loc)(this.values, irx, (x) => x);
const final_vals = sub_vals.map(vec => (0, cmm_1.vec_loc)(vec, icx));
const final_index = new Index_1.default((0, cmm_1.vec_loc)(this.index.values, irx), this.index.name);
const final_columns = new Index_1.default((0, cmm_1.vec_loc)(this.columns.values, icx), this.columns.name);
return new DataFrame(final_vals, { index: final_index, columns: final_columns });
default:
return null;
}
}
iloc(row, col) {
if (row === null)
row = undefined;
if (col === null)
col = undefined;
row = (0, util_1._trans_iloc)(row, this.shape[0]);
col = (0, util_1._trans_iloc)(col, this.shape[1]);
let res;
res = this._iloc_symmetric(row, col);
// console.log('sym res',res)
if (res !== null)
return res;
if (col === undefined || (0, util_1.isVal)(row)) {
res = this._iloc_asymmetric(this.values, this.index, this.columns, false, row, col);
// console.log('asym row res',res)
if (res !== null)
return res;
}
else {
res = this._iloc_asymmetric(this.tr, this.columns, this.index, true, col, row);
// console.log('asym col res',res)
if (res !== null)
return res;
}
throw (`input parameters for iloc might be wrong`);
}
loc(row, col) {
if (row === null)
row = undefined;
if (col === null)
col = undefined;
row = row;
col = col;
const num_row = (0, cmm_1._trans)(this.index, row);
const num_col = (0, cmm_1._trans)(this.columns, col);
return this.iloc(num_row, num_col);
}
_iset_asymmetric(v1, l1, l2, i1, rpl, i2) {
// // TODO study function union types
// type loc_fun_type = (a:T[] | T[][] | ns_arr, idx:boolean[] | number[]) => T[] | T[][] | ns_arr
switch (true) {
case (0, util_1.isVal)(i1) && i2 === undefined:
util_1.check.iloc.num(i1, l1.shape);
util_1.check.iset.rpl.num(rpl, l2.shape);
v1[i1] = rpl;
break;
case (0, util_1.isVal)(i1) && (0, util_1.isArr)(i2):
{
util_1.check.iloc.num(i1, l1.shape);
util_1.check.iset.rpl.num(rpl, i2.length);
const i2x = i2;
const vec = v1[i1];
(0, cmm_1.vec_set)(vec, rpl, i2x);
}
break;
case (0, util_1.isArr)(i1) && i2 === undefined:
(0, cmm_1.vec_set)(v1, rpl, i1);
break;
default:
return null;
}
}
_iset_symmetric(ir, ic, rpl) {
switch (true) {
case ir == undefined && ic == undefined:
util_1.check.iset.rpl.mat(rpl, this.shape);
this.values = rpl;
this._tr = undefined;
break;
case (0, util_1.isVal)(ir) && (0, util_1.isVal)(ic):
util_1.check.iloc.num(ir, this.shape[0]);
util_1.check.iloc.num(ic, this.shape[1]);
this.values[ir][ic] = rpl;
if (!_.isUndefined(this._tr))
this.tr[ic][ir] = rpl;
break;
case (0, util_1.isArr)(ir) && (0, util_1.isArr)(ic):
const sub_mat = (0, cmm_1.vec_loc)(this.values, ir, (x) => x);
sub_mat.forEach((vec, ix) => {
(0, cmm_1.vec_set)(vec, rpl[ix], ic);
});
this._tr = undefined;
break;
default:
return null;
}
}
_iset(row, col, rpl) {
let res;
res = this._iset_symmetric(row, col, rpl);
// console.log('_iset_symmetric',res,row,col,rpl)
if (res === null) {
rpl = rpl;
if (col === undefined || (0, util_1.isVal)(row)) {
res = this._iset_asymmetric(this.values, this.index, this.columns, row, rpl, col);
// console.log('_iset_asymmetric1',res)
if (res === undefined)
this._tr = undefined;
}
else {
if (rpl.length > 0 && (0, util_1.isArr)(rpl[0]))
rpl = this._transpose(rpl);
res = this._iset_asymmetric(this.tr, this.columns, this.index, col, rpl, row);
if (res === undefined)
this.values = this._transpose(this.tr);
}
}
if (res === null)
throw ('function failed. Please check the input for _iset');
}
iset(first, second, third) {
if (second === undefined && third === undefined) {
this._iset(undefined, undefined, first);
}
else if (third === undefined) {
if (first === null)
first = undefined;
this._iset(first, undefined, second);
}
else {
if (first === null)
first = undefined;
if (second === null)
second = undefined;
this._iset(first, second, third);
}
}
set(first, second, third) {
if (second === undefined && third === undefined) {
this._iset(undefined, undefined, first);
}
else if (third === undefined) {
if (first === null)
first = undefined;
if ((0, util_1.isVal)(first) && !this.index.has(first))
//using set to add new row
this.push(second, { name: first, axis: 0 });
else {
// second = this._hdl_duplicate(first,this.index,second)
const num_row = (0, cmm_1._trans)(this.index, first);
this._iset(num_row, undefined, second);
}
}
else {
if (first === null)
first = undefined;
if (second === null)
second = undefined;
if (first === undefined && (0, util_1.isVal)(second) && !this.columns.has(second))
//using set to add new column
this.push(third, { name: second, axis: 1 });
else {
// third = this._hdl_duplicate(second,this.columns,third)
// third = this._hdl_duplicate(first,this.index,third)
const num_row = (0, cmm_1._trans)(this.index, first);
const num_col = (0, cmm_1._trans)(this.columns, second);
this._iset(num_row, num_col, third);
}
}
}
// push(val:T[],name:number|string='',axis:0|1=1){
_push(val, { name = '', axis = 1 } = {}) {
if (axis === 0) {
util_1.check.iset.rpl.num(val, this.shape[1]);
this.values.push(val);
this.index.values.push(name);
this.shape[axis] += 1;
if (!_.isUndefined(this._tr))
this.tr.forEach((v, i) => {
v.push(val[i]);
});
}
else {
util_1.check.iset.rpl.num(val, this.shape[0]);
if (!_.isUndefined(this._tr))
this.tr.push(val);
this.columns.values.push(name);
this.shape[axis] += 1;
this.values.forEach((v, i) => {
v.push(val[i]);
});
}
}
_series_push(val, options) {
const label = options.axis === 0 ? 'columns' : 'index';
if (JSON.stringify(val.index.values) ===
JSON.stringify(this[label].values))
this._push(val.values, options);
else {
if (this[label].is_unique()) {
try {
val = val.loc(this[label].values);
}
catch (e) {
throw (`There are values in the DataFrame's ${label} that are not in the to be pushed Series' index.`);
}
if (val.shape > this[label].shape)
throw (`The series' index values that are indexed by the DataFrame's ${label} are not unique.`);
this._push(val.values, options);
}
else {
throw (`If the to be pushed Series' index does not match the DataFrame's ${label} exactly, the DataFrame's${label} must have only unique values.`);
}
}
}
push(val, options = {}) {
if (val instanceof Series_1.default) {
_.defaults(options, { name: val.name, axis: 1 });
this._series_push(val, options);
}
else {
_.defaults(options, { name: '', axis: 1 });
this._push(val, options);
}
}
_insert(i1, l1, v1, rpl, name) {
util_1.check.iloc.num(i1, l1.shape);
v1.splice(i1, 0, rpl);
l1.insert(i1, name);
}
// insert(idx:number,val:T[],name:number|string='',axis:0|1=1){
insert(idx, val, { name = '', axis = 1 } = {}) {
if (axis === 0) {
idx = idx < 0 ? this.shape[0] + idx : idx;
this._insert(idx, this.index, this.values, val, name);
this.shape[axis] += 1;
this._tr = undefined;
}
else {
idx = idx < 0 ? this.shape[1] + idx : idx;
this._insert(idx, this.columns, this.tr, val, name);
this.shape[axis] += 1;
this.values = this._transpose(this.tr);
}
}
drop(labels, axis = 1) {
labels = (0, util_1.isArr)(labels) ? labels : [labels];
const labels2 = labels;
if (axis === 0) {
const new_idx = (0, util_1.range)(this.index.shape).filter(i => !labels2.includes(this.index.values[i]));
return this.iloc(new_idx);
}
else {
const new_idx = (0, util_1.range)(this.columns.shape).filter(i => !labels2.includes(this.columns.values[i]));
return this.iloc(null, new_idx);
}
}
drop_duplicates(labels, { keep = 'first', axis = 1 } = {}) {
if (axis === 1) {
const sub = this.loc(null, labels);
const idx = (0, cmm_1.duplicated)(sub.values, keep);
return this.loc(idx.map(x => !x));
}
else {
let sub = this.loc(labels);
if (sub instanceof DataFrame)
sub = sub.transpose();
const idx = (0, cmm_1.duplicated)(sub.values, keep);
return this.loc(null, idx.map(x => !x));
}
}
set_index(label) {
util_1.check.set_index.label_uniq(label, this.columns);
const vec = this.loc(null, label).values;
const df = this.drop(label);
//TODO: consider validate if vec is ns_arr
df.index = new Index_1.default(vec, label);
return df;
}
set_columns(label) {
util_1.check.set_index.label_uniq(label, this.index);
const vec = this.loc(label).values;
const df = this.drop(label, 0);
//TODO: consider validate if vec is ns_arr
df.columns = new Index_1.default(vec, label);
return df;
}
reset_index(name) {
const df = new DataFrame((0, cmm_1.cp)(this.values), { columns: this.columns.cp() });
const val = this.index.values;
name = name ? name : this.index.name;
// workaround for val using "as T[]""
// maybe there is a better way to
// handle this.
df.insert(0, val, { name: name, axis: 1 });
return df;
}
reset_columns(name) {
const df = new DataFrame((0, cmm_1.cp)(this.values), { index: this.index.cp() });
const val = this.columns.values;
name = name ? name : this.columns.name;
// workaround for val using "as T[]""
// maybe there is a better way to
// handle this.
df.insert(0, val, { name: name, axis: 0 });
return df;
}
to_dict(axis = 1) {
// similar to pandas DataFrame.to_dict('records')
const vals_arr = axis === 1 ? this.values : this.tr;
const index = axis === 1 ? this.columns : this.index;
if (!index.is_unique())
console.warn('The index is not unique. The output will only include the value of the last key among duplicated keys.');
return vals_arr.map(vals => {
const o = {};
index.values.forEach((k, i) => {
o[k] = vals[i];
});
return o;
});
}
bool(expr, axis = 1) {
return this.b(expr, { axis: axis });
}
b(expr, options) {
if (_.isUndefined(options))
options = {};
let { ctx = undefined, axis = 1 } = options;
// ["bc"] > 5 && [5] > 6
const arr = [];
(0, util_1.range)(expr.length).forEach(i => {
let char = expr[i];
if (char === '[' || char === ']') {
arr.push(i);
}
});
util_1.check.frame.b.expr(arr.length);
// console.log(arr)
let labels = [];
let expr2 = expr;
(0, util_1.range)(arr.length / 2).forEach(i => {
const start = arr[i * 2];
const end = arr[i * 2 + 1];
// console.log(start,end)
const pattern = expr.slice(start, end + 1);
const labelx = expr.slice(start + 1, end);
let label = labelx.trim();
// differentiate loc [] from array []
//https://stackoverflow.com/questions/881085/count-the-number-of-occurrences-of-a-character-in-a-string-in-javascript
const dbl_quote_count = (label.match(/"/g) || []).length;
const sgl_quote_count = (label.match(/'/g) || []).length;
const quote_count = dbl_quote_count > sgl_quote_count ?
dbl_quote_count : sgl_quote_count;
if (label.includes(',') && (quote_count === 0 || quote_count > 2))
return;
// [element,] to represent an arry with one element.
if (label[label.length - 1] === ',')
return;
// handle trailling white space in []
if (label !== labelx)
expr2 = expr.replaceAll(pattern, `[${label}]`);
// console.log('a',label)
label = label[0] === '"' || label[0] === "'" ?
label.slice(1, label.length - 1) : parseInt(label);
labels.push(label);
});
expr = expr2;
// console.log(labels)
const index = axis === 1 ? this.columns : this.index;
const vals = axis === 1 ? this.values : this.tr;
const num_idx = labels.map(x => {
const indices = index.trans(x);
let idx;
if ((0, util_1.isArr)(indices)) {
// for duplicate index, use the last one as in pandas query function
idx = indices[indices.length - 1];
console.warn(`label ${x} is duplicated in the DataFrame's ${axis === 1 ? 'columns' : 'index'}. The last one is used.`);
}
else {
idx = indices;
}
return idx;
});
labels.forEach((label, i) => {
const num = num_idx[i];
const pattern = (0, util_1.isNum)(label) ?
`[${label}]` : `["${label}"]`;
const rpl = `v[${num}]`;
expr = expr.replaceAll(pattern, rpl);
});
const __ctx__ = options.ctx;
const newExpr = (0, cmm_1.addCtx)(expr, __ctx__);
// console.log(expr)
// console.log(newExpr)
const bidx = vals.map(v => eval(newExpr));
return bidx;
}
query(first, second, third) {
return this.q(first, second, third);
}
q(first, second, third) {
let row_index = null;
let col_index = null;
if (_.isUndefined(second))
row_index = this.b(first, { axis: 1 });
else if (_.isUndefined(third)) {
if (!_.isString(second) && second !== null)
row_index = this.b(first, { axis: 1, ctx: second });
else {
const atPosArr = _.isString(first) ?
(0, df_lib_1.findUnquotedAt)(first) :
undefined;
if (atPosArr && atPosArr.length > 0)
row_index = this.b(first, { axis: 1, ctx: second });
else {
col_index = second === null ? null :
this.b(second, { axis: 0 });
row_index = first === null ? null :
this.b(first, { axis: 1 });
}
}
}
else {
col_index = second === null ? null :
this.b(second, { axis: 0, ctx: third });
row_index = first === null ? null :
this.b(first, { axis: 1, ctx: third });
}
// switch(true){
// case _.isUndefined(second):
// row_index = this.b(first as string,{axis:1})
// break
// case first !== null && second === null:
// col_index = this.b(first as string,0)
// break
// case first === null:
// row_index = this.b(second as string,1)
// break
// default:
// row_index = this.b(second as string,1)
// col_index = this.b(first as string,0)
// }
return this.loc(row_index, col_index);
}
_iter(indexType, func) {
const accessor = (i) => indexType === 'index' ?
this.iloc(i) :
this.iloc(null, i);
if (_.isUndefined(func)) {
const self = this;
function* iter() {
let i = 0;
const itemFunc = indexType === 'index' ?
(row, k, i) => ({ row: row, key: k, i: i }) :
(row, k, i) => ({ col: row, key: k, i: i });
for (const k of self[indexType].values) {
const row = accessor(i);
yield [row, k, i];
i += 1;
}
}
return iter();
}
else
this[indexType].values.forEach((k, i) => {
const row = accessor(i);
func(row, k, i);
});
}
iterrows(func) {
if (_.isUndefined(func))
return this._iter('index');
else
return this._iter('index', func);
}
itercols(func) {
if (_.isUndefined(func))
return this._iter('columns');
else
return this._iter('columns', func);
}
// groupby():GroupByThen<T>
// groupby(labels:nsx|null):GroupByThen<T>
// groupby(labels:nsx|null,axis:0|1):GroupByThen<T>
groupby(labels, axis = 0) {
if (_.isUndefined(labels)) {
return this._groupby(null);
}
else
return this._groupby(labels, axis);
}
_groupby(labels, axis = 0) {
const index = axis === 0 ? this.columns : this.index;
const iter = axis === 0 ? this.iterrows : this.itercols;
const _index = axis === 0 ? this.index : this.columns;
const res = {};
if (_.isNull(labels)) {
iter.call(this, (ss, k, i) => {
const karr = [k];
const key = JSON.stringify(karr);
if (!(key in res))
res[key] = [];
res[key].push(i);
});
}
else {
labels = ((0, util_1.isArr)(labels) ? labels : [labels]);
iter.call(this, (ss, k, i) => {
const karr = ss.loc(labels).values;
const key = JSON.stringify(karr);
if (!(key in res))
res[key] = [];
res[key].push(i);
});
}
const then = new df_lib_1.GroupByThen(res, axis, this, labels, index);
return then;
}
// _sort_values(labels:nsx|null,ascending=true,axis:0|1=1){
// if(axis === 1){
// if(_.isNull(labels)){
// const idx = _sortIndices(this.index.values,
// ascending)
// return this.iloc(idx)
// }else{
// //TODO: any
// const sub = this.loc(null,labels as any) as DataFrame<T>
// const idx = _sortIndices(sub.values,
// ascending)
// return this.iloc(idx)
// }
// }else{
// if(_.isNull(labels)){
// const idx = _sortIndices(this.columns.values,
// ascending)
// return this.iloc(null,idx)
// }else{
// //TODO: any
// const sub = this.loc(labels as any) as DataFrame<T>
// const idx = _sortIndices(sub.tr,
// ascending)
// return this.iloc(null,idx)
// }
// }
// }
// sort_values(labels:nsx|null,ascending=true,axis:0|1=1){
sort_values(labels, { ascending = true, axis = 1 } = {}) {
const index = axis === 1 ? this.index : this.columns;
const iloc = axis === 1 ?
((idx) => this.iloc(idx)) :
((idx) => this.iloc(null, idx));
const loc = axis === 1 ?
((labels) => this.loc(null, labels)) :
((labels) => this.loc(labels));
const subFun = axis === 1 ?
((sub) => sub.values) :
((sub) => sub.tr);
if (_.isNull(labels)) {
const idx = (0, df_lib_1._sortIndices)(index.values, false, ascending);
return iloc(idx);
}
else {
const sub = loc(labels);
if (sub instanceof Series_1.default) {
const sub2 = sub;
const idx = (0, df_lib_1._sortIndices)(sub2.values, false, ascending);
return iloc(idx);
}
else {
const sub2 = sub;
const idx = (0, df_lib_1._sortIndices)(subFun(sub2), true, ascending);
return iloc(idx);
}
}
}
op(opStr, second) {
if (_.isUndefined(second)) {
let vals;
if (_.isString(opStr))
vals = this.values.map(vec => vec.map(x => eval(opStr)));
else
vals = this.values.map(vec => vec.map(x => opStr(x)));
return new DataFrame(vals, { index: this.index.cp(),
columns: this.columns.cp() });
}
else if (second instanceof DataFrame &&
this.index.is_unique() &&
second.index.is_unique()) {
util_1.check.op.index(this.index, second.index);
const vals = [];
this.index.values.forEach((idx) => {
const sx = this.loc(idx);
const sy = second.loc(idx);
const sz = sx.op(opStr, sy);
vals.push(sz.values);
});
return new DataFrame(vals, { index: this.index,
columns: this.columns });
}
else if (second instanceof DataFrame) {
util_1.check.op.index(this.index, second.index);
util_1.check.op.indexSame(this.index, second.index);
const vals = [];
this.index.values.forEach((e, idx) => {
const sx = this.iloc(idx);
const sy = second.iloc(idx);
const sz = sx.op(opStr, sy);
vals.push(sz.values);
});
return new DataFrame(vals, { index: this.index,
columns: this.columns });
}
else {
util_1.check.op.values(this.index, second);
util_1.check.op.values(this.columns, second[0]);
const vals = [];
this.values.forEach((vec, i) => {
const vec2 = second[i];
const vecNew = [];
vec.forEach((x, j) => {
const y = vec2[j];
vecNew.push(_.isString(opStr) ?
eval(opStr) : opStr(x, y));
});
vals.push(vecNew);
});
return new DataFrame(vals, { index: this.index,
columns: this.columns });
}
}
merge(df, { on = undefined, axis = 1 } = {}) {
let leftDf;
if (!_.isUndefined(on)) {
if (axis === 1) {
leftDf = this.set_index(on);
df = df.set_index(on);
}
else {
leftDf = this.set_columns(on);
df = df.set_columns(on);
}
}
else {
leftDf = this;
}
// console.log('aaa',leftDf,df)
const res = (0, util2_1.concat)([leftDf, df], axis);
// console.log('aaa',res)
if (_.isUndefined(on))
return res;
else {
if (axis === 1) {
res.index.name = on;
return res.reset_index();
}
else {
res.columns.name = on;
return res.reset_columns();
}
}
}
rank(options = {}) {
options = _.defaults(options, { axis: 0 });
if (options.axis === 0) {
const rankMat = this.tr.map(vec => ranks(vec, options));
const df = new DataFrame(rankMat, { index: this.columns.cp(),
columns: this.index.cp() });
df.transpose(true);
return df;
}
else {
const rankMat = this.values.map(vec => ranks(vec, options));
const df = new DataFrame(rankMat, { index: this.index.cp(),
columns: this.columns.cp() });
return df;
}
}
change(op_str, { periods = 1, axis = 0 } = {}) {
if (axis === 1) {
const diff = this.transpose().change(op_str, { periods: periods });
return diff.transpose(true);
}
if (!Number.isInteger(periods))
throw new Error('periods must be an integer');
if (periods >= 1) {
const later = this.iloc(`${periods}:`);
const earlier = this.iloc(`:-${periods}`);
const diff = later.op(op_str, earlier.values);
const head = new DataFrame((0, util2_1.full)([periods, this.shape[1]], NaN), { index: this.index.values.slice(0, periods),
columns: this.columns.cp() });
return (0, util2_1.concat)([head, diff], 0);
}
else if (periods <= -1) {
const earlier = this.iloc(`:${periods}`);
const later = this.iloc(`${-periods}:`);
const diff = earlier.op(op_str, later.values);
const tail = new DataFrame((0, util2_1.full)([-periods, this.shape[1]], NaN), { index: this.index.values.slice(this.shape[0] + periods),
columns: this.columns.cp() });
return (0, util2_1.concat)([diff, tail], 0);
}
else
return new DataFrame((0, util2_1.full)(this.shape, 0), { index: this.index.cp(), columns: this.columns.cp() });
}
diff({ periods = 1, axis = 0 } = {}) {
return this.change('x-y', { periods, axis });
}
pct_change({ periods = 1, axis = 0 } = {}) {
return this.change('(x-y)/y', { periods, axis });
}
rolling(window, { min_periods = undefined, center = false, closed = 'right', step = 1, axis = 0 } = {}) {
if (axis === 0)
return new df_lib_1.Rolling(this, window, min_periods, center, closed, step, axis);
else
return new df_lib_1.Rolling(this.transpose(), window, min_periods, center, closed, step, axis);
}
isna() {
return this.op('_.isNil(x) || _.isNaN(x)');
}
// drop_duplicates_by_index(){
// return drop_duplicates_by_index(this)
// }
to_raw(copy = true) {
// copy = _.isUndefined(copy) ? true : copy
if (copy)
return { values: (0, cmm_1.cp)(this.values),
index: this.index.to_raw(),
columns: this.index.to_raw()
};
else
return { values: this.values,
index: this.index.to_raw(copy),
columns: this.index.to_raw(copy)
};
}
reduce(func, axis = 0) {
if (axis === 1) {
const vals = this.values.map(row => func(row));
return new Series_1.default(vals, { index: this.index });
}
else {
const vals = this.tr.map(col => func(col));
return new Series_1.default(vals, { index: this.columns });
}
}
_reduce_num(func, axis) {
return this.reduce(func, axis);
}
min(axis = 0) {
return this._reduce_num(stat.min, axis);
}
max(axis = 0) {
return this._reduce_num(stat.max, axis);
}
sum(axis = 0) {
return this._reduce_num(stat.sum, axis);
}
mean(axis = 0) {
return this._reduce_num(stat.mean, axis);
}
median(axis = 0) {
return this._reduce_num(stat.median, axis);
}
std(axis = 0) {
return this._reduce_num(stat.sampleStandardDeviation, axis);
}
var(axis = 0) {
return this._reduce_num(stat.sampleVariance, axis);
}
mode(axis = 0) {
return this._reduce_num(stat.mode, axis);
}
prod(axis = 0) {
return this._reduce_num(stat.product, axis);
}
}
// const stat_methods = ['mean','sum','median',
// ['std','sampleStandardDeviation'],
// ['var','sampleVariance'],
// 'mode','min','max','prod'
// ]
// stat_methods.forEach(method=>{
// DataFrame.prototype
// // DataFrame<T>.prototype[method as string] = function(axis:0|1=0){
// // return this._reduce_num(stat[method],axis)
// // }
// })
exports.default = DataFrame;