Skip to content
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

feat: Added diff() function to DataFrame #414

Merged
merged 8 commits into from
Mar 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions src/danfojs-base/core/frame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1333,6 +1333,86 @@ export default class DataFrame extends NDframe implements DataFrameInterface {

}

/**
* Return difference of DataFrame with other.
* @param other DataFrame, Series, Array or Scalar number (positive numbers are preceding rows, negative are following rows) to compare difference with.
* @param options.axis 0 or 1. If 0, compute the difference column-wise, if 1, row-wise
* @param options.inplace Boolean indicating whether to perform the operation inplace or not. Defaults to false
* @example
* ```
* const df = new DataFrame([[1, 2, 3, 4, 5, 6], [1, 1, 2, 3, 5, 8], [1, 4, 9, 16, 25, 36]], { columns: ['A', 'B', 'C'] })
*
* // Difference with previous row
* const df0 = df.diff(1)
* console.log(df0)
*
* // Difference with previous column
* const df1 = df.diff(1, {axis: 0})
* console.log(df1)
*
* // Difference with previous 3rd previous row
* const df2 = df.diff(3)
* console.log(df2)
*
* // Difference with following row
* const df3 = df.diff(-1)
* console.log(df3)
*
* // Difference with another DataFrame
* const df4 = df.diff(df3)
* console.log(df4)
* ```
*/
diff(other: DataFrame | Series | number[] | number, options?: { axis?: 0 | 1, inplace?: boolean }): DataFrame
NeonSpork marked this conversation as resolved.
Show resolved Hide resolved
diff(other: DataFrame | Series | number[] | number, options?: { axis?: 0 | 1, inplace?: boolean }): DataFrame | void {
const { inplace, axis } = { inplace: false, axis: 1, ...options }

if (this.$frameIsNotCompactibleForArithmeticOperation()) {
throw Error("TypeError: diff operation is not supported for string dtypes");
}

if ([0, 1].indexOf(axis) === -1) {
throw Error("ParamError: Axis must be 0 or 1");
}

if (other === 0) {
return this;
}

if (typeof other === "number") {
let origDF = this.copy() as DataFrame;
if (axis === 0) {
origDF = origDF.T;
}
const originalTensor = origDF.tensor.clone();
const unit = new Array(originalTensor.shape[originalTensor.rank - 1]).fill(NaN);
let diffArray: any[] = originalTensor.arraySync();
if (other > 0) {
for (let i = 0; i < other; i++) {
diffArray.unshift(unit);
diffArray.pop();
}
}
else if (other < 0) {
for (let i = 0; i > other; i--) {
diffArray.push(unit);
diffArray.shift();
}
}
const diffTensor = tensorflow.tensor2d(diffArray, originalTensor.shape);
const diffDF = this.$MathOps([originalTensor, diffTensor], "sub", inplace) as DataFrame;
if (axis === 0) {
return diffDF.T;
}
return diffDF;
}

if (other instanceof DataFrame || other instanceof Series) {
const tensors = this.$getTensorsForArithmeticOperationByAxis(other, axis);
return this.$MathOps(tensors, "sub", inplace);
}
}

