Skip to content

Commit cd613bf

Browse files
committed
PERF: fastpath for iget from 2dim->1dim
1 parent 91a6958 commit cd613bf

File tree

3 files changed

+58
-24
lines changed

3 files changed

+58
-24
lines changed

pandas/core/common.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1802,9 +1802,11 @@ def _possibly_infer_to_datetimelike(value):
18021802
v = value
18031803
if not is_list_like(v):
18041804
v = [v]
1805-
v = np.array(v)
1805+
if not isinstance(v, np.ndarray):
1806+
v = np.array(v)
18061807
shape = v.shape
1807-
v = v.ravel()
1808+
if not v.ndim == 1:
1809+
v = v.ravel()
18081810

18091811
if len(v):
18101812

pandas/core/internals.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2521,7 +2521,7 @@ def _consolidate_inplace(self):
25212521
self._known_consolidated = True
25222522
self._rebuild_blknos_and_blklocs()
25232523

2524-
def get(self, item):
2524+
def get(self, item, fastpath=True):
25252525
"""
25262526
Return values for selected item (ndarray or BlockManager).
25272527
"""
@@ -2539,7 +2539,7 @@ def get(self, item):
25392539
else:
25402540
raise ValueError("cannot label index with a null key")
25412541

2542-
return self.iget(loc)
2542+
return self.iget(loc, fastpath=fastpath)
25432543
else:
25442544

25452545
if isnull(item):
@@ -2549,8 +2549,25 @@ def get(self, item):
25492549
return self.reindex_indexer(new_axis=self.items[indexer],
25502550
indexer=indexer, axis=0, allow_dups=True)
25512551

2552-
def iget(self, i):
2553-
return self.blocks[self._blknos[i]].iget(self._blklocs[i])
2552+
def iget(self, i, fastpath=True):
2553+
"""
2554+
Return the data as a SingleBlockManager if fastpath=True and possible
2555+
2556+
Otherwise return as a ndarray
2557+
2558+
"""
2559+
2560+
block = self.blocks[self._blknos[i]]
2561+
values = block.iget(self._blklocs[i])
2562+
if not fastpath or block.is_sparse or values.ndim != 1:
2563+
return values
2564+
2565+
# fastpath shortcut for select a single-dim from a 2-dim BM
2566+
return SingleBlockManager([ block.make_block_same_class(values,
2567+
placement=slice(0, len(values)),
2568+
fastpath=True) ],
2569+
self.axes[1])
2570+
25542571

