Skip to content

Commit 133515b

Browse files
authored
Merge pull request #359 from javascriptdata/feat/iat-at
Add new feature `iat` and `at`
2 parents 52ee69d + 93a9344 commit 133515b

File tree

7 files changed

+291
-65
lines changed

7 files changed

+291
-65
lines changed

src/danfojs-base/core/frame.ts

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,8 +1747,8 @@ export default class DataFrame extends NDframe implements DataFrameInterface {
17471747
options?: { inplace?: boolean, atIndex?: number | string }
17481748
): DataFrame | void {
17491749
let { inplace, atIndex } = { inplace: false, atIndex: this.columns.length, ...options };
1750-
if (typeof atIndex === "string" ) {
1751-
if (!(this.columns.includes(atIndex))){
1750+
if (typeof atIndex === "string") {
1751+
if (!(this.columns.includes(atIndex))) {
17521752
throw new Error(`${atIndex} not a column`)
17531753
}
17541754
atIndex = this.columns.indexOf(atIndex)
@@ -2762,7 +2762,7 @@ export default class DataFrame extends NDframe implements DataFrameInterface {
27622762
inplace?: boolean
27632763
}
27642764
): DataFrame
2765-
rename(
2765+
rename(
27662766
mapper: {
27672767
[index: string | number]: string | number
27682768
},
@@ -3332,4 +3332,47 @@ export default class DataFrame extends NDframe implements DataFrameInterface {
33323332
return toExcelNode(this, options as ExcelOutputOptionsNode)
33333333
}
33343334
}
3335+
3336+
/**
3337+
* Access a single value for a row/column pair by integer position.
3338+
* Similar to {@link iloc}, in that both provide integer-based lookups.
3339+
* Use iat if you only need to get or set a single value in a DataFrame.
3340+
* @param row Row index of the value to access.
3341+
* @param column Column index of the value to access.
3342+
* @example
3343+
* ```
3344+
* const df = new DataFrame([[1, 2], [3, 4]], { columns: ['A', 'B']})
3345+
* df.iat(0, 0) // 1
3346+
* df.iat(0, 1) // 2
3347+
* df.iat(1, 0) // 3
3348+
* ```
3349+
*/
3350+
iat(row: number, column: number): string | number | boolean | undefined {
3351+
if(typeof row === 'string' || typeof column === 'string') {
3352+
throw new Error('ParamError: row and column index must be an integer. Use .at to get a row or column by label.')
3353+
}
3354+
3355+
return (this.values as ArrayType2D)[row][column]
3356+
}
3357+
3358+
/**
3359+
* Access a single value for a row/column label pair.
3360+
* Similar to {@link loc}, in that both provide label-based lookups.
3361+
* Use at if you only need to get or set a single value in a DataFrame.
3362+
* @param row Row index of the value to access.
3363+
* @param column Column label of the value to access.
3364+
* @example
3365+
* ```
3366+
* const df = new DataFrame([[1, 2], [3, 4]], { columns: ['A', 'B']})
3367+
* df.at(0,'A') // 1
3368+
* df.at(1, 'A') // 3
3369+
* df.at(1, 'B') // 4
3370+
* ```
3371+
*/
3372+
at(row: string | number, column: string): string | number | boolean | undefined {
3373+
if(typeof column !== 'string') {
3374+
throw new Error('ParamError: column index must be a string. Use .iat to get a row or column by index.')
3375+
}
3376+
return (this.values as ArrayType2D)[this.index.indexOf(row)][this.columns.indexOf(column)]
3377+
}
33353378
}

src/danfojs-base/core/series.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2239,4 +2239,44 @@ export default class Series extends NDframe implements SeriesInterface {
22392239
return toExcelNode(this, options as ExcelOutputOptionsNode)
22402240
}
22412241
}
2242+
2243+
/**
2244+
* Access a single value for a row index.
2245+
* Similar to iloc, in that both provide index-based lookups.
2246+
* Use iat if you only need to get or set a single value in a Series.
2247+
* @param row Row index of the value to access.
2248+
* @example
2249+
* ```
2250+
* const sf = new Series([1, 2, 3, 4, 5])
2251+
* sf.iat(0) //returns 1
2252+
* sf.iat(1) //returns 2
2253+
* sf.iat(2) //returns 3
2254+
* ```
2255+
*/
2256+
iat(row: number): number | string | boolean | undefined {
2257+
if(typeof row === 'string') {
2258+
throw new Error('ParamError: row index must be an integer. Use .at to get a row by label.')
2259+
}
2260+
return (this.values as ArrayType1D)[row];
2261+
}
2262+
2263+
/**
2264+
* Access a single value for a row label.
2265+
* Similar to loc, in that both provide label-based lookups.
2266+
* Use at if you only need to get or set a single value in a Series.
2267+
* @param row Row label of the value to access.
2268+
* @example
2269+
* ```
2270+
* const sf = new Series([1, 2, 3, 4, 5, 6], { index: ['A', 'B', 'C', 'D', 'E', 'F'] })
2271+
* sf.at('A') //returns 1
2272+
* sf.at('B') //returns 2
2273+
* sf.at('C') //returns 3
2274+
* ```
2275+
*/
2276+
at(row: string): number | string | boolean | undefined {
2277+
if(typeof row !== 'string') {
2278+
throw new Error('ParamError: row index must be a string. Use .iat to get a row by index.')
2279+
}
2280+
return (this.values as ArrayType1D)[this.index.indexOf(row)];
2281+
}
22422282
}

src/danfojs-base/shared/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ export interface SeriesInterface extends NDframeInterface {
184184
toCSV(options?: CsvOutputOptionsBrowser): string | void
185185
toJSON(options?: JsonOutputOptionsBrowser): object | void
186186
toExcel(options?: ExcelOutputOptionsBrowser): void
187+
iat(index: number): number | string | boolean | undefined
188+
at(index: string | number): number | string | boolean | undefined
187189
}
188190

189191
//Start of DataFrame class types
@@ -327,6 +329,8 @@ export interface DataFrameInterface extends NDframeInterface {
327329
toCSV(options?: CsvOutputOptionsBrowser): string | void
328330
toJSON(options?: JsonOutputOptionsBrowser): object | void
329331
toExcel(options?: ExcelOutputOptionsBrowser): void
332+
iat(row: number, column: number): number | string | boolean | undefined
333+
at(row: string | number, column: string): number | string | boolean | undefined
330334
}
331335

332336
export interface DateTime {

src/danfojs-browser/tests/core/frame.test.js

Lines changed: 46 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2742,68 +2742,6 @@ describe("DataFrame", function () {
27422742
});
27432743
});
27442744

