def test_index_level_leaf_loc_to_iloc_c(self) -> None: groups = Index(('A', 'B', 'C')) dates = IndexDate.from_date_range('2018-01-01', '2018-01-04') observations = Index(('x', 'y')) lvl2a = IndexLevel(index=observations) lvl2b = IndexLevel(index=observations, offset=2) lvl2c = IndexLevel(index=observations, offset=4) lvl2d = IndexLevel(index=observations, offset=6) lvl2_targets = ArrayGO((lvl2a, lvl2b, lvl2c, lvl2d)) lvl1a = IndexLevel(index=dates, targets=lvl2_targets, offset=0) lvl1b = IndexLevel(index=dates, targets=lvl2_targets, offset=len(lvl1a)) lvl1c = IndexLevel(index=dates, targets=lvl2_targets, offset=len(lvl1a) * 2) lvl0 = IndexLevel(index=groups, targets=ArrayGO((lvl1a, lvl1b, lvl1c))) with self.assertRaises(KeyError): lvl0.leaf_loc_to_iloc(('A')) self.assertEqual(lvl0.leaf_loc_to_iloc(('A', '2018-01-01', 'y')), 1)
def test_index_level_leaf_loc_to_iloc_a(self): groups = Index(('A', 'B', 'C')) dates = IndexDate.from_date_range('2018-01-01', '2018-01-04') observations = Index(('x', 'y')) lvl2a = IndexLevel(index=observations) lvl2b = IndexLevel(index=observations, offset=2) lvl2c = IndexLevel(index=observations, offset=4) lvl2d = IndexLevel(index=observations, offset=6) lvl2_targets = ArrayGO((lvl2a, lvl2b, lvl2c, lvl2d)) lvl1a = IndexLevel(index=dates, targets=lvl2_targets, offset=0) lvl1b = IndexLevel(index=dates, targets=lvl2_targets, offset=len(lvl1a)) lvl1c = IndexLevel(index=dates, targets=lvl2_targets, offset=len(lvl1a) * 2) # we need as many targets as len(index) lvl0 = IndexLevel(index=groups, targets=ArrayGO((lvl1a, lvl1b, lvl1c))) self.assertEqual(lvl0.leaf_loc_to_iloc(('B', '2018-01-04', 'y'),), 15) self.assertEqual(lvl0.leaf_loc_to_iloc(('A', '2018-01-01', 'y')), 1)
def test_index_level_a(self) -> None: groups = IndexGO(('A', 'B')) observations = IndexGO(('x', 'y')) targets = np.array( (IndexLevelGO(index=observations), IndexLevelGO(observations, offset=2))) level0 = IndexLevelGO(index=groups, targets=ArrayGO(targets)) level1 = level0.to_index_level() groups = IndexGO(('C', 'D')) observations = IndexGO(('x', 'y', 'z')) targets = np.array( (IndexLevelGO(index=observations), IndexLevelGO(observations, offset=3))) level2 = IndexLevelGO(index=groups, targets=ArrayGO(targets)) with self.assertRaises(RuntimeError): level0.extend(IndexLevelGO(index=observations)) level0.extend(level2) self.assertEqual(len(level0.values), 10) self.assertEqual(len(level1.values), 4) self.assertEqual(len(level2.values), 6) assert level0.targets is not None self.assertEqual([lvl.offset for lvl in level0.targets], [0, 2, 4, 7]) self.assertEqual(level2.depth, next(level2.depths()))
def test_index_level_a(self) -> None: groups = IndexGO(('A', 'B')) observations = IndexGO(('x', 'y')) targets = np.array((IndexLevelGO(index=observations), IndexLevelGO(observations, offset=2))) level0 = IndexLevelGO(index=groups, targets=ArrayGO(targets)) level1 = level0.to_index_level() groups = IndexGO(('C', 'D')) observations = IndexGO(('x', 'y', 'z')) targets = np.array((IndexLevelGO(index=observations), IndexLevelGO(observations, offset=3))) level2 = IndexLevelGO(index=groups, targets=ArrayGO(targets)) level0.extend(level2) self.assertEqual(len(level0.get_labels()), 10) self.assertEqual(len(level1.get_labels()), 4) self.assertEqual(len(level2.get_labels()), 6) assert level0.targets is not None # import ipdb; ipdb.set_trace() self.assertEqual([lvl.offset for lvl in level0.targets], [0, 2, 4, 7])
def test_index_level_append_a(self) -> None: category = IndexGO(('I', 'II')) groups = IndexGO(('A', 'B')) observations = IndexGO(('x', 'y')) lvl2a = IndexLevelGO(index=observations) lvl2b = IndexLevelGO(index=observations, offset=2) lvl2_targets = ArrayGO((lvl2a, lvl2b)) # must defensively copy index assert id(lvl2a.index) != id(lvl2b.index) lvl1a = IndexLevelGO(index=groups, targets=lvl2_targets, offset=0) # must create new index levels for each lower node lvl2c = IndexLevelGO(index=observations) lvl2d = IndexLevelGO(index=observations, offset=2) lvl2_targets = ArrayGO((lvl2c, lvl2d)) # must defensively copy index assert id(lvl2c.index) != id(lvl2d.index) lvl1b = IndexLevelGO(index=groups, targets=lvl2_targets, offset=len(lvl1a)) # we need as many targets as len(index) lvl0 = IndexLevelGO(index=category, targets=ArrayGO((lvl1a, lvl1b))) with self.assertRaises(RuntimeError): # RuntimeError: level for extension does not have necessary levels. lvl0.extend(lvl1b) lvl0.append(('II', 'B', 'z')) # depth not found is 2 self.assertEqual( [lvl0.loc_to_iloc(tuple(x)) for x in lvl0.values], list(range(9))) lvl0.append(('II', 'C', 'a')) # depth not found is 1 self.assertEqual( [lvl0.loc_to_iloc(tuple(x)) for x in lvl0.values], list(range(10))) lvl0.append(('III', 'A', 'a')) # 0 self.assertEqual( [lvl0.loc_to_iloc(tuple(x)) for x in lvl0.values], list(range(11))) self.assertEqual( lvl0.values.tolist(), [['I', 'A', 'x'], ['I', 'A', 'y'], ['I', 'B', 'x'], ['I', 'B', 'y'], ['II', 'A', 'x'], ['II', 'A', 'y'], ['II', 'B', 'x'], ['II', 'B', 'y'], ['II', 'B', 'z'], ['II', 'C', 'a'], ['III', 'A', 'a']])
def test_level_append_a(self): category = IndexGO(('I', 'II')) groups = IndexGO(('A', 'B')) observations = IndexGO(('x', 'y')) lvl2a = IndexLevelGO(index=observations) lvl2b = IndexLevelGO(index=observations, offset=2) lvl2_targets = ArrayGO((lvl2a, lvl2b)) # must defensively copy index assert id(lvl2a.index) != id(lvl2b.index) lvl1a = IndexLevelGO(index=groups, targets=lvl2_targets, offset=0) # must create new index levels for each lower node lvl2c = IndexLevelGO(index=observations) lvl2d = IndexLevelGO(index=observations, offset=2) lvl2_targets = ArrayGO((lvl2c, lvl2d)) # must defensively copy index assert id(lvl2c.index) != id(lvl2d.index) lvl1b = IndexLevelGO(index=groups, targets=lvl2_targets, offset=len(lvl1a)) # we need as many targets as len(index) lvl0 = IndexLevelGO(index=category, targets=ArrayGO((lvl1a, lvl1b))) lvl0.append(('II', 'B', 'z')) # depth not found is 2 self.assertEqual( [lvl0.loc_to_iloc(tuple(x)) for x in lvl0.get_labels()], list(range(9))) lvl0.append(('II', 'C', 'a')) # depth not found is 1 self.assertEqual( [lvl0.loc_to_iloc(tuple(x)) for x in lvl0.get_labels()], list(range(10))) lvl0.append(('III', 'A', 'a')) # 0 self.assertEqual( [lvl0.loc_to_iloc(tuple(x)) for x in lvl0.get_labels()], list(range(11))) self.assertEqual( lvl0.get_labels().tolist(), [['I', 'A', 'x'], ['I', 'A', 'y'], ['I', 'B', 'x'], ['I', 'B', 'y'], ['II', 'A', 'x'], ['II', 'A', 'y'], ['II', 'B', 'x'], ['II', 'B', 'y'], ['II', 'B', 'z'], ['II', 'C', 'a'], ['III', 'A', 'a']])
def test_index_level_extend_c(self) -> None: observations0 = IndexGO(('x', 'y')) targets0 = ArrayGO( (IndexLevelGO(index=observations0), IndexLevelGO(observations0, offset=2))) level0 = IndexLevelGO(index=IndexDateGO(('2021', '2022')), targets=targets0) observations1 = IndexGO(('x', 'y')) targets1 = ArrayGO( (IndexLevelGO(index=observations1), IndexLevelGO(observations1, offset=2))) level1 = IndexLevelGO(index=IndexYearMonthGO(('1853-03', '1873-12')), targets=targets1) # RuntimeError: level for extension does not have corresponding types: <class 'static_frame.core.index_datetime.IndexDateGO'>, <class 'static_frame.core.index_datetime.IndexYearMonthGO'> with self.assertRaises(RuntimeError): level0.extend(level1)
def test_array_getitem_a(self): a = np.array(('a', 'b', 'c', 'd'), object) a.flags.writeable = False ag1 = ArrayGO(a) # insure no copy for immutable self.assertEqual(mloc(ag1.values), mloc(a)) ag1.append('b') post = ag1[ag1.values == 'b'] self.assertEqual(post.tolist(), ['b', 'b']) self.assertEqual(ag1[[2, 1, 1, 1]].tolist(), ['c', 'b', 'b', 'b'])
def to_index_level( self, offset: tp.Optional[int] = 0, cls: tp.Optional[tp.Type['IndexLevel']] = None, ) -> 'IndexLevel': ''' A deepcopy with optional adjustments, such as a different offset and possibly a different class. The supplied class will be used to construct the IndexLevel instance (as well as internal indices), permitting the production of an IndexLevelGO. Args: offset: optionally provide a new offset for the copy. This is not applied recursively ''' cls = cls if cls else self.__class__ index = mutable_immutable_index_filter(cls.STATIC, self.index) if self.targets is not None: targets: tp.Optional[ArrayGO] = ArrayGO( [t.to_index_level(offset=None, cls=cls) for t in self.targets], own_iterable=True) else: targets = None offset = self.offset if offset is None else offset return cls( index=index, #type: ignore targets=targets, offset=offset, depth_reference=self.depth, )
def to_index_level( self, offset: tp.Optional[int] = 0, cls: tp.Type['IndexLevel'] = None, ) -> 'IndexLevel': ''' A deepcopy with optional adjustments, such as a different offset and possibly a different class. Args: offset: optionally provide a new offset for the copy. This is not applied recursively ''' index = self.index.copy() if self.targets is not None: # targets = np.empty(len(self.targets), dtype=object) # for idx, t in enumerate(self.targets): # # offset of None retains existing offset # targets[idx] = t.to_index_level(offset=None, cls=cls) targets = ArrayGO( [t.to_index_level(offset=None, cls=cls) for t in self.targets], own_iterable=True) else: targets = None offset = self.offset if offset is None else offset cls = cls if cls else self.__class__ return cls(index=index, targets=targets, offset=offset)
def _relabel_at_depth(self, mapper: RelabelInput, depth_level: tp.List[int]) -> 'IndexLevel': ''' Returns a new IndexLevel instance with relabeled indices at the specified `depth_level`s according to `mapper`, where `mapper` is a callable or a mapping. Note: There is a strong expectation that depth_level is sorted. ''' assert depth_level, "Invalid depth_levels should have already been sanitized" if len(depth_level) == 1: return self._relabel_at_single_depth(mapper, depth_level[0]) if depth_level[0] == 0: index = self.index.relabel(mapper) target_depths = [level - 1 for level in depth_level[1:]] own_index = True else: index = self.index target_depths = [level - 1 for level in depth_level] own_index = False new_targets = np.empty(len(self.targets), dtype=DTYPE_OBJECT) for i, target in enumerate(self.targets): new_targets[i] = target._relabel_at_depth(mapper, target_depths) return self.__class__(index=index, targets=ArrayGO(new_targets, own_iterable=True), offset=self.offset, own_index=own_index, depth_reference=self._depth)
def _relabel_at_single_depth(self, mapper: RelabelInput, depth_level: int) -> 'IndexLevel': ''' Returns a new IndexLevel instance with relabeled indices at the specified `depth_level` according to `mapper`. It will recursive through the internal index levels to apply a `relabel` to all the appropriate indices. ''' if depth_level == 0: return self.__class__(index=self.index.relabel(mapper), targets=self.targets, offset=self.offset, own_index=True, depth_reference=self._depth) # This will only happen if `relabel_at_depth` was not given a sorted # `depth_level` argument. assert self.targets is not None, f"Invalid depth_level={depth_level}" new_targets = np.empty(len(self.targets), dtype=DTYPE_OBJECT) for i, target in enumerate(self.targets): new_targets[i] = target._relabel_at_single_depth( mapper, depth_level - 1) return self.__class__(index=self.index, targets=ArrayGO(new_targets, own_iterable=True), offset=self.offset, own_index=False, depth_reference=self._depth)
def get_level(level_data, offset=0, depth=0): if isinstance(level_data, dict): level_labels = [] targets = np.empty(len(level_data), dtype=object) offset_local = 0 # ordered key, value pairs, where the key is the label, the value is a list or dictionary; enmerate for insertion pre-allocated object array for idx, (k, v) in enumerate(level_data.items()): level_labels.append(k) level = get_level(v, offset=offset_local, depth=depth + 1) targets[idx] = level offset_local += len(level) # for lower level offsetting index = get_index(level_labels, depth=depth) targets = ArrayGO(targets, own_iterable=True) else: # an iterable, terminal node, no offsets needed index = get_index(level_data, depth=depth) targets = None return cls._LEVEL_CONSTRUCTOR( index=index, offset=offset, targets=targets, )
def test_index_level_dtypes_a(self) -> None: groups = IndexGO(('A', 'B')) observations = IndexGO(('x', 'y')) targets = ArrayGO((IndexLevelGO(index=observations), IndexLevelGO(observations, offset=2))) level0 = IndexLevelGO(index=groups, targets=targets) self.assertEqual([d.kind for d in level0.dtypes()], ['U', 'U'])
def test_index_level_get_labels_a(self): groups = IndexGO(('A', 'B')) observations = IndexGO(('x', 'y')) targets = ArrayGO( (IndexLevelGO(index=observations), IndexLevelGO(observations, offset=2))) level0 = IndexLevelGO(index=groups, targets=targets) self.assertEqual(level0.get_labels().tolist(), [['A', 'x'], ['A', 'y'], ['B', 'x'], ['B', 'y']]) self.assertEqual(level0.get_labels().dtype.kind, 'U') groups = IndexGO((1, 2)) observations = IndexGO((10, 20)) targets = ArrayGO( (IndexLevelGO(index=observations), IndexLevelGO(observations, offset=2))) level1 = IndexLevelGO(index=groups, targets=targets) self.assertEqual(level1.get_labels().dtype.kind, 'i')
def append(self, key: tp.Sequence[tp.Hashable]) -> None: '''Add a single, full-depth leaf loc. ''' # find fist depth that does not contain key depth_count = next(self.depths()) if len(key) != depth_count: raise RuntimeError( 'appending key {} of insufficent depth {}'.format( key, depth_count)) depth_not_found = -1 edge_nodes = np.empty(depth_count, dtype=object) node = self for depth, k in enumerate(key): edge_nodes[depth] = node # only set on first encounter in descent if depth_not_found == -1 and not node.index.__contains__(k): depth_not_found = depth if node.targets is not None: node = node.targets[-1] assert depth_not_found != -1 level_previous = None for depth in range(depth_count - 1, depth_not_found - 1, -1): node = edge_nodes[depth] k = key[depth] # print('key', k, 'current edge index', node.index.values) if depth == depth_not_found: # when at the the depth not found, we always update the index node.index.append(k) # if we have targets, must update them if node.targets is not None: assert level_previous is not None level_previous.offset = node.__len__() node.targets.append(level_previous) else: # depth not found is higher up if node.targets is None: # we are at the max depth; will need to create a LevelGO to append in th next level level_previous = IndexLevelGO(index=IndexGO((k, )), offset=0, targets=None) else: # targets = np.empty(1, dtype=object) targets = ArrayGO([ level_previous, ], own_iterable=True) level_previous = IndexLevelGO(index=IndexGO((k, )), offset=0, targets=targets)
def test_array_deepcopy_a(self) -> None: ag1 = ArrayGO(np.array(('a', 'b', 'c', 'd'), dtype=object)) ag1.append('e') ag1.extend(('f', 'g')) ag2 = copy.deepcopy(ag1) self.assertEqual(ag1._array.tolist(), ag2._array.tolist()) #type: ignore
def from_product( cls: tp.Type[IH], *levels, name: tp.Hashable = None) -> IH: # tp.Iterable[tp.Hashable] ''' Given groups of iterables, return an ``IndexHierarchy`` made of the product of a values in those groups, where the first group is the top-most hierarchy. Returns: :py:class:`static_frame.IndexHierarchy` ''' indices = [] # store in a list, where index is depth for lvl in levels: if not isinstance(lvl, Index): # Index, not IndexBase lvl = cls._INDEX_CONSTRUCTOR(lvl) indices.append(lvl) if len(indices) == 1: raise RuntimeError('only one level given') # build name from index names, assuming they are all specified if name is None: name = tuple(index.name for index in indices) if any(n is None for n in name): name = None targets_previous = None # need to walk up from bottom to top # get depth pairs and iterate over those depth = len(indices) - 1 while depth > 0: index = indices[depth] index_up = indices[depth - 1] # for each label in the next-up index, we need a reference to this index with an offset of that index (or level) targets = np.empty(len(index_up), dtype=object) offset = 0 for idx, _ in enumerate(index_up): # this level does not have targets, only an index (as a leaf) level = cls._LEVEL_CONSTRUCTOR(index=index, offset=offset, targets=targets_previous) targets[idx] = level offset += len(level) targets_previous = ArrayGO(targets, own_iterable=True) depth -= 1 level = cls._LEVEL_CONSTRUCTOR(index=index_up, targets=targets_previous) return cls(level, name=name)
def add_level(self, level: tp.Hashable): '''Return an IndexHierarchy with a new root level added. ''' if self.STATIC: # can reuse levels levels_src = self._levels else: levels_src = self._levels.to_index_level() levels = self._LEVEL_CONSTRUCTOR(index=self._INDEX_CONSTRUCTOR( (level, )), targets=ArrayGO([levels_src], own_iterable=True), offset=0) return self.__class__(levels)
def test_array_copy_a(self): ag1 = ArrayGO(np.array(('a', 'b', 'c', 'd'), object)) ag1.append('e') ag2 = ag1.copy() ag1.extend(('f', 'g')) self.assertEqual(ag1.values.tolist(), ['a', 'b', 'c', 'd', 'e', 'f', 'g']) self.assertEqual(ag2.values.tolist(), ['a', 'b', 'c', 'd', 'e'])
def test_index_level_append_b(self) -> None: groups = IndexGO(('A', 'B')) observations = IndexGO(('x', 'y')) lvl2a = IndexLevelGO(index=observations) lvl2b = IndexLevelGO(index=observations, offset=2) lvl2_targets = ArrayGO((lvl2a, lvl2b)) lvl1a = IndexLevelGO(index=groups, targets=lvl2_targets, offset=0) with self.assertRaises(RuntimeError): lvl1a.append((1, 2, 3)) lvl1a.append((1, 2)) self.assertEqual( lvl1a.values.tolist(), [['A', 'x'], ['A', 'y'], ['B', 'x'], ['B', 'y'], [1, 2]])
def get_level(level_data, offset=0): if isinstance(level_data, dict): level_labels = [] targets = np.empty(len(level_data), dtype=object) offset_local = 0 for idx, (k, v) in enumerate(level_data.items()): level_labels.append(k) level = get_level(v, offset=offset_local) targets[idx] = level offset_local += len(level) index = cls._INDEX_CONSTRUCTOR(level_labels) targets = ArrayGO(targets, own_iterable=True) else: # an iterable, terminal node, no offsets needed targets = None index = cls._INDEX_CONSTRUCTOR(level_data) return cls._LEVEL_CONSTRUCTOR(index=index, offset=offset, targets=targets)
def test_index_level_deepcopy_a(self) -> None: groups = IndexGO(('A', 'B')) observations = IndexGO(('x', 'y')) lvl2a = IndexLevelGO(index=observations) lvl2b = IndexLevelGO(index=observations, offset=2) lvl2_targets = ArrayGO((lvl2a, lvl2b)) assert id(lvl2a.index) != id(lvl2b.index) lvl1a = IndexLevelGO(index=groups, targets=lvl2_targets, offset=0) post = copy.deepcopy(lvl1a) self.assertEqual(lvl1a.values.tolist(), post.values.tolist()) self.assertEqual( id(post.targets[0].index._labels), #type: ignore id(post.targets[1].index._labels)) #type: ignore
def test_array_append_a(self) -> None: ag1 = ArrayGO(('a', 'b', 'c', 'd')) self.assertEqual([x for x in ag1], ['a', 'b', 'c', 'd']) self.assertEqual(ag1.values.tolist(), ['a', 'b', 'c', 'd']) ag1.append('e') ag1.extend(('f', 'g')) self.assertEqual(ag1.values.tolist(), ['a', 'b', 'c', 'd', 'e', 'f', 'g']) self.assertEqual([x for x in ag1], ['a', 'b', 'c', 'd', 'e', 'f', 'g'])
def test_array_append_b(self): ag1 = ArrayGO(np.array(('a', 'b', 'c', 'd'), object)) self.assertEqual([x for x in ag1], ['a', 'b', 'c', 'd']) self.assertEqual(ag1.values.tolist(), ['a', 'b', 'c', 'd']) ag1.append('e') ag1.extend(('f', 'g')) self.assertEqual(ag1.values.tolist(), ['a', 'b', 'c', 'd', 'e', 'f', 'g']) self.assertEqual([x for x in ag1], ['a', 'b', 'c', 'd', 'e', 'f', 'g'])
def from_level_data( cls, level_data: tp.Any, get_index: tp.Callable[[IndexInitializer, int], IndexBase], offset: int = 0, depth: int = 0, ) -> 'IndexLevel': ''' Recursive function used in ``from_tree`` constructor. ''' if isinstance(level_data, dict): level_labels = [] targets = np.empty(len(level_data), dtype=object) offset_local = 0 # ordered key, value pairs, where the key is the label, the value is a list or dictionary; enmerate for insertion pre-allocated object array for idx, (k, v) in enumerate(level_data.items()): level_labels.append(k) level = cls.from_level_data(v, get_index, offset=offset_local, depth=depth + 1) targets[idx] = level offset_local += len(level) # for lower level offsetting index = get_index(level_labels, depth) targets = ArrayGO(targets, own_iterable=True) else: # an iterable, terminal node, no offsets needed index = get_index(level_data, depth) targets = None return cls( index=index, #type: ignore offset=offset, targets=targets, )
def from_index_items( cls: tp.Type[IH], items: tp.Iterable[tp.Tuple[tp.Hashable, Index]], *, index_constructor: tp.Optional[IndexConstructor] = None) -> IH: ''' Given an iterable of pairs of label, :obj:`Index`, produce an :obj:`IndexHierarchy` where the labels are depth 0, the indices are depth 1. Args: items: iterable of pairs of label, :obj:`Index`. index_constructor: Optionally provide index constructor for outermost index. ''' labels = [] index_levels = [] offset = 0 for label, index in items: labels.append(label) index = mutable_immutable_index_filter(cls.STATIC, index) index_levels.append( cls._LEVEL_CONSTRUCTOR(index, offset=offset, own_index=True)) offset += len(index) targets = ArrayGO(np.array(index_levels, dtype=object), own_iterable=True) index_outer = index_from_optional_constructor( labels, default_constructor=cls._INDEX_CONSTRUCTOR, explicit_constructor=index_constructor) return cls( cls._LEVEL_CONSTRUCTOR(index=index_outer, targets=targets, own_index=True))
def test_hierarchy_loc_to_iloc_a(self): groups = Index(('A', 'B', 'C')) dates = IndexDate.from_date_range('2018-01-01', '2018-01-04') observations = Index(('x', 'y')) lvl2a = IndexLevel(index=observations) lvl2b = IndexLevel(index=observations, offset=2) lvl2c = IndexLevel(index=observations, offset=4) lvl2d = IndexLevel(index=observations, offset=6) lvl2_targets = ArrayGO((lvl2a, lvl2b, lvl2c, lvl2d)) lvl1a = IndexLevel(index=dates, targets=lvl2_targets, offset=0) lvl1b = IndexLevel(index=dates, targets=lvl2_targets, offset=len(lvl1a)) lvl1c = IndexLevel(index=dates, targets=lvl2_targets, offset=len(lvl1a) * 2) # we need as many targets as len(index) lvl0 = IndexLevel(index=groups, targets=ArrayGO((lvl1a, lvl1b, lvl1c))) self.assertEqual(len(lvl2a), 2) self.assertEqual(len(lvl1a), 8) self.assertEqual(len(lvl0), 24) self.assertEqual(list(lvl2a.depths()), [1]) self.assertEqual(list(lvl1a.depths()), [2, 2, 2, 2]) self.assertEqual(list(lvl0.depths()), [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]) ih = IndexHierarchy(lvl0) self.assertEqual(len(ih), 24) post = ih.loc_to_iloc(HLoc[['A', 'B', 'C'], slice('2018-01-01', '2018-01-04'), ['x', 'y']]) # this will break if we recognize this can be a slice self.assertEqual(post, list(range(len(ih)))) post = ih.loc_to_iloc(HLoc[['A', 'B', 'C'], slice('2018-01-01', '2018-01-04'), 'x']) self.assertEqual(post, list(range(0, len(ih), 2))) post = ih.loc_to_iloc(HLoc['C', '2018-01-03', 'y']) self.assertEqual(post, 21) post = ih.loc_to_iloc(HLoc['B', '2018-01-03':, 'y']) self.assertEqual(post, [13, 15]) post = ih.loc_to_iloc(HLoc[['B', 'C'], '2018-01-03']) self.assertEqual(post, [12, 13, 20, 21]) post = ih.loc_to_iloc(HLoc[['A', 'C'], :, 'y']) self.assertEqual(post, [1, 3, 5, 7, 17, 19, 21, 23]) post = ih.loc_to_iloc(HLoc[['A', 'C'], :, 'x']) self.assertEqual(post, [0, 2, 4, 6, 16, 18, 20, 22])
def test_array_init_a(self) -> None: with self.assertRaises(NotImplementedError): _ = ArrayGO(np.array((3, 4, 5)))
def test_array_len_a(self): ag1 = ArrayGO(np.array(('a', 'b', 'c', 'd'), object)) ag1.append('e') self.assertEqual(len(ag1), 5)