25552572
def get_scalar(self, tup):
25562573
"""

pandas/tests/test_internals.py

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,9 @@ def test_get_scalar(self):
356356
for item in self.mgr.items:
357357
for i, index in enumerate(self.mgr.axes[1]):
358358
res = self.mgr.get_scalar((item, index))
359-
exp = self.mgr.get(item)[i]
359+
exp = self.mgr.get(item, fastpath=False)[i]
360+
assert_almost_equal(res, exp)
361+
exp = self.mgr.get(item).values[i]
360362
assert_almost_equal(res, exp)
361363

362364
def test_get(self):
@@ -366,19 +368,22 @@ def test_get(self):
366368
placement=np.arange(3))
367369
mgr = BlockManager(blocks=[block], axes=[cols, np.arange(3)])
368370

369-
assert_almost_equal(mgr.get('a'), values[0])
370-
assert_almost_equal(mgr.get('b'), values[1])
371-
assert_almost_equal(mgr.get('c'), values[2])
371+
assert_almost_equal(mgr.get('a', fastpath=False), values[0])
372+
assert_almost_equal(mgr.get('b', fastpath=False), values[1])
373+
assert_almost_equal(mgr.get('c', fastpath=False), values[2])
374+
assert_almost_equal(mgr.get('a').values, values[0])
375+
assert_almost_equal(mgr.get('b').values, values[1])
376+
assert_almost_equal(mgr.get('c').values, values[2])
372377

373378
def test_set(self):
374379
mgr = create_mgr('a,b,c: int', item_shape=(3,))
375380

376381
mgr.set('d', np.array(['foo'] * 3))
377382
mgr.set('b', np.array(['bar'] * 3))
378-
assert_almost_equal(mgr.get('a'), [0] * 3)
379-
assert_almost_equal(mgr.get('b'), ['bar'] * 3)
380-
assert_almost_equal(mgr.get('c'), [2] * 3)
381-
assert_almost_equal(mgr.get('d'), ['foo'] * 3)
383+
assert_almost_equal(mgr.get('a').values, [0] * 3)
384+
assert_almost_equal(mgr.get('b').values, ['bar'] * 3)
385+
assert_almost_equal(mgr.get('c').values, [2] * 3)
386+
assert_almost_equal(mgr.get('d').values, ['foo'] * 3)
382387

383388
def test_insert(self):
384389
self.mgr.insert(0, 'inserted', np.arange(N))
@@ -580,10 +585,14 @@ def test_reindex_items(self):
580585
reindexed = mgr.reindex_axis(['g', 'c', 'a', 'd'], axis=0)
581586
self.assertEqual(reindexed.nblocks, 2)
582587
assert_almost_equal(reindexed.items, ['g', 'c', 'a', 'd'])
583-
assert_almost_equal(mgr.get('g'), reindexed.get('g'))
584-
assert_almost_equal(mgr.get('c'), reindexed.get('c'))
585-
assert_almost_equal(mgr.get('a'), reindexed.get('a'))
586-
assert_almost_equal(mgr.get('d'), reindexed.get('d'))
588+
assert_almost_equal(mgr.get('g',fastpath=False), reindexed.get('g',fastpath=False))
589+
assert_almost_equal(mgr.get('c',fastpath=False), reindexed.get('c',fastpath=False))
590+
assert_almost_equal(mgr.get('a',fastpath=False), reindexed.get('a',fastpath=False))
591+
assert_almost_equal(mgr.get('d',fastpath=False), reindexed.get('d',fastpath=False))
592+
assert_almost_equal(mgr.get('g').values, reindexed.get('g').values)
593+
assert_almost_equal(mgr.get('c').values, reindexed.get('c').values)
594+
assert_almost_equal(mgr.get('a').values, reindexed.get('a').values)
595+
assert_almost_equal(mgr.get('d').values, reindexed.get('d').values)
587596

588597
def test_multiindex_xs(self):
589598
mgr = create_mgr('a,b,c: f8; d,e,f: i8')
@@ -608,16 +617,19 @@ def test_get_numeric_data(self):
608617

609618
numeric = mgr.get_numeric_data()
610619
assert_almost_equal(numeric.items, ['int', 'float', 'complex', 'bool'])
611-
assert_almost_equal(mgr.get('float'), numeric.get('float'))
620+
assert_almost_equal(mgr.get('float',fastpath=False), numeric.get('float',fastpath=False))
621+
assert_almost_equal(mgr.get('float').values, numeric.get('float').values)
612622

613623
# Check sharing
614624
numeric.set('float', np.array([100., 200., 300.]))
615-
assert_almost_equal(mgr.get('float'), np.array([100., 200., 300.]))
625+
assert_almost_equal(mgr.get('float',fastpath=False), np.array([100., 200., 300.]))
626+
assert_almost_equal(mgr.get('float').values, np.array([100., 200., 300.]))
616627

617628
numeric2 = mgr.get_numeric_data(copy=True)
618629
assert_almost_equal(numeric.items, ['int', 'float', 'complex', 'bool'])
619630
numeric2.set('float', np.array([1000., 2000., 3000.]))
620-
assert_almost_equal(mgr.get('float'), np.array([100., 200., 300.]))
631+
assert_almost_equal(mgr.get('float',fastpath=False), np.array([100., 200., 300.]))
632+
assert_almost_equal(mgr.get('float').values, np.array([100., 200., 300.]))
621633

622634
def test_get_bool_data(self):
623635
mgr = create_mgr('int: int; float: float; complex: complex;'
@@ -627,15 +639,18 @@ def test_get_bool_data(self):
627639

628640
bools = mgr.get_bool_data()
629641
assert_almost_equal(bools.items, ['bool'])
630-
assert_almost_equal(mgr.get('bool'), bools.get('bool'))
642+
assert_almost_equal(mgr.get('bool',fastpath=False), bools.get('bool',fastpath=False))
643+
assert_almost_equal(mgr.get('bool').values, bools.get('bool').values)
631644

632645
bools.set('bool', np.array([True, False, True]))
633-
assert_almost_equal(mgr.get('bool'), [True, False, True])
646+
assert_almost_equal(mgr.get('bool',fastpath=False), [True, False, True])
647+
assert_almost_equal(mgr.get('bool').values, [True, False, True])
634648

635649
# Check sharing
636650
bools2 = mgr.get_bool_data(copy=True)
637651
bools2.set('bool', np.array([False, True, False]))
638-
assert_almost_equal(mgr.get('bool'), [True, False, True])
652+
assert_almost_equal(mgr.get('bool',fastpath=False), [True, False, True])
653+
assert_almost_equal(mgr.get('bool').values, [True, False, True])
639654

640655
def test_unicode_repr_doesnt_raise(self):
641656
str_repr = repr(create_mgr(u('b,\u05d0: object')))

0 commit comments

Comments
 (0)