Skip to content

Commit 3dc29ac

Browse files
authored
Merge pull request #30 from static-frame/28/delimited-to-arrays
2 parents 0cd33b4 + f6cad26 commit 3dc29ac

14 files changed

Lines changed: 5457 additions & 159 deletions

doc/articles/dta.md

Lines changed: 357 additions & 0 deletions
Large diffs are not rendered by default.

performance/__main__.py

Lines changed: 249 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
import sys
2+
import os
3+
import io
14
from collections import namedtuple
25
import datetime
36
import timeit
47
import argparse
58
import typing as tp
6-
from enum import Enum
9+
10+
sys.path.append(os.getcwd())
711

812
import numpy as np
913

@@ -35,6 +39,7 @@
3539
from arraykit import resolve_dtype_iter as resolve_dtype_iter_ak
3640
from arraykit import dtype_from_element as dtype_from_element_ak
3741
from arraykit import array_deepcopy as array_deepcopy_ak
42+
from arraykit import delimited_to_arrays as delimited_to_arrays_ak
3843
from arraykit import isna_element as isna_element_ak
3944

4045
from arraykit import ArrayGO as ArrayGOAK
@@ -44,6 +49,236 @@ class Perf:
4449
FUNCTIONS = ('main',)
4550
NUMBER = 500_000
4651

