Skip to content

Commit

Permalink
Merge pull request #414 from NeonSpork/diff-port
Browse files Browse the repository at this point in the history
feat: Added diff() function to DataFrame
  • Loading branch information
risenW authored Mar 9, 2022
2 parents 554ddd8 + 8d4c911 commit 746c4cc
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 4 deletions.
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
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

0 comments on commit 746c4cc

Please sign in to comment.