diff --git a/src/danfojs-base/core/frame.ts b/src/danfojs-base/core/frame.ts index b9e575c4..827d70ac 100644 --- a/src/danfojs-base/core/frame.ts +++ b/src/danfojs-base/core/frame.ts @@ -1747,8 +1747,8 @@ export default class DataFrame extends NDframe implements DataFrameInterface { options?: { inplace?: boolean, atIndex?: number | string } ): DataFrame | void { let { inplace, atIndex } = { inplace: false, atIndex: this.columns.length, ...options }; - if (typeof atIndex === "string" ) { - if (!(this.columns.includes(atIndex))){ + if (typeof atIndex === "string") { + if (!(this.columns.includes(atIndex))) { throw new Error(`${atIndex} not a column`) } atIndex = this.columns.indexOf(atIndex) @@ -2762,7 +2762,7 @@ export default class DataFrame extends NDframe implements DataFrameInterface { inplace?: boolean } ): DataFrame - rename( + rename( mapper: { [index: string | number]: string | number }, @@ -3332,4 +3332,47 @@ export default class DataFrame extends NDframe implements DataFrameInterface { return toExcelNode(this, options as ExcelOutputOptionsNode) } } + + /** + * Access a single value for a row/column pair by integer position. + * Similar to {@link iloc}, in that both provide integer-based lookups. + * Use iat if you only need to get or set a single value in a DataFrame. + * @param row Row index of the value to access. + * @param column Column index of the value to access. + * @example + * ``` + * const df = new DataFrame([[1, 2], [3, 4]], { columns: ['A', 'B']}) + * df.iat(0, 0) // 1 + * df.iat(0, 1) // 2 + * df.iat(1, 0) // 3 + * ``` + */ + iat(row: number, column: number): string | number | boolean | undefined { + if(typeof row === 'string' || typeof column === 'string') { + throw new Error('ParamError: row and column index must be an integer. Use .at to get a row or column by label.') + } + + return (this.values as ArrayType2D)[row][column] + } + + /** + * Access a single value for a row/column label pair. + * Similar to {@link loc}, in that both provide label-based lookups. + * Use at if you only need to get or set a single value in a DataFrame. + * @param row Row index of the value to access. + * @param column Column label of the value to access. + * @example + * ``` + * const df = new DataFrame([[1, 2], [3, 4]], { columns: ['A', 'B']}) + * df.at(0,'A') // 1 + * df.at(1, 'A') // 3 + * df.at(1, 'B') // 4 + * ``` + */ + at(row: string | number, column: string): string | number | boolean | undefined { + if(typeof column !== 'string') { + throw new Error('ParamError: column index must be a string. Use .iat to get a row or column by index.') + } + return (this.values as ArrayType2D)[this.index.indexOf(row)][this.columns.indexOf(column)] + } } diff --git a/src/danfojs-base/core/series.ts b/src/danfojs-base/core/series.ts index 3b9659b0..a45f0547 100644 --- a/src/danfojs-base/core/series.ts +++ b/src/danfojs-base/core/series.ts @@ -2239,4 +2239,44 @@ export default class Series extends NDframe implements SeriesInterface { return toExcelNode(this, options as ExcelOutputOptionsNode) } } + + /** + * Access a single value for a row index. + * Similar to iloc, in that both provide index-based lookups. + * Use iat if you only need to get or set a single value in a Series. + * @param row Row index of the value to access. + * @example + * ``` + * const sf = new Series([1, 2, 3, 4, 5]) + * sf.iat(0) //returns 1 + * sf.iat(1) //returns 2 + * sf.iat(2) //returns 3 + * ``` + */ + iat(row: number): number | string | boolean | undefined { + if(typeof row === 'string') { + throw new Error('ParamError: row index must be an integer. Use .at to get a row by label.') + } + return (this.values as ArrayType1D)[row]; + } + + /** + * Access a single value for a row label. + * Similar to loc, in that both provide label-based lookups. + * Use at if you only need to get or set a single value in a Series. + * @param row Row label of the value to access. + * @example + * ``` + * const sf = new Series([1, 2, 3, 4, 5, 6], { index: ['A', 'B', 'C', 'D', 'E', 'F'] }) + * sf.at('A') //returns 1 + * sf.at('B') //returns 2 + * sf.at('C') //returns 3 + * ``` + */ + at(row: string): number | string | boolean | undefined { + if(typeof row !== 'string') { + throw new Error('ParamError: row index must be a string. Use .iat to get a row by index.') + } + return (this.values as ArrayType1D)[this.index.indexOf(row)]; + } } \ No newline at end of file diff --git a/src/danfojs-base/shared/types.ts b/src/danfojs-base/shared/types.ts index 60f30b55..7e1ca201 100644 --- a/src/danfojs-base/shared/types.ts +++ b/src/danfojs-base/shared/types.ts @@ -184,6 +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 } //Start of DataFrame class types @@ -327,6 +329,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 } export interface DateTime { diff --git a/src/danfojs-browser/tests/core/frame.test.js b/src/danfojs-browser/tests/core/frame.test.js index d564bebd..0b171c64 100644 --- a/src/danfojs-browser/tests/core/frame.test.js +++ b/src/danfojs-browser/tests/core/frame.test.js @@ -2742,68 +2742,6 @@ describe("DataFrame", function () { }); }); - // describe("IO outputs", function () { - // it("toExcel works", async function () { - // const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] - // const df = new dfd.DataFrame(data, { columns: ["a", "b", "c", "d"] }); - - // const filePath = path.join(process.cwd(), "test", "samples", "test.xlsx"); - // df.toExcel({ filePath }) - - // const dfNew = await readExcel(filePath, {}); - // assert.equal(fs.existsSync(filePath), true) - // assert.deepEqual(dfNew.columns, [ - // 'a', - // 'b', - // 'c', - // 'd', - // ]); - // assert.deepEqual(dfNew.dtypes, [ - // 'int32', 'int32', - // 'int32', 'int32', - // ]); - // assert.deepEqual(dfNew.shape, [3, 4]) - // }); - - // it("toCSV works for specified seperator", async function () { - // const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] - // let df = new dfd.DataFrame(data, { columns: ["a", "b", "c", "d"] }); - // assert.deepEqual(df.toCSV({ sep: "+" }), `a+b+c+d\n1+2+3+4\n5+6+7+8\n9+10+11+12\n`); - // }); - // it("toCSV write to local file works", async function () { - // const data = [[1, 2, 3, "4"], [5, 6, 7, "8"], [9, 10, 11, "12"]] - // let df = new dfd.DataFrame(data, { columns: ["a", "b", "c", "d"] }); - - // const filePath = path.join(process.cwd(), "test", "samples", "test_write.csv"); - - // df.toCSV({ sep: ",", filePath }); - // assert.equal(fs.existsSync(filePath), true); - // }); - // it("toJSON works for row format", async function () { - // const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] - // const df = new dfd.DataFrame(data, { columns: ["a", "b", "c", "d"] }); - // const expected = { - // "a": [1, 5, 9], - // "b": [2, 6, 10], - // "c": [3, 7, 11], - // "d": [4, 8, 12], - // } - // const json = df.toJSON({ format: "row" }) - // assert.deepEqual(json, expected); - // }); - // it("toJSON writes file to local path", async function () { - // const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] - // const df = new dfd.DataFrame(data, { columns: ["a", "b", "c", "d"] }); - - // const rowfilePath = path.join(process.cwd(), "test", "samples", "test_row_write.json"); - // const colfilePath = path.join(process.cwd(), "test", "samples", "test_col_write.json"); - - // df.toJSON({ format: "row", filePath: rowfilePath }) - // df.toJSON({ format: "column", filePath: colfilePath }) - // assert.equal(fs.existsSync(rowfilePath), true); - // assert.equal(fs.existsSync(colfilePath), true); - // }); - // }) describe("getDummies", function () { it("getDummies works on DataFrame", function () { @@ -2902,5 +2840,51 @@ describe("DataFrame", function () { }); }); + describe("iat", function () { + it("iat works on DataFrame", function () { + const data = [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10, 11, 12 ] ]; + const columns = [ "a", "b", "c", "d" ]; + const df = new dfd.DataFrame(data, { columns }); + assert.equal(df.iat(0, 0), 1); + assert.equal(df.iat(1, 1), 6); + assert.equal(df.iat(2, 3), 12); + }); + it("throws error on string indices", function () { + const data = [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10, 11, 12 ] ]; + const columns = [ "a", "b", "c", "d" ]; + const index = [ "A", "B", "C" ]; + const df = new dfd.DataFrame(data, { columns, index }); + /* @ts-ignore */ + assert.throws(function () { df.iat("A", 0); }, Error, "ParamError: row and column index must be an integer. Use .at to get a row or column by label."); + /* @ts-ignore */ + assert.throws(function () { df.iat(0, "A"); }, Error, "ParamError: row and column index must be an integer. Use .at to get a row or column by label."); + }); + }); + + describe("at", function () { + it("at works on DataFrame", function () { + const data = [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10, 11, 12 ] ]; + const columns = [ "a", "b", "c", "d" ]; + const index = [ "A", "B", "C" ]; + const df = new dfd.DataFrame(data, { columns, index }); + assert.equal(df.at("A", "a"), 1); + assert.equal(df.at("B", "b"), 6); + assert.equal(df.at("C", "c"), 11); + + }); + it("throws error on numeric column index", function () { + const data = [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10, 11, 12 ] ]; + const columns = [ "a", "b", "c", "d" ]; + const index = [ 0, "B", "C" ]; + const df = new dfd.DataFrame(data, { columns, index }); + assert.equal(df.at(0, "b"), 2); + /* @ts-ignore */ + assert.throws(function () { df.at(0, 1); }, Error, "ParamError: column index must be a string. Use .iat to get a row or column by index."); + /* @ts-ignore */ + assert.throws(function () { df.at("B", 0); }, Error, "ParamError: column index must be a string. Use .iat to get a row or column by index."); + + }); + + }); }); diff --git a/src/danfojs-browser/tests/core/series.test.js b/src/danfojs-browser/tests/core/series.test.js index 2a5f4680..43aec234 100644 --- a/src/danfojs-browser/tests/core/series.test.js +++ b/src/danfojs-browser/tests/core/series.test.js @@ -1583,4 +1583,58 @@ describe("Series Functions", () => { }); }); + + describe("iat", function () { + it("iat works on Series", function () { + const data = [ 1, 2, 3, 4 ]; + const index = [ "a", "b", "c", "d" ]; + const df = new dfd.Series(data, { index }); + assert.equal(df.iat(0), 1); + assert.equal(df.iat(1), 2); + assert.equal(df.iat(2), 3); + }); + it("iat can return undefined", function () { + const data = [ 1, undefined, null, NaN ]; + const df = new dfd.Series(data); + assert.equal(df.iat(1), undefined); + assert.equal(df.iat(2), null); + /* @ts-ignore */ + assert.equal(isNaN(df.iat(3)), true); + }); + it("throws error on string indices", function () { + const data = [ 1, 2, 3, 4 ]; + const index = [ "a", "b", "c", "d" ]; + const df = new dfd.Series(data, { index }); + /* @ts-ignore */ + assert.throws(function () { df.iat("A"); }, Error, "ParamError: row index must be an integer. Use .at to get a row by label."); + }); + }); + + describe("at", function () { + it("at works on Series", function () { + const data = [ 1, 2, 3, 4 ]; + const index = [ "a", "b", "c", "d" ]; + const df = new dfd.Series(data, { index }); + assert.equal(df.at("a"), 1); + assert.equal(df.at("b"), 2); + assert.equal(df.at("c"), 3); + }); + it("at can return undefined", function () { + const data = [ 1, undefined, null, NaN ]; + const index = [ "a", "b", "c", "d" ]; + const df = new dfd.Series(data, { index }); + assert.equal(df.at("b"), undefined); + assert.equal(df.at("c"), null); + /* @ts-ignore */ + assert.equal(isNaN(df.at("d")), true); + }); + it("throws error on string indices", function () { + const data = [ 1, 2, 3, 4 ]; + const index = [ "a", "b", "c", "d" ]; + const df = new dfd.Series(data, { index }); + /* @ts-ignore */ + assert.throws(function () { df.at(0); }, Error, "ParamError: row index must be a string. Use .iat to get a row by index."); + }); + + }); }); diff --git a/src/danfojs-node/test/core/frame.test.ts b/src/danfojs-node/test/core/frame.test.ts index a6bf5108..18960c94 100644 --- a/src/danfojs-node/test/core/frame.test.ts +++ b/src/danfojs-node/test/core/frame.test.ts @@ -2905,5 +2905,52 @@ describe("DataFrame", function () { }); }); + describe("iat", function () { + it("iat works on DataFrame", function () { + const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]; + const columns = ["a", "b", "c", "d"]; + const df = new DataFrame(data, { columns }); + assert.equal(df.iat(0, 0), 1); + assert.equal(df.iat(1, 1), 6); + assert.equal(df.iat(2, 3), 12); + }); + it("throws error on string indices", function () { + const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]; + const columns = ["a", "b", "c", "d"]; + const index = ["A", "B", "C"]; + const df = new DataFrame(data, { columns, index }); + /* @ts-ignore */ + assert.throws(function () { df.iat("A", 0); }, Error, "ParamError: row and column index must be an integer. Use .at to get a row or column by label."); + /* @ts-ignore */ + assert.throws(function () { df.iat(0, "A"); }, Error, "ParamError: row and column index must be an integer. Use .at to get a row or column by label."); + }); + }) + + describe("at", function () { + it("at works on DataFrame", function () { + const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]; + const columns = ["a", "b", "c", "d"]; + const index = ["A", "B", "C"] + const df = new DataFrame(data, { columns, index }); + assert.equal(df.at("A", "a"), 1); + assert.equal(df.at("B", "b"), 6); + assert.equal(df.at("C", "c"), 11); + + }); + it("throws error on numeric column index", function () { + const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]; + const columns = ["a", "b", "c", "d"]; + const index = [0, "B", "C"] + const df = new DataFrame(data, { columns, index }); + + assert.equal(df.at(0, "b"), 2); + /* @ts-ignore */ + assert.throws(function () { df.at(0, 1); }, Error, "ParamError: column index must be a string. Use .iat to get a row or column by index."); + /* @ts-ignore */ + assert.throws(function () { df.at("B", 0); }, Error, "ParamError: column index must be a string. Use .iat to get a row or column by index."); + + }); + + }); }); diff --git a/src/danfojs-node/test/core/series.test.ts b/src/danfojs-node/test/core/series.test.ts index 9ec573cc..a7e41ae5 100644 --- a/src/danfojs-node/test/core/series.test.ts +++ b/src/danfojs-node/test/core/series.test.ts @@ -1591,4 +1591,58 @@ describe("Series Functions", () => { assert.deepEqual(sf.and(data2).index, expected); }); }); + + describe("iat", function () { + it("iat works on Series", function () { + const data = [1, 2, 3, 4]; + const index = ["a", "b", "c", "d"]; + const df = new Series(data, { index }); + assert.equal(df.iat(0), 1); + assert.equal(df.iat(1), 2); + assert.equal(df.iat(2), 3); + }); + it("iat can return undefined", function () { + const data = [1, undefined, null, NaN]; + const df = new Series(data); + assert.equal(df.iat(1), undefined); + assert.equal(df.iat(2), null); + /* @ts-ignore */ + assert.equal(isNaN(df.iat(3)), true); + }); + it("throws error on string indices", function () { + const data = [1, 2, 3, 4]; + const index = ["a", "b", "c", "d"]; + const df = new Series(data, { index }); + /* @ts-ignore */ + assert.throws(function () { df.iat("A"); }, Error, "ParamError: row index must be an integer. Use .at to get a row by label."); + }); + }) + + describe("at", function () { + it("at works on Series", function () { + const data = [1, 2, 3, 4]; + const index = ["a", "b", "c", "d"]; + const df = new Series(data, { index }); + assert.equal(df.at("a"), 1); + assert.equal(df.at("b"), 2); + assert.equal(df.at("c"), 3); + }); + it("at can return undefined", function () { + const data = [1, undefined, null, NaN]; + const index = ["a", "b", "c", "d"]; + const df = new Series(data, { index }); + assert.equal(df.at("b"), undefined); + assert.equal(df.at("c"), null); + /* @ts-ignore */ + assert.equal(isNaN(df.at("d")), true); + }); + it("throws error on string indices", function () { + const data = [1, 2, 3, 4]; + const index = ["a", "b", "c", "d"]; + const df = new Series(data, { index }); + /* @ts-ignore */ + assert.throws(function () { df.at(0); }, Error, "ParamError: row index must be a string. Use .iat to get a row by index."); + }); + + }); }) \ No newline at end of file