52+
class FixtureFileLike:
53+
54+
COUNT_ROW = 100_000
55+
COUNT_COLUMN = 500
56+
NUMBER = 1
57+
58+
def __init__(self):
59+
records_int = [','.join(str(x) for x in range(self.COUNT_COLUMN))] * self.COUNT_ROW
60+
self.file_like_int = io.StringIO('\n'.join(records_int))
61+
62+
records_bool = [','.join(str(bool(x % 2)) for x in range(self.COUNT_COLUMN))] * self.COUNT_ROW
63+
self.file_like_bool = io.StringIO('\n'.join(records_bool))
64+
65+
records_str = [','.join('foobar' for x in range(self.COUNT_COLUMN))] * self.COUNT_ROW
66+
self.file_like_str = io.StringIO('\n'.join(records_str))
67+
68+
records_float = [','.join('1.2345' for x in range(self.COUNT_COLUMN))] * self.COUNT_ROW
69+
self.file_like_float = io.StringIO('\n'.join(records_float))
70+
71+
self.axis = 1
72+
73+
# #-------------------------------------------------------------------------------
74+
class DelimitedToArraysTypedPandas(FixtureFileLike, Perf):
75+
FUNCTIONS = ('bool_uniform', 'int_uniform', 'str_uniform', 'float_uniform')
76+
77+
class DelimitedToArraysTypedPandasAK(DelimitedToArraysTypedPandas):
78+
entry = staticmethod(delimited_to_arrays_ak)
79+
dtypes_int = ([int] * FixtureFileLike.COUNT_COLUMN).__getitem__
80+
dtypes_bool = ([bool] * FixtureFileLike.COUNT_COLUMN).__getitem__
81+
dtypes_str = ([str] * FixtureFileLike.COUNT_COLUMN).__getitem__
82+
dtypes_float = ([float] * FixtureFileLike.COUNT_COLUMN).__getitem__
83+
84+
def int_uniform(self):
85+
self.file_like_int.seek(0)
86+
_ = self.entry(self.file_like_int, dtypes=self.dtypes_int, axis=self.axis)
87+
88+
def bool_uniform(self):
89+
self.file_like_bool.seek(0)
90+
_ = self.entry(self.file_like_bool, dtypes=self.dtypes_bool, axis=self.axis)
91+
92+
def str_uniform(self):
93+
self.file_like_str.seek(0)
94+
_ = self.entry(self.file_like_str, dtypes=self.dtypes_str, axis=self.axis)
95+
96+
def float_uniform(self):
97+
self.file_like_float.seek(0)
98+
_ = self.entry(self.file_like_float, dtypes=self.dtypes_float, axis=self.axis)
99+
100+
101+
class DelimitedToArraysTypedPandasREF(DelimitedToArraysTypedPandas):
102+
import pandas
103+
entry = staticmethod(pandas.read_csv)
104+
dtypes_int = {i: int for i in range(FixtureFileLike.COUNT_COLUMN)}
105+
dtypes_bool = {i: bool for i in range(FixtureFileLike.COUNT_COLUMN)}
106+
dtypes_str = {i: object for i in range(FixtureFileLike.COUNT_COLUMN)}
107+
dtypes_float = {i: float for i in range(FixtureFileLike.COUNT_COLUMN)}
108+
109+
def int_uniform(self):
110+
self.file_like_int.seek(0)
111+
_ = self.entry(self.file_like_int, dtype=self.dtypes_int)
112+
113+
def bool_uniform(self):
114+
self.file_like_bool.seek(0)
115+
_ = self.entry(self.file_like_bool, dtype=self.dtypes_bool)
116+
117+
def str_uniform(self):
118+
self.file_like_str.seek(0)
119+
_ = self.entry(self.file_like_str, dtype=self.dtypes_str)
120+
121+
def float_uniform(self):
122+
self.file_like_float.seek(0)
123+
_ = self.entry(self.file_like_float, dtype=self.dtypes_float)
124+
125+
# #-------------------------------------------------------------------------------
126+
127+
class DelimitedToArraysParsedPandas(FixtureFileLike, Perf):
128+
FUNCTIONS = ('bool_uniform', 'int_uniform', 'str_uniform', 'float_uniform')
129+
130+
class DelimitedToArraysParsedPandasAK(DelimitedToArraysParsedPandas):
131+
entry = staticmethod(delimited_to_arrays_ak)
132+
133+
def int_uniform(self):
134+
self.file_like_int.seek(0)
135+
_ = self.entry(self.file_like_int, dtypes=None, axis=self.axis)
136+
137+
def bool_uniform(self):
138+
self.file_like_bool.seek(0)
139+
_ = self.entry(self.file_like_bool, dtypes=None, axis=self.axis)
140+
141+
def str_uniform(self):
142+
self.file_like_str.seek(0)
143+
_ = self.entry(self.file_like_str, dtypes=None, axis=self.axis)
144+
145+
def float_uniform(self):
146+
self.file_like_float.seek(0)
147+
_ = self.entry(self.file_like_float, dtypes=None, axis=self.axis)
148+
149+
150+
class DelimitedToArraysParsedPandasREF(DelimitedToArraysParsedPandas):
151+
import pandas
152+
entry = staticmethod(pandas.read_csv)
153+
154+
def int_uniform(self):
155+
self.file_like_int.seek(0)
156+
_ = self.entry(self.file_like_int)
157+
158+
def bool_uniform(self):
159+
self.file_like_bool.seek(0)
160+
_ = self.entry(self.file_like_bool)
161+
162+
def str_uniform(self):
163+
self.file_like_str.seek(0)
164+
_ = self.entry(self.file_like_str)
165+
166+
def float_uniform(self):
167+
self.file_like_float.seek(0)
168+
_ = self.entry(self.file_like_float)
169+
170+
171+
# #-------------------------------------------------------------------------------
172+
class DelimitedToArraysTypedGenft(FixtureFileLike, Perf):
173+
FUNCTIONS = ('bool_uniform', 'int_uniform', 'str_uniform', 'float_uniform')
174+
175+
class DelimitedToArraysTypedGenftAK(DelimitedToArraysTypedGenft):
176+
entry = staticmethod(delimited_to_arrays_ak)
177+
178+
dtypes_int = ([int] * FixtureFileLike.COUNT_COLUMN).__getitem__
179+
dtypes_bool = ([bool] * FixtureFileLike.COUNT_COLUMN).__getitem__
180+
dtypes_str = ([str] * FixtureFileLike.COUNT_COLUMN).__getitem__
181+
dtypes_float = ([float] * FixtureFileLike.COUNT_COLUMN).__getitem__
182+
axis = 1
183+
184+
def int_uniform(self):
185+
self.file_like_int.seek(0)
186+
_ = self.entry(self.file_like_int, dtypes=self.dtypes_int, axis=self.axis)
187+
188+
def bool_uniform(self):
189+
self.file_like_bool.seek(0)
190+
_ = self.entry(self.file_like_bool, dtypes=self.dtypes_bool, axis=self.axis)
191+
192+
def str_uniform(self):
193+
self.file_like_str.seek(0)
194+
_ = self.entry(self.file_like_str, dtypes=self.dtypes_str, axis=self.axis)
195+
196+
def float_uniform(self):
197+
self.file_like_float.seek(0)
198+
_ = self.entry(self.file_like_float, dtypes=self.dtypes_float, axis=self.axis)
199+
200+
201+
class DelimitedToArraysTypedGenftREF(DelimitedToArraysTypedGenft):
202+
entry = staticmethod(np.genfromtxt)
203+
204+
def int_uniform(self):
205+
self.file_like_int.seek(0)
206+
_ = self.entry(self.file_like_int, delimiter=',', dtype=int)
207+
208+
def bool_uniform(self):
209+
self.file_like_bool.seek(0)
210+
_ = self.entry(self.file_like_bool, delimiter=',', dtype=bool)
211+
212+
def str_uniform(self):
213+
self.file_like_str.seek(0)
214+
_ = self.entry(self.file_like_str, delimiter=',', dtype=str)
215+
216+
def float_uniform(self):
217+
self.file_like_float.seek(0)
218+
_ = self.entry(self.file_like_float, delimiter=',', dtype=float)
219+
220+
221+
# #-------------------------------------------------------------------------------
222+
# class DelimitedToArraysParsedGenft(FixtureFileLike, Perf):
223+
# NUMBER = 10
224+
# COUNT_ROW = 1_000
225+
226+
# def __init__(self):
227+
# records_int = [','.join(str(x) for x in range(1000))] * self.COUNT_ROW
228+
# self.file_like_int = io.StringIO('\n'.join(records_int))
229+
230+
# records_bool = [','.join(str(bool(x % 2)) for x in range(1000))] * self.COUNT_ROW
231+
# self.file_like_bool = io.StringIO('\n'.join(records_bool))
232+
233+
# records_str = [','.join('foobar' for x in range(1000))] * self.COUNT_ROW
234+
# self.file_like_str = io.StringIO('\n'.join(records_str))
235+
236+
# records_float = [','.join('1.2345' for x in range(1000))] * self.COUNT_ROW
237+
# self.file_like_float = io.StringIO('\n'.join(records_float))
238+
239+
# class DelimitedToArraysParsedGenftAK(DelimitedToArraysParsedGenft):
240+
# entry = staticmethod(delimited_to_arrays_ak)
241+
242+
# def __init__(self):
243+
# self.axis = 1
244+
245+
# def int_uniform(self):
246+
# self.file_like_int.seek(0)
247+
# _ = self.entry(self.file_like_int, dtypes=None, axis=self.axis)
248+
249+
# def bool_uniform(self):
250+
# self.file_like_bool.seek(0)
251+
# _ = self.entry(self.file_like_bool, dtypes=None, axis=self.axis)
252+
253+
# def str_uniform(self):
254+
# self.file_like_str.seek(0)
255+
# _ = self.entry(self.file_like_str, dtypes=None, axis=self.axis)
256+
257+
# def float_uniform(self):
258+
# self.file_like_float.seek(0)
259+
# _ = self.entry(self.file_like_float, dtypes=None, axis=self.axis)
260+
261+
262+
# class DelimitedToArraysParsedGenftREF(DelimitedToArraysParsedGenft):
263+
# entry = staticmethod(np.genfromtxt)
264+
265+
# def int_uniform(self):
266+
# self.file_like_int.seek(0)
267+
# _ = self.entry(self.file_like_int, delimiter=',', dtype=None)
268+
269+
# def bool_uniform(self):
270+
# self.file_like_bool.seek(0)
271+
# _ = self.entry(self.file_like_bool, delimiter=',', dtype=None)
272+
273+
# def str_uniform(self):
274+
# self.file_like_str.seek(0)
275+
# _ = self.entry(self.file_like_str, delimiter=',', dtype=None)
276+
277+
# def float_uniform(self):
278+
# self.file_like_float.seek(0)
279+
# _ = self.entry(self.file_like_float, delimiter=',', dtype=None)
280+
281+
47282
#-------------------------------------------------------------------------------
48283
class MLoc(Perf):
49284

@@ -186,7 +421,7 @@ class ResolveDTypeREF(ResolveDType):
186421
class ResolveDTypeIter(Perf):
187422

188423
FUNCTIONS = ('iter10', 'iter100000')
189-
NUMBER = 1000
424+
NUMBER = 500
190425

191426
def __init__(self):
192427
self.dtypes10 = [np.dtype(int)] * 9 + [np.dtype(float)]
@@ -238,7 +473,7 @@ class ArrayDeepcopyREF(ArrayDeepcopy):
238473

239474
#-------------------------------------------------------------------------------
240475
class ArrayGOPerf(Perf):
241-
NUMBER = 1000
476+
NUMBER = 500
242477

243478
def __init__(self):
244479
self.array = np.arange(100).astype(object)
@@ -472,7 +707,6 @@ def get_arg_parser():
472707
help='Provide one or more performance tests by name.')
473708
return p
474709

475-
476710
def main():
477711
options = get_arg_parser().parse_args()
478712
match = None if not options.names else set(options.names)
@@ -500,11 +734,17 @@ def main():
500734
number=cls_runner.NUMBER)
501735
records.append((cls_perf.__name__, func_attr, results['ak'], results['ref'], results['ref'] / results['ak']))
502736

503-
width = 32
504-
for record in records:
505-
print(''.join(
506-
(r.ljust(width) if isinstance(r, str) else str(round(r, 8)).ljust(width)) for r in record
507-
))
737+
import pandas as pd # NOTE: cannot make StaticFrame a dependency
738+
riter = iter(records)
739+
columns = next(riter)
740+
f = pd.DataFrame.from_records(riter, columns=columns)
741+
print(f)
742+
743+
# width = 32
744+
# for record in records:
745+
# print(''.join(
746+
# (r.ljust(width) if isinstance(r, str) else str(round(r, 8)).ljust(width)) for r in record
747+
# ))
508748

