def test_duplicate_multiindex_codes(): # GH 17464 # Make sure that a MultiIndex with duplicate levels throws a ValueError with pytest.raises(ValueError): mi = MultiIndex([["A"] * 10, range(10)], [[0] * 10, range(10)]) # And that using set_levels with duplicate levels fails mi = MultiIndex.from_arrays([["A", "A", "B", "B", "B"], [1, 2, 1, 2, 3]]) with pytest.raises(ValueError): mi.set_levels([["A", "B", "A", "A", "B"], [2, 1, 3, -2, 5]], inplace=True)
def test_duplicate_multiindex_codes(): # GH 17464 # Make sure that a MultiIndex with duplicate levels throws a ValueError with pytest.raises(ValueError): mi = MultiIndex([['A'] * 10, range(10)], [[0] * 10, range(10)]) # And that using set_levels with duplicate levels fails mi = MultiIndex.from_arrays([['A', 'A', 'B', 'B', 'B'], [1, 2, 1, 2, 3]]) with pytest.raises(ValueError): mi.set_levels([['A', 'B', 'A', 'A', 'B'], [2, 1, 3, -2, 5]], inplace=True)
def test_duplicate_multiindex_codes(): # GH 17464 # Make sure that a MultiIndex with duplicate levels throws a ValueError msg = r"Level values must be unique: \[[A', ]+\] on level 0" with pytest.raises(ValueError, match=msg): mi = MultiIndex([["A"] * 10, range(10)], [[0] * 10, range(10)]) # And that using set_levels with duplicate levels fails mi = MultiIndex.from_arrays([["A", "A", "B", "B", "B"], [1, 2, 1, 2, 3]]) msg = r"Level values must be unique: \[[AB', ]+\] on level 0" with pytest.raises(ValueError, match=msg): with tm.assert_produces_warning(FutureWarning): mi.set_levels([["A", "B", "A", "A", "B"], [2, 1, 3, -2, 5]], inplace=True)
def test_inplace_mutation_resets_values(): levels = [["a", "b", "c"], [4]] levels2 = [[1, 2, 3], ["a"]] codes = [[0, 1, 0, 2, 2, 0], [0, 0, 0, 0, 0, 0]] mi1 = MultiIndex(levels=levels, codes=codes) mi2 = MultiIndex(levels=levels2, codes=codes) vals = mi1.values.copy() vals2 = mi2.values.copy() assert mi1._tuples is not None # Make sure level setting works new_vals = mi1.set_levels(levels2).values tm.assert_almost_equal(vals2, new_vals) # Non-inplace doesn't kill _tuples [implementation detail] tm.assert_almost_equal(mi1._tuples, vals) # ...and values is still same too tm.assert_almost_equal(mi1.values, vals) # Inplace should kill _tuples mi1.set_levels(levels2, inplace=True) tm.assert_almost_equal(mi1.values, vals2) # Make sure label setting works too codes2 = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]] exp_values = np.empty((6,), dtype=object) exp_values[:] = [(1, "a")] * 6 # Must be 1d array of tuples assert exp_values.shape == (6,) new_values = mi2.set_codes(codes2).values # Not inplace shouldn't change tm.assert_almost_equal(mi2._tuples, vals2) # Should have correct values tm.assert_almost_equal(exp_values, new_values) # ...and again setting inplace should kill _tuples, etc mi2.set_codes(codes2, inplace=True) tm.assert_almost_equal(mi2.values, new_values)
def test_inplace_mutation_resets_values(): levels = [['a', 'b', 'c'], [4]] levels2 = [[1, 2, 3], ['a']] labels = [[0, 1, 0, 2, 2, 0], [0, 0, 0, 0, 0, 0]] mi1 = MultiIndex(levels=levels, labels=labels) mi2 = MultiIndex(levels=levels2, labels=labels) vals = mi1.values.copy() vals2 = mi2.values.copy() assert mi1._tuples is not None # Make sure level setting works new_vals = mi1.set_levels(levels2).values tm.assert_almost_equal(vals2, new_vals) # Non-inplace doesn't kill _tuples [implementation detail] tm.assert_almost_equal(mi1._tuples, vals) # ...and values is still same too tm.assert_almost_equal(mi1.values, vals) # Inplace should kill _tuples mi1.set_levels(levels2, inplace=True) tm.assert_almost_equal(mi1.values, vals2) # Make sure label setting works too labels2 = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]] exp_values = np.empty((6,), dtype=object) exp_values[:] = [(long(1), 'a')] * 6 # Must be 1d array of tuples assert exp_values.shape == (6,) new_values = mi2.set_labels(labels2).values # Not inplace shouldn't change tm.assert_almost_equal(mi2._tuples, vals2) # Should have correct values tm.assert_almost_equal(exp_values, new_values) # ...and again setting inplace should kill _tuples, etc mi2.set_labels(labels2, inplace=True) tm.assert_almost_equal(mi2.values, new_values)
def multiindex_apply_function( index: pd.MultiIndex, level: int, func: str, args: Iterable = None, kwargs: Mapping = None, ) -> pd.MultiIndex: args = args or [] kwargs = kwargs or {} new_index = index.set_levels( getattr(index.levels[level], func)(*args, **kwargs), level=level ) return new_index
def test_inplace_mutation_resets_values(): levels = [["a", "b", "c"], [4]] levels2 = [[1, 2, 3], ["a"]] codes = [[0, 1, 0, 2, 2, 0], [0, 0, 0, 0, 0, 0]] mi1 = MultiIndex(levels=levels, codes=codes) mi2 = MultiIndex(levels=levels2, codes=codes) # instantiating MultiIndex should not access/cache _.values assert "_values" not in mi1._cache assert "_values" not in mi2._cache vals = mi1.values.copy() vals2 = mi2.values.copy() # accessing .values should cache ._values assert mi1._values is mi1._cache["_values"] assert mi1.values is mi1._cache["_values"] assert isinstance(mi1._cache["_values"], np.ndarray) # Make sure level setting works new_vals = mi1.set_levels(levels2).values tm.assert_almost_equal(vals2, new_vals) # Non-inplace doesn't drop _values from _cache [implementation detail] tm.assert_almost_equal(mi1._cache["_values"], vals) # ...and values is still same too tm.assert_almost_equal(mi1.values, vals) # Inplace should drop _values from _cache with tm.assert_produces_warning(FutureWarning): mi1.set_levels(levels2, inplace=True) assert "_values" not in mi1._cache tm.assert_almost_equal(mi1.values, vals2) # Make sure label setting works too codes2 = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]] exp_values = np.empty((6,), dtype=object) exp_values[:] = [(1, "a")] * 6 # Must be 1d array of tuples assert exp_values.shape == (6,) new_mi = mi2.set_codes(codes2) assert "_values" not in new_mi._cache new_values = new_mi.values assert "_values" in new_mi._cache # Not inplace shouldn't change tm.assert_almost_equal(mi2._cache["_values"], vals2) # Should have correct values tm.assert_almost_equal(exp_values, new_values) # ...and again setting inplace should drop _values from _cache, etc with tm.assert_produces_warning(FutureWarning): mi2.set_codes(codes2, inplace=True) assert "_values" not in mi2._cache tm.assert_almost_equal(mi2.values, new_values) assert "_values" in mi2._cache