/**
* Return the absolute value of elements in a DataFrame.
* @param options.inplace Boolean indicating whether to perform the operation inplace or not. Defaults to false
Expand Down
9 changes: 5 additions & 4 deletions src/danfojs-base/shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ export interface SeriesInterface extends NDframeInterface {
toCSV(options?: CsvOutputOptionsBrowser): string | void
toJSON(options?: JsonOutputOptionsBrowser): object | void
toExcel(options?: ExcelOutputOptionsBrowser): void
iat(index: number): number | string | boolean | undefined
at(index: string | number): number | string | boolean | undefined
iat(index: number): number | string | boolean | undefined
at(index: string | number): number | string | boolean | undefined
}

//Start of DataFrame class types
Expand Down Expand Up @@ -218,6 +218,7 @@ export interface DataFrameInterface extends NDframeInterface {
div(other: DataFrame | Series | number | number[], options?: { axis?: 0 | 1, inplace?: boolean }): DataFrame | void
pow(other: DataFrame | Series | number | number[], options?: { axis?: 0 | 1, inplace?: boolean }): DataFrame | void
mod(other: DataFrame | Series | number | number[], options?: { axis?: 0 | 1, inplace?: boolean }): DataFrame | void
diff(other: DataFrame | Series | number[] | number, options?: { axis?: 0 | 1, inplace?: boolean }): DataFrame | void
mean(options?: { axis?: 0 | 1 }): Series
median(options?: { axis?: 0 | 1 }): Series
mode(options?: { axis?: 0 | 1, keep?: number }): Series
Expand Down Expand Up @@ -329,8 +330,8 @@ export interface DataFrameInterface extends NDframeInterface {
toCSV(options?: CsvOutputOptionsBrowser): string | void
toJSON(options?: JsonOutputOptionsBrowser): object | void
toExcel(options?: ExcelOutputOptionsBrowser): void
iat(row: number, column: number): number | string | boolean | undefined
at(row: string | number, column: string): number | string | boolean | undefined
iat(row: number, column: number): number | string | boolean | undefined
at(row: string | number, column: string): number | string | boolean | undefined
}

export interface DateTime {
Expand Down
45 changes: 45 additions & 0 deletions src/danfojs-browser/tests/core/frame.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,51 @@ describe("DataFrame", function () {

});

describe("diff", function () {
it("Return same DataFrame if other === 0", function () {
const data = [ [ 0, 2, 4 ], [ 10, 10, 10 ], [ 1, 2, 3 ] ];
const df = new dfd.DataFrame(data);
assert.deepEqual((df.diff(0)).values, [ [ 0, 2, 4 ], [ 10, 10, 10 ], [ 1, 2, 3 ] ]);
});
it("Return difference of DataFrame with previous row", function () {
const data = [ [ 0, 2, 4 ], [ 10, 10, 10 ], [ 1, 2, 3 ] ];
const df = new dfd.DataFrame(data);
assert.deepEqual((df.diff(1)).values, [ [ NaN, NaN, NaN ], [ 10, 8, 6 ], [ -9, -8, -7 ] ]);
});
it("Return difference of DataFrame with following row", function () {
const data = [ [ 0, 2, 4 ], [ 10, 10, 10 ], [ 1, 2, 3 ] ];
const df = new dfd.DataFrame(data);
assert.deepEqual((df.diff(-1)).values, [ [ -10, -8, -6 ], [ 9, 8, 7 ], [ NaN, NaN, NaN ] ]);
});
it("Return difference of a DataFrame with a Series along default axis 1", function () {
const data = [ [ 0, 2, 4 ], [ 10, 10, 10 ], [ 1, 2, 3 ] ];
const sf = new dfd.Series([ 1, 2, 1 ]);
const df = new dfd.DataFrame(data);
assert.deepEqual((df.diff(sf)).values, [ [ -1, 0, 3 ], [ 9, 8, 9 ], [ 0, 0, 2 ] ]);
});
it("Return difference of a DataFrame with along axis 0 (column-wise), previous column", function () {
const data = [ [ 0, 2, 4 ], [ 10, 10, 10 ], [ 1, 2, 3 ] ];
const df = new dfd.DataFrame(data);
assert.deepEqual((df.diff(1, { axis: 0 })).values, [ [ NaN, 2, 2 ], [ NaN, 0, 0 ], [ NaN, 1, 1 ] ]);
});
it("Return difference of a DataFrame with along axis 0 (column-wise), following column", function () {
const data = [ [ 0, 2, 4 ], [ 10, 10, 10 ], [ 1, 2, 3 ] ];
const df = new dfd.DataFrame(data);
assert.deepEqual((df.diff(-1, { axis: 0 })).values, [ [ -2, -2, NaN ], [ 0, 0, NaN ], [ -1, -1, NaN ] ]);
});
it("Return difference of a DataFrame with another DataFrame along default axis 1", function () {
const df1 = new dfd.DataFrame([ [ 0, 2, 4 ], [ 3, 10, 4 ] ]);
const df2 = new dfd.DataFrame([ [ -1, -2, 4 ], [ 10, 5, 0 ] ]);
assert.deepEqual((df1.diff(df2)).values, [ [ 1, 4, 0 ], [ -7, 5, 4 ] ]);
});
it("Throw error if DataFrame for diff contains string", function () {
const df = new dfd.DataFrame([ [ "words", "words", "words" ], [ "words", "words", "words" ] ]);
assert.throws(() => {
df.diff(1);
}, Error, "TypeError: diff operation is not supported for string dtypes");
});
});

describe("mean", function () {
it("Returns the mean of a DataFrame (Default axis is [1:column])", function () {
const data = [ [ 0, 2, 4 ],
Expand Down
45 changes: 45 additions & 0 deletions src/danfojs-node/test/core/frame.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -992,6 +992,51 @@ describe("DataFrame", function () {

});

describe("diff", function () {
it("Return same DataFrame if other === 0", function () {
const data = [[0, 2, 4], [10, 10, 10], [1, 2, 3]];
const df = new DataFrame(data);
assert.deepEqual((df.diff(0) as DataFrame).values, [[0, 2, 4], [10, 10, 10], [1, 2, 3]]);
});
it("Return difference of DataFrame with previous row", function () {
const data = [[0, 2, 4], [10, 10, 10], [1, 2, 3]];
const df = new DataFrame(data);
assert.deepEqual((df.diff(1) as DataFrame).values, [[NaN, NaN, NaN], [10, 8, 6], [-9, -8, -7]]);
});
it("Return difference of DataFrame with following row", function () {
const data = [[0, 2, 4], [10, 10, 10], [1, 2, 3]];
const df = new DataFrame(data);
assert.deepEqual((df.diff(-1) as DataFrame).values, [[-10, -8, -6], [9, 8, 7], [NaN, NaN, NaN]]);
});
it("Return difference of a DataFrame with a Series along default axis 1", function () {
const data = [[0, 2, 4], [10, 10, 10], [1, 2, 3]];
const sf = new Series([1, 2, 1]);
const df = new DataFrame(data);
assert.deepEqual((df.diff(sf) as DataFrame).values, [[-1, 0, 3], [9, 8, 9], [0, 0, 2]]);
});
it("Return difference of a DataFrame with along axis 0 (column-wise), previous column", function () {
const data = [[0, 2, 4], [10, 10, 10], [1, 2, 3]];
const df = new DataFrame(data);
assert.deepEqual((df.diff(1, { axis: 0 }) as DataFrame).values, [[NaN, 2, 2], [NaN, 0, 0], [NaN, 1, 1]]);
});
it("Return difference of a DataFrame with along axis 0 (column-wise), following column", function () {
const data = [[0, 2, 4], [10, 10, 10], [1, 2, 3]];
const df = new DataFrame(data);
assert.deepEqual((df.diff(-1, { axis: 0 }) as DataFrame).values, [[-2, -2, NaN], [0, 0, NaN], [-1, -1, NaN]]);
});
it("Return difference of a DataFrame with another DataFrame along default axis 1", function () {
const df1 = new DataFrame([[0, 2, 4], [3, 10, 4]]);
const df2 = new DataFrame([[-1, -2, 4], [10, 5, 0]]);
assert.deepEqual((df1.diff(df2) as DataFrame).values, [[1, 4, 0], [-7, 5, 4]]);
});
it("Throw error if DataFrame for diff contains string", function () {
const df = new DataFrame([["words", "words", "words"], ["words", "words", "words"]]);
assert.throws(() => {
df.diff(1);
}, Error, "TypeError: diff operation is not supported for string dtypes");
});
});

describe("mod", function () {
it("Return modulus of DataFrame with a single Number", function () {
const data = [[0, 2, 4], [360, 180, 360]];
Expand Down