2745-
// describe("IO outputs", function () {
2746-
// it("toExcel works", async function () {
2747-
// const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
2748-
// const df = new dfd.DataFrame(data, { columns: ["a", "b", "c", "d"] });
2749-
2750-
// const filePath = path.join(process.cwd(), "test", "samples", "test.xlsx");
2751-
// df.toExcel({ filePath })
2752-
2753-
// const dfNew = await readExcel(filePath, {});
2754-
// assert.equal(fs.existsSync(filePath), true)
2755-
// assert.deepEqual(dfNew.columns, [
2756-
// 'a',
2757-
// 'b',
2758-
// 'c',
2759-
// 'd',
2760-
// ]);
2761-
// assert.deepEqual(dfNew.dtypes, [
2762-
// 'int32', 'int32',
2763-
// 'int32', 'int32',
2764-
// ]);
2765-
// assert.deepEqual(dfNew.shape, [3, 4])
2766-
// });
2767-
2768-
// it("toCSV works for specified seperator", async function () {
2769-
// const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
2770-
// let df = new dfd.DataFrame(data, { columns: ["a", "b", "c", "d"] });
2771-
// assert.deepEqual(df.toCSV({ sep: "+" }), `a+b+c+d\n1+2+3+4\n5+6+7+8\n9+10+11+12\n`);
2772-
// });
2773-
// it("toCSV write to local file works", async function () {
2774-
// const data = [[1, 2, 3, "4"], [5, 6, 7, "8"], [9, 10, 11, "12"]]
2775-
// let df = new dfd.DataFrame(data, { columns: ["a", "b", "c", "d"] });
2776-
2777-
// const filePath = path.join(process.cwd(), "test", "samples", "test_write.csv");
2778-
2779-
// df.toCSV({ sep: ",", filePath });
2780-
// assert.equal(fs.existsSync(filePath), true);
2781-
// });
2782-
// it("toJSON works for row format", async function () {
2783-
// const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
2784-
// const df = new dfd.DataFrame(data, { columns: ["a", "b", "c", "d"] });
2785-
// const expected = {
2786-
// "a": [1, 5, 9],
2787-
// "b": [2, 6, 10],
2788-
// "c": [3, 7, 11],
2789-
// "d": [4, 8, 12],
2790-
// }
2791-
// const json = df.toJSON({ format: "row" })
2792-
// assert.deepEqual(json, expected);
2793-
// });
2794-
// it("toJSON writes file to local path", async function () {
2795-
// const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
2796-
// const df = new dfd.DataFrame(data, { columns: ["a", "b", "c", "d"] });
2797-
2798-
// const rowfilePath = path.join(process.cwd(), "test", "samples", "test_row_write.json");
2799-
// const colfilePath = path.join(process.cwd(), "test", "samples", "test_col_write.json");
2800-
2801-
// df.toJSON({ format: "row", filePath: rowfilePath })
2802-
// df.toJSON({ format: "column", filePath: colfilePath })
2803-
// assert.equal(fs.existsSync(rowfilePath), true);
2804-
// assert.equal(fs.existsSync(colfilePath), true);
2805-
// });
2806-
// })
28072745

