node-pandas 1.0.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.kiro/agents/git-committer-agent.md +208 -0
- package/.kiro/agents/npm-publisher-agent.md +501 -0
- package/.kiro/publish-status-2.0.0.md +134 -0
- package/.kiro/published-versions.md +11 -0
- package/.kiro/specs/pandas-like-enhancements/.config.kiro +1 -0
- package/.kiro/specs/pandas-like-enhancements/design.md +377 -0
- package/.kiro/specs/pandas-like-enhancements/requirements.md +257 -0
- package/.kiro/specs/pandas-like-enhancements/tasks.md +477 -0
- package/CHANGELOG.md +42 -0
- package/README.md +375 -103
- package/TESTING_SETUP.md +183 -0
- package/jest.config.js +25 -0
- package/package.json +11 -3
- package/src/bases/CsvBase.js +4 -13
- package/src/dataframe/dataframe.js +596 -64
- package/src/features/GroupBy.js +561 -0
- package/src/features/dateRange.js +106 -0
- package/src/index.js +6 -1
- package/src/series/series.js +690 -14
- package/src/utils/errors.js +314 -0
- package/src/utils/getIndicesColumns.js +1 -1
- package/src/utils/getTransformedDataList.js +1 -1
- package/src/utils/logger.js +259 -0
- package/src/utils/typeDetection.js +339 -0
- package/src/utils/utils.js +5 -1
- package/src/utils/validation.js +450 -0
- package/tests/README.md +151 -0
- package/tests/integration/.gitkeep +0 -0
- package/tests/integration/README.md +3 -0
- package/tests/property/.gitkeep +0 -0
- package/tests/property/README.md +3 -0
- package/tests/setup.js +16 -0
- package/tests/test.js +58 -21
- package/tests/unit/.gitkeep +0 -0
- package/tests/unit/README.md +3 -0
- package/tests/unit/dataframe.test.js +1141 -0
- package/tests/unit/example.test.js +23 -0
- package/tests/unit/series.test.js +441 -0
- package/tests/unit/tocsv.test.js +838 -0
- package/tests/utils/testAssertions.js +143 -0
- package/tests/utils/testDataGenerator.js +123 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type Detection Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides comprehensive type detection and inference for data values,
|
|
5
|
+
* arrays, and DataFrame columns. Supports detection of numeric, string,
|
|
6
|
+
* boolean, date, and null types, with special handling for numeric strings.
|
|
7
|
+
*
|
|
8
|
+
* @module typeDetection
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Detects if a value is null or undefined
|
|
13
|
+
*
|
|
14
|
+
* @param {*} value - The value to check
|
|
15
|
+
* @returns {boolean} True if value is null or undefined
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* isNull(null) // true
|
|
19
|
+
* isNull(undefined) // true
|
|
20
|
+
* isNull(0) // false
|
|
21
|
+
* isNull('') // false
|
|
22
|
+
*/
|
|
23
|
+
function isNull(value) {
|
|
24
|
+
return value === null || value === undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Detects if a value is a boolean
|
|
29
|
+
*
|
|
30
|
+
* @param {*} value - The value to check
|
|
31
|
+
* @returns {boolean} True if value is a boolean
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* isBoolean(true) // true
|
|
35
|
+
* isBoolean(false) // true
|
|
36
|
+
* isBoolean(1) // false
|
|
37
|
+
* isBoolean('true') // false
|
|
38
|
+
*/
|
|
39
|
+
function isBoolean(value) {
|
|
40
|
+
return typeof value === 'boolean';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Detects if a value is a numeric string (can be parsed as a number)
|
|
45
|
+
*
|
|
46
|
+
* @param {*} value - The value to check
|
|
47
|
+
* @returns {boolean} True if value is a string that represents a number
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* isNumericString('123') // true
|
|
51
|
+
* isNumericString('123.45') // true
|
|
52
|
+
* isNumericString('-456') // true
|
|
53
|
+
* isNumericString('abc') // false
|
|
54
|
+
* isNumericString('') // false
|
|
55
|
+
*/
|
|
56
|
+
function isNumericString(value) {
|
|
57
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
return !isNaN(parseFloat(value)) && isFinite(value);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Detects if a value is a number (including numeric strings)
|
|
65
|
+
*
|
|
66
|
+
* @param {*} value - The value to check
|
|
67
|
+
* @returns {boolean} True if value is a number or numeric string
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* isNumeric(123) // true
|
|
71
|
+
* isNumeric(123.45) // true
|
|
72
|
+
* isNumeric('123') // true
|
|
73
|
+
* isNumeric('abc') // false
|
|
74
|
+
* isNumeric(null) // false
|
|
75
|
+
*/
|
|
76
|
+
function isNumeric(value) {
|
|
77
|
+
if (isNull(value)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
if (typeof value === 'number') {
|
|
81
|
+
return !isNaN(value) && isFinite(value);
|
|
82
|
+
}
|
|
83
|
+
return isNumericString(value);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Detects if a value is a string
|
|
88
|
+
*
|
|
89
|
+
* @param {*} value - The value to check
|
|
90
|
+
* @returns {boolean} True if value is a string
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* isString('hello') // true
|
|
94
|
+
* isString('') // true
|
|
95
|
+
* isString(123) // false
|
|
96
|
+
* isString(null) // false
|
|
97
|
+
*/
|
|
98
|
+
function isString(value) {
|
|
99
|
+
return typeof value === 'string';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Detects if a value is a Date object
|
|
104
|
+
*
|
|
105
|
+
* @param {*} value - The value to check
|
|
106
|
+
* @returns {boolean} True if value is a Date object
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* isDate(new Date()) // true
|
|
110
|
+
* isDate('2023-01-01') // false
|
|
111
|
+
* isDate(1234567890) // false
|
|
112
|
+
*/
|
|
113
|
+
function isDate(value) {
|
|
114
|
+
return value instanceof Date && !isNaN(value.getTime());
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Detects if a value is a date string (ISO 8601 format)
|
|
119
|
+
*
|
|
120
|
+
* @param {*} value - The value to check
|
|
121
|
+
* @returns {boolean} True if value is a string in ISO 8601 date format
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* isDateString('2023-01-01') // true
|
|
125
|
+
* isDateString('2023-01-01T12:00:00Z') // true
|
|
126
|
+
* isDateString('01/01/2023') // false
|
|
127
|
+
* isDateString('not a date') // false
|
|
128
|
+
*/
|
|
129
|
+
function isDateString(value) {
|
|
130
|
+
if (!isString(value)) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
// ISO 8601 date format: YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss[.sss]Z
|
|
134
|
+
const isoDateRegex = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?)?$/;
|
|
135
|
+
if (!isoDateRegex.test(value)) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
const date = new Date(value);
|
|
139
|
+
return !isNaN(date.getTime());
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Detects the type of a single value
|
|
144
|
+
*
|
|
145
|
+
* Returns one of: 'null', 'boolean', 'numeric', 'string', 'date', 'unknown'
|
|
146
|
+
*
|
|
147
|
+
* @param {*} value - The value to detect
|
|
148
|
+
* @returns {string} The detected type
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* detectType(null) // 'null'
|
|
152
|
+
* detectType(true) // 'boolean'
|
|
153
|
+
* detectType(123) // 'numeric'
|
|
154
|
+
* detectType('hello') // 'string'
|
|
155
|
+
* detectType(new Date()) // 'date'
|
|
156
|
+
* detectType({}) // 'unknown'
|
|
157
|
+
*/
|
|
158
|
+
function detectType(value) {
|
|
159
|
+
if (isNull(value)) {
|
|
160
|
+
return 'null';
|
|
161
|
+
}
|
|
162
|
+
if (isBoolean(value)) {
|
|
163
|
+
return 'boolean';
|
|
164
|
+
}
|
|
165
|
+
if (isDate(value)) {
|
|
166
|
+
return 'date';
|
|
167
|
+
}
|
|
168
|
+
if (isNumeric(value)) {
|
|
169
|
+
return 'numeric';
|
|
170
|
+
}
|
|
171
|
+
if (isString(value)) {
|
|
172
|
+
return 'string';
|
|
173
|
+
}
|
|
174
|
+
return 'unknown';
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Infers the dominant type of an array of values
|
|
179
|
+
*
|
|
180
|
+
* Analyzes all values in the array and returns the most common type.
|
|
181
|
+
* Null values are ignored in type inference.
|
|
182
|
+
*
|
|
183
|
+
* @param {Array} array - The array to analyze
|
|
184
|
+
* @returns {string} The inferred type: 'null', 'boolean', 'numeric', 'string', 'date', or 'mixed'
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* inferArrayType([1, 2, 3]) // 'numeric'
|
|
188
|
+
* inferArrayType(['a', 'b', 'c']) // 'string'
|
|
189
|
+
* inferArrayType([1, 'a', true]) // 'mixed'
|
|
190
|
+
* inferArrayType([null, null, null]) // 'null'
|
|
191
|
+
* inferArrayType([]) // 'null'
|
|
192
|
+
*/
|
|
193
|
+
function inferArrayType(array) {
|
|
194
|
+
if (!Array.isArray(array) || array.length === 0) {
|
|
195
|
+
return 'null';
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const typeCounts = {};
|
|
199
|
+
let nonNullCount = 0;
|
|
200
|
+
|
|
201
|
+
for (const value of array) {
|
|
202
|
+
const type = detectType(value);
|
|
203
|
+
if (type !== 'null') {
|
|
204
|
+
typeCounts[type] = (typeCounts[type] || 0) + 1;
|
|
205
|
+
nonNullCount++;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (nonNullCount === 0) {
|
|
210
|
+
return 'null';
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// If all non-null values are the same type, return that type
|
|
214
|
+
if (Object.keys(typeCounts).length === 1) {
|
|
215
|
+
return Object.keys(typeCounts)[0];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// If there are multiple types, return 'mixed'
|
|
219
|
+
return 'mixed';
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Infers the type of a DataFrame column
|
|
224
|
+
*
|
|
225
|
+
* Analyzes all values in a column and returns the inferred type.
|
|
226
|
+
* This is a convenience wrapper around inferArrayType.
|
|
227
|
+
*
|
|
228
|
+
* @param {Array} column - The column data (array of values)
|
|
229
|
+
* @returns {string} The inferred type
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* inferColumnType([1, 2, 3, null]) // 'numeric'
|
|
233
|
+
* inferColumnType(['a', 'b', null]) // 'string'
|
|
234
|
+
*/
|
|
235
|
+
function inferColumnType(column) {
|
|
236
|
+
return inferArrayType(column);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Infers types for all columns in a DataFrame
|
|
241
|
+
*
|
|
242
|
+
* @param {Array<Array>} data - 2D array where each inner array is a column
|
|
243
|
+
* @param {Array<string>} [columnNames] - Optional column names for reference
|
|
244
|
+
* @returns {Object} Object mapping column names/indices to inferred types
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* inferDataFrameTypes([[1, 2, 3], ['a', 'b', 'c']])
|
|
248
|
+
* // { '0': 'numeric', '1': 'string' }
|
|
249
|
+
*
|
|
250
|
+
* inferDataFrameTypes([[1, 2, 3], ['a', 'b', 'c']], ['id', 'name'])
|
|
251
|
+
* // { id: 'numeric', name: 'string' }
|
|
252
|
+
*/
|
|
253
|
+
function inferDataFrameTypes(data, columnNames = null) {
|
|
254
|
+
const types = {};
|
|
255
|
+
|
|
256
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
257
|
+
return types;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Handle row-based data (array of objects or arrays)
|
|
261
|
+
if (Array.isArray(data[0]) && !Array.isArray(data[0][0])) {
|
|
262
|
+
// Row-based format: [[row1], [row2], ...]
|
|
263
|
+
const numCols = data[0].length;
|
|
264
|
+
for (let colIndex = 0; colIndex < numCols; colIndex++) {
|
|
265
|
+
const column = data.map(row => row[colIndex]);
|
|
266
|
+
const colName = columnNames ? columnNames[colIndex] : String(colIndex);
|
|
267
|
+
types[colName] = inferColumnType(column);
|
|
268
|
+
}
|
|
269
|
+
} else if (Array.isArray(data[0])) {
|
|
270
|
+
// Column-based format: [[col1], [col2], ...]
|
|
271
|
+
for (let colIndex = 0; colIndex < data.length; colIndex++) {
|
|
272
|
+
const colName = columnNames ? columnNames[colIndex] : String(colIndex);
|
|
273
|
+
types[colName] = inferColumnType(data[colIndex]);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return types;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Converts a value to its numeric representation if possible
|
|
282
|
+
*
|
|
283
|
+
* @param {*} value - The value to convert
|
|
284
|
+
* @returns {number|null} The numeric value, or null if conversion fails
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* toNumeric(123) // 123
|
|
288
|
+
* toNumeric('456') // 456
|
|
289
|
+
* toNumeric('123.45') // 123.45
|
|
290
|
+
* toNumeric('abc') // null
|
|
291
|
+
* toNumeric(null) // null
|
|
292
|
+
*/
|
|
293
|
+
function toNumeric(value) {
|
|
294
|
+
if (isNull(value)) {
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
if (typeof value === 'number') {
|
|
298
|
+
return isNaN(value) ? null : value;
|
|
299
|
+
}
|
|
300
|
+
if (isNumericString(value)) {
|
|
301
|
+
return parseFloat(value);
|
|
302
|
+
}
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Converts a value to its string representation
|
|
308
|
+
*
|
|
309
|
+
* @param {*} value - The value to convert
|
|
310
|
+
* @returns {string|null} The string value, or null if value is null/undefined
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* toString(123) // '123'
|
|
314
|
+
* toString('hello') // 'hello'
|
|
315
|
+
* toString(true) // 'true'
|
|
316
|
+
* toString(null) // null
|
|
317
|
+
*/
|
|
318
|
+
function toString(value) {
|
|
319
|
+
if (isNull(value)) {
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
return String(value);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
module.exports = {
|
|
326
|
+
isNull,
|
|
327
|
+
isBoolean,
|
|
328
|
+
isNumericString,
|
|
329
|
+
isNumeric,
|
|
330
|
+
isString,
|
|
331
|
+
isDate,
|
|
332
|
+
isDateString,
|
|
333
|
+
detectType,
|
|
334
|
+
inferArrayType,
|
|
335
|
+
inferColumnType,
|
|
336
|
+
inferDataFrameTypes,
|
|
337
|
+
toNumeric,
|
|
338
|
+
toString
|
|
339
|
+
};
|
package/src/utils/utils.js
CHANGED
|
@@ -2,12 +2,16 @@ const dataType = require('./dataType') // require('dataType') => Error: Cannot f
|
|
|
2
2
|
const getTransformedDataList = require('./getTransformedDataList')
|
|
3
3
|
const getIndicesColumns = require('./getIndicesColumns')
|
|
4
4
|
const excludingColumns = require("./excludingColumns")
|
|
5
|
+
const typeDetection = require('./typeDetection')
|
|
6
|
+
const validation = require('./validation')
|
|
5
7
|
// const readCsv = require('./readCsv')
|
|
6
8
|
|
|
7
9
|
module.exports = {
|
|
8
10
|
dataType,
|
|
9
11
|
getTransformedDataList,
|
|
10
12
|
getIndicesColumns,
|
|
11
|
-
excludingColumns
|
|
13
|
+
excludingColumns,
|
|
14
|
+
typeDetection,
|
|
15
|
+
validation
|
|
12
16
|
// readCsv
|
|
13
17
|
}
|