509749
if __name__ == '__main__':
510750
main()

pylintrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
persistent=no
33
jobs=8
44
unsafe-load-any-extension=y
5+
init-hook='import sys; sys.setrecursionlimit(20 * sys.getrecursionlimit())'
56

67
[MESSAGES CONTROL]
78

@@ -20,7 +21,7 @@ unsafe-load-any-extension=y
2021
#Missing class docstring C0115
2122
#Missing function or method docstring C0116
2223
#import-outside-toplevel C0415
23-
#Line too long C0301
24+
#Line too long C0301s
2425
#Trailing newlines C0305
2526
#Exactly one space required after comma C0326
2627
#Wrong hanging indentation C0330

requirements-backward.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
numpy==1.18.5
1+
numpy==1.19.5

requirements-test-backward.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
astroid==2.5.3
22
pytest==7.1.2
3-
numpy==1.18.5
3+
numpy==1.19.5
44
pylint==2.7.4
55
invoke==1.4.0
66
pandas==1.2.5

src/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@
1616
from ._arraykit import resolve_dtype_iter as resolve_dtype_iter
1717
from ._arraykit import isna_element as isna_element
1818
from ._arraykit import dtype_from_element as dtype_from_element
19+
from ._arraykit import delimited_to_arrays as delimited_to_arrays
20+
from ._arraykit import iterable_str_to_array_1d as iterable_str_to_array_1d
1921
from ._arraykit import get_new_indexers_and_screen as get_new_indexers_and_screen

src/__init__.pyi

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,32 @@ class ArrayGO:
2020
def copy(self: _T) -> _T: ...
2121
def extend(self, __values: tp.Iterable[object]) -> None: ...
2222

23+
def iterable_str_to_array_1d(
24+
iterable: tp.Iterable[str],
25+
*,
26+
dtype,
27+
thousandschar,
28+
decimalchar,
29+
): ...
30+
31+
def delimited_to_arrays(
32+
__file_like: tp.Iterable[str],
33+
*,
34+
dtypes: tp.Callable[[int], tp.Any],
35+
axis: int,
36+
skip_header: int,
37+
skip_footer: int,
38+
delimiter: str,
39+
doublequote: bool,
40+
escapechar: str,
41+
quotechar: str,
42+
quoting: int,
43+
skipinitialspace: bool,
44+
strict: bool,
45+
thousandschar: str,
46+
decimalchar: str,
47+
) -> tp.Iterable[np.array]: ...
48+
2349
def immutable_filter(__array: np.ndarray) -> np.ndarray: ...
2450
def mloc(__array: np.ndarray) -> int: ...
2551
def name_filter(__name: tp.Hashable) -> tp.Hashable: ...

0 commit comments

Comments
 (0)