28082746
describe("getDummies", function () {
28092747
it("getDummies works on DataFrame", function () {
@@ -2902,5 +2840,51 @@ describe("DataFrame", function () {
29022840
});
29032841
});
29042842

2843+
describe("iat", function () {
2844+
it("iat works on DataFrame", function () {
2845+
const data = [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10, 11, 12 ] ];
2846+
const columns = [ "a", "b", "c", "d" ];
2847+
const df = new dfd.DataFrame(data, { columns });
2848+
assert.equal(df.iat(0, 0), 1);
2849+
assert.equal(df.iat(1, 1), 6);
2850+
assert.equal(df.iat(2, 3), 12);
2851+
});
2852+
it("throws error on string indices", function () {
2853+
const data = [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10, 11, 12 ] ];
2854+
const columns = [ "a", "b", "c", "d" ];
2855+
const index = [ "A", "B", "C" ];
2856+
const df = new dfd.DataFrame(data, { columns, index });
2857+
/* @ts-ignore */
2858+
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.");
2859+
/* @ts-ignore */
2860+
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.");
2861+
});
2862+
});
2863+
2864+
describe("at", function () {
2865+
it("at works on DataFrame", function () {
2866+
const data = [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10, 11, 12 ] ];
2867+
const columns = [ "a", "b", "c", "d" ];
2868+
const index = [ "A", "B", "C" ];
2869+
const df = new dfd.DataFrame(data, { columns, index });
2870+
assert.equal(df.at("A", "a"), 1);
2871+
assert.equal(df.at("B", "b"), 6);
2872+
assert.equal(df.at("C", "c"), 11);
2873+
2874+
});
2875+
it("throws error on numeric column index", function () {
2876+
const data = [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10, 11, 12 ] ];
2877+
const columns = [ "a", "b", "c", "d" ];
2878+
const index = [ 0, "B", "C" ];
2879+
const df = new dfd.DataFrame(data, { columns, index });
29052880

2881+
assert.equal(df.at(0, "b"), 2);
2882+
/* @ts-ignore */
2883+
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.");
2884+
/* @ts-ignore */
2885+
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.");
2886+
2887+
});
2888+
2889+
});
29062890
});

src/danfojs-browser/tests/core/series.test.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,4 +1583,58 @@ describe("Series Functions", () => {
15831583
});
15841584

15851585
});
1586+
1587+
describe("iat", function () {
1588+
it("iat works on Series", function () {
1589+
const data = [ 1, 2, 3, 4 ];
1590+
const index = [ "a", "b", "c", "d" ];
1591+
const df = new dfd.Series(data, { index });
1592+
assert.equal(df.iat(0), 1);
1593+
assert.equal(df.iat(1), 2);
1594+
assert.equal(df.iat(2), 3);
1595+
});
1596+
it("iat can return undefined", function () {
1597+
const data = [ 1, undefined, null, NaN ];
1598+
const df = new dfd.Series(data);
1599+
assert.equal(df.iat(1), undefined);
1600+
assert.equal(df.iat(2), null);
1601+
/* @ts-ignore */
1602+
assert.equal(isNaN(df.iat(3)), true);
1603+
});
1604+
it("throws error on string indices", function () {
1605+
const data = [ 1, 2, 3, 4 ];
1606+
const index = [ "a", "b", "c", "d" ];
1607+
const df = new dfd.Series(data, { index });
1608+
/* @ts-ignore */
1609+
assert.throws(function () { df.iat("A"); }, Error, "ParamError: row index must be an integer. Use .at to get a row by label.");
1610+
});
1611+
});
1612+
1613+
describe("at", function () {
1614+
it("at works on Series", function () {
1615+
const data = [ 1, 2, 3, 4 ];
1616+
const index = [ "a", "b", "c", "d" ];
1617+
const df = new dfd.Series(data, { index });
1618+
assert.equal(df.at("a"), 1);
1619+
assert.equal(df.at("b"), 2);
1620+
assert.equal(df.at("c"), 3);
1621+
});
1622+
it("at can return undefined", function () {
1623+
const data = [ 1, undefined, null, NaN ];
1624+
const index = [ "a", "b", "c", "d" ];
1625+
const df = new dfd.Series(data, { index });
1626+
assert.equal(df.at("b"), undefined);
1627+
assert.equal(df.at("c"), null);
1628+
/* @ts-ignore */
1629+
assert.equal(isNaN(df.at("d")), true);
1630+
});
1631+
it("throws error on string indices", function () {
1632+
const data = [ 1, 2, 3, 4 ];
1633+
const index = [ "a", "b", "c", "d" ];
1634+
const df = new dfd.Series(data, { index });
1635+
/* @ts-ignore */
1636+
assert.throws(function () { df.at(0); }, Error, "ParamError: row index must be a string. Use .iat to get a row by index.");
1637+
});
1638+
1639+
});
15861640
});

src/danfojs-node/test/core/frame.test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2905,5 +2905,52 @@ describe("DataFrame", function () {
29052905
});
29062906
});
29072907

2908+
describe("iat", function () {
2909+
it("iat works on DataFrame", function () {
2910+
const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];
2911+
const columns = ["a", "b", "c", "d"];
2912+
const df = new DataFrame(data, { columns });
2913+
assert.equal(df.iat(0, 0), 1);
2914+
assert.equal(df.iat(1, 1), 6);
2915+
assert.equal(df.iat(2, 3), 12);
2916+
});
2917+
it("throws error on string indices", function () {
2918+
const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];
2919+
const columns = ["a", "b", "c", "d"];
2920+
const index = ["A", "B", "C"];
2921+
const df = new DataFrame(data, { columns, index });
2922+
/* @ts-ignore */
2923+
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.");
2924+
/* @ts-ignore */
2925+
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.");
2926+
});
2927+
})
2928+
2929+
describe("at", function () {
2930+
it("at works on DataFrame", function () {
2931+
const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];
2932+
const columns = ["a", "b", "c", "d"];
2933+
const index = ["A", "B", "C"]
2934+
const df = new DataFrame(data, { columns, index });
2935+
assert.equal(df.at("A", "a"), 1);
2936+
assert.equal(df.at("B", "b"), 6);
2937+
assert.equal(df.at("C", "c"), 11);
2938+
2939+
});
2940+
it("throws error on numeric column index", function () {
2941+
const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];
2942+
const columns = ["a", "b", "c", "d"];
2943+
const index = [0, "B", "C"]
2944+
const df = new DataFrame(data, { columns, index });
2945+
2946+
assert.equal(df.at(0, "b"), 2);
2947+
/* @ts-ignore */
2948+
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.");
2949+
/* @ts-ignore */
2950+
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.");
2951+
2952+
});
2953+
2954+
});
29082955

29092956
});

0 commit comments

Comments
 (0)