|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | + |
| 3 | +import numpy as np |
| 4 | +import pandas as pd |
| 5 | +import pandas.util.testing as tm |
1 | 6 | import pytest
|
| 7 | +from pandas import Index, MultiIndex, date_range, period_range |
| 8 | +from pandas.compat import lrange |
2 | 9 |
|
3 | 10 |
|
4 | 11 | def test_shift(idx):
|
5 | 12 |
|
6 | 13 | # GH8083 test the base class for shift
|
7 | 14 | pytest.raises(NotImplementedError, idx.shift, 1)
|
8 | 15 | pytest.raises(NotImplementedError, idx.shift, 1, 2)
|
| 16 | + |
| 17 | + |
| 18 | +def test_bounds(idx): |
| 19 | + idx._bounds |
| 20 | + |
| 21 | + |
| 22 | +def test_groupby(idx): |
| 23 | + groups = idx.groupby(np.array([1, 1, 1, 2, 2, 2])) |
| 24 | + labels = idx.get_values().tolist() |
| 25 | + exp = {1: labels[:3], 2: labels[3:]} |
| 26 | + tm.assert_dict_equal(groups, exp) |
| 27 | + |
| 28 | + # GH5620 |
| 29 | + groups = idx.groupby(idx) |
| 30 | + exp = {key: [key] for key in idx} |
| 31 | + tm.assert_dict_equal(groups, exp) |
| 32 | + |
| 33 | + |
| 34 | +def test_truncate(): |
| 35 | + major_axis = Index(lrange(4)) |
| 36 | + minor_axis = Index(lrange(2)) |
| 37 | + |
| 38 | + major_labels = np.array([0, 0, 1, 2, 3, 3]) |
| 39 | + minor_labels = np.array([0, 1, 0, 1, 0, 1]) |
| 40 | + |
| 41 | + index = MultiIndex(levels=[major_axis, minor_axis], |
| 42 | + labels=[major_labels, minor_labels]) |
| 43 | + |
| 44 | + result = index.truncate(before=1) |
| 45 | + assert 'foo' not in result.levels[0] |
| 46 | + assert 1 in result.levels[0] |
| 47 | + |
| 48 | + result = index.truncate(after=1) |
| 49 | + assert 2 not in result.levels[0] |
| 50 | + assert 1 in result.levels[0] |
| 51 | + |
| 52 | + result = index.truncate(before=1, after=2) |
| 53 | + assert len(result.levels[0]) == 2 |
| 54 | + |
| 55 | + # after < before |
| 56 | + pytest.raises(ValueError, index.truncate, 3, 1) |
| 57 | + |
| 58 | + |
| 59 | +def test_where(): |
| 60 | + i = MultiIndex.from_tuples([('A', 1), ('A', 2)]) |
| 61 | + |
| 62 | + def f(): |
| 63 | + i.where(True) |
| 64 | + |
| 65 | + pytest.raises(NotImplementedError, f) |
| 66 | + |
| 67 | + |
| 68 | +def test_where_array_like(): |
| 69 | + i = MultiIndex.from_tuples([('A', 1), ('A', 2)]) |
| 70 | + klasses = [list, tuple, np.array, pd.Series] |
| 71 | + cond = [False, True] |
| 72 | + |
| 73 | + for klass in klasses: |
| 74 | + def f(): |
| 75 | + return i.where(klass(cond)) |
| 76 | + pytest.raises(NotImplementedError, f) |
| 77 | + |
| 78 | +# TODO: reshape |
| 79 | + |
| 80 | + |
| 81 | +def test_reorder_levels(idx): |
| 82 | + # this blows up |
| 83 | + tm.assert_raises_regex(IndexError, '^Too many levels', |
| 84 | + idx.reorder_levels, [2, 1, 0]) |
| 85 | + |
| 86 | + |
| 87 | +def test_numpy_repeat(): |
| 88 | + reps = 2 |
| 89 | + numbers = [1, 2, 3] |
| 90 | + names = np.array(['foo', 'bar']) |
| 91 | + |
| 92 | + m = MultiIndex.from_product([ |
| 93 | + numbers, names], names=names) |
| 94 | + expected = MultiIndex.from_product([ |
| 95 | + numbers, names.repeat(reps)], names=names) |
| 96 | + tm.assert_index_equal(np.repeat(m, reps), expected) |
| 97 | + |
| 98 | + msg = "the 'axis' parameter is not supported" |
| 99 | + tm.assert_raises_regex( |
| 100 | + ValueError, msg, np.repeat, m, reps, axis=1) |
| 101 | + |
| 102 | + |
| 103 | +def test_append_mixed_dtypes(): |
| 104 | + # GH 13660 |
| 105 | + dti = date_range('2011-01-01', freq='M', periods=3, ) |
| 106 | + dti_tz = date_range('2011-01-01', freq='M', periods=3, tz='US/Eastern') |
| 107 | + pi = period_range('2011-01', freq='M', periods=3) |
| 108 | + |
| 109 | + mi = MultiIndex.from_arrays([[1, 2, 3], |
| 110 | + [1.1, np.nan, 3.3], |
| 111 | + ['a', 'b', 'c'], |
| 112 | + dti, dti_tz, pi]) |
| 113 | + assert mi.nlevels == 6 |
| 114 | + |
| 115 | + res = mi.append(mi) |
| 116 | + exp = MultiIndex.from_arrays([[1, 2, 3, 1, 2, 3], |
| 117 | + [1.1, np.nan, 3.3, 1.1, np.nan, 3.3], |
| 118 | + ['a', 'b', 'c', 'a', 'b', 'c'], |
| 119 | + dti.append(dti), |
| 120 | + dti_tz.append(dti_tz), |
| 121 | + pi.append(pi)]) |
| 122 | + tm.assert_index_equal(res, exp) |
| 123 | + |
| 124 | + other = MultiIndex.from_arrays([['x', 'y', 'z'], ['x', 'y', 'z'], |
| 125 | + ['x', 'y', 'z'], ['x', 'y', 'z'], |
| 126 | + ['x', 'y', 'z'], ['x', 'y', 'z']]) |
| 127 | + |
| 128 | + res = mi.append(other) |
| 129 | + exp = MultiIndex.from_arrays([[1, 2, 3, 'x', 'y', 'z'], |
| 130 | + [1.1, np.nan, 3.3, 'x', 'y', 'z'], |
| 131 | + ['a', 'b', 'c', 'x', 'y', 'z'], |
| 132 | + dti.append(pd.Index(['x', 'y', 'z'])), |
| 133 | + dti_tz.append(pd.Index(['x', 'y', 'z'])), |
| 134 | + pi.append(pd.Index(['x', 'y', 'z']))]) |
| 135 | + tm.assert_index_equal(res, exp) |
| 136 | + |
| 137 | + |
| 138 | +def test_take(idx): |
| 139 | + indexer = [4, 3, 0, 2] |
| 140 | + result = idx.take(indexer) |
| 141 | + expected = idx[indexer] |
| 142 | + assert result.equals(expected) |
| 143 | + |
| 144 | + # TODO: Remove Commented Code |
| 145 | + # if not isinstance(idx, |
| 146 | + # (DatetimeIndex, PeriodIndex, TimedeltaIndex)): |
| 147 | + # GH 10791 |
| 148 | + with pytest.raises(AttributeError): |
| 149 | + idx.freq |
| 150 | + |
| 151 | + |
| 152 | +def test_take_invalid_kwargs(idx): |
| 153 | + idx = idx |
| 154 | + indices = [1, 2] |
| 155 | + |
| 156 | + msg = r"take\(\) got an unexpected keyword argument 'foo'" |
| 157 | + tm.assert_raises_regex(TypeError, msg, idx.take, |
| 158 | + indices, foo=2) |
| 159 | + |
| 160 | + msg = "the 'out' parameter is not supported" |
| 161 | + tm.assert_raises_regex(ValueError, msg, idx.take, |
| 162 | + indices, out=indices) |
| 163 | + |
| 164 | + msg = "the 'mode' parameter is not supported" |
| 165 | + tm.assert_raises_regex(ValueError, msg, idx.take, |
| 166 | + indices, mode='clip') |
| 167 | + |
| 168 | + |
| 169 | +def test_take_fill_value(): |
| 170 | + # GH 12631 |
| 171 | + vals = [['A', 'B'], |
| 172 | + [pd.Timestamp('2011-01-01'), pd.Timestamp('2011-01-02')]] |
| 173 | + idx = pd.MultiIndex.from_product(vals, names=['str', 'dt']) |
| 174 | + |
| 175 | + result = idx.take(np.array([1, 0, -1])) |
| 176 | + exp_vals = [('A', pd.Timestamp('2011-01-02')), |
| 177 | + ('A', pd.Timestamp('2011-01-01')), |
| 178 | + ('B', pd.Timestamp('2011-01-02'))] |
| 179 | + expected = pd.MultiIndex.from_tuples(exp_vals, names=['str', 'dt']) |
| 180 | + tm.assert_index_equal(result, expected) |
| 181 | + |
| 182 | + # fill_value |
| 183 | + result = idx.take(np.array([1, 0, -1]), fill_value=True) |
| 184 | + exp_vals = [('A', pd.Timestamp('2011-01-02')), |
| 185 | + ('A', pd.Timestamp('2011-01-01')), |
| 186 | + (np.nan, pd.NaT)] |
| 187 | + expected = pd.MultiIndex.from_tuples(exp_vals, names=['str', 'dt']) |
| 188 | + tm.assert_index_equal(result, expected) |
| 189 | + |
| 190 | + # allow_fill=False |
| 191 | + result = idx.take(np.array([1, 0, -1]), allow_fill=False, |
| 192 | + fill_value=True) |
| 193 | + exp_vals = [('A', pd.Timestamp('2011-01-02')), |
| 194 | + ('A', pd.Timestamp('2011-01-01')), |
| 195 | + ('B', pd.Timestamp('2011-01-02'))] |
| 196 | + expected = pd.MultiIndex.from_tuples(exp_vals, names=['str', 'dt']) |
| 197 | + tm.assert_index_equal(result, expected) |
| 198 | + |
| 199 | + msg = ('When allow_fill=True and fill_value is not None, ' |
| 200 | + 'all indices must be >= -1') |
| 201 | + with tm.assert_raises_regex(ValueError, msg): |
| 202 | + idx.take(np.array([1, 0, -2]), fill_value=True) |
| 203 | + with tm.assert_raises_regex(ValueError, msg): |
| 204 | + idx.take(np.array([1, 0, -5]), fill_value=True) |
| 205 | + |
| 206 | + with pytest.raises(IndexError): |
| 207 | + idx.take(np.array([1, -5])) |
| 208 | + |
| 209 | + |
| 210 | +def test_iter(idx): |
| 211 | + result = list(idx) |
| 212 | + expected = [('foo', 'one'), ('foo', 'two'), ('bar', 'one'), |
| 213 | + ('baz', 'two'), ('qux', 'one'), ('qux', 'two')] |
| 214 | + assert result == expected |
| 215 | + |
| 216 | + |
| 217 | +def test_sub(idx): |
| 218 | + |
| 219 | + first = idx |
| 220 | + |
| 221 | + # - now raises (previously was set op difference) |
| 222 | + with pytest.raises(TypeError): |
| 223 | + first - idx[-3:] |
| 224 | + with pytest.raises(TypeError): |
| 225 | + idx[-3:] - first |
| 226 | + with pytest.raises(TypeError): |
| 227 | + idx[-3:] - first.tolist() |
| 228 | + with pytest.raises(TypeError): |
| 229 | + first.tolist() - idx[-3:] |
| 230 | + |
| 231 | + |
| 232 | +def test_map(idx): |
| 233 | + # callable |
| 234 | + index = idx |
| 235 | + |
| 236 | + # we don't infer UInt64 |
| 237 | + if isinstance(index, pd.UInt64Index): |
| 238 | + expected = index.astype('int64') |
| 239 | + else: |
| 240 | + expected = index |
| 241 | + |
| 242 | + result = index.map(lambda x: x) |
| 243 | + tm.assert_index_equal(result, expected) |
| 244 | + |
| 245 | + |
| 246 | +@pytest.mark.parametrize( |
| 247 | + "mapper", |
| 248 | + [ |
| 249 | + lambda values, idx: {i: e for e, i in zip(values, idx)}, |
| 250 | + lambda values, idx: pd.Series(values, idx)]) |
| 251 | +def test_map_dictlike(idx, mapper): |
| 252 | + |
| 253 | + if isinstance(idx, (pd.CategoricalIndex, pd.IntervalIndex)): |
| 254 | + pytest.skip("skipping tests for {}".format(type(idx))) |
| 255 | + |
| 256 | + identity = mapper(idx.values, idx) |
| 257 | + |
| 258 | + # we don't infer to UInt64 for a dict |
| 259 | + if isinstance(idx, pd.UInt64Index) and isinstance(identity, dict): |
| 260 | + expected = idx.astype('int64') |
| 261 | + else: |
| 262 | + expected = idx |
| 263 | + |
| 264 | + result = idx.map(identity) |
| 265 | + tm.assert_index_equal(result, expected) |
| 266 | + |
| 267 | + # empty mappable |
| 268 | + expected = pd.Index([np.nan] * len(idx)) |
| 269 | + result = idx.map(mapper(expected, idx)) |
| 270 | + tm.assert_index_equal(result, expected) |
| 271 | + |
| 272 | + |
| 273 | +@pytest.mark.parametrize('func', [ |
| 274 | + np.exp, np.exp2, np.expm1, np.log, np.log2, np.log10, |
| 275 | + np.log1p, np.sqrt, np.sin, np.cos, np.tan, np.arcsin, |
| 276 | + np.arccos, np.arctan, np.sinh, np.cosh, np.tanh, |
| 277 | + np.arcsinh, np.arccosh, np.arctanh, np.deg2rad, |
| 278 | + np.rad2deg |
| 279 | +]) |
| 280 | +def test_numpy_ufuncs(func): |
| 281 | + # test ufuncs of numpy 1.9.2. see: |
| 282 | + # http://docs.scipy.org/doc/numpy/reference/ufuncs.html |
| 283 | + |
| 284 | + # some functions are skipped because it may return different result |
| 285 | + # for unicode input depending on numpy version |
| 286 | + |
| 287 | + # copy and paste from idx fixture as pytest doesn't support |
| 288 | + # parameters and fixtures at the same time. |
| 289 | + major_axis = Index(['foo', 'bar', 'baz', 'qux']) |
| 290 | + minor_axis = Index(['one', 'two']) |
| 291 | + major_labels = np.array([0, 0, 1, 2, 3, 3]) |
| 292 | + minor_labels = np.array([0, 1, 0, 1, 0, 1]) |
| 293 | + index_names = ['first', 'second'] |
| 294 | + |
| 295 | + idx = MultiIndex( |
| 296 | + levels=[major_axis, minor_axis], |
| 297 | + labels=[major_labels, minor_labels], |
| 298 | + names=index_names, |
| 299 | + verify_integrity=False |
| 300 | + ) |
| 301 | + |
| 302 | + with pytest.raises(Exception): |
| 303 | + with np.errstate(all='ignore'): |
| 304 | + func(idx) |
| 305 | + |
| 306 | + |
| 307 | +@pytest.mark.parametrize('func', [ |
| 308 | + np.isfinite, np.isinf, np.isnan, np.signbit |
| 309 | +]) |
| 310 | +def test_numpy_type_funcs(func): |
| 311 | + # for func in [np.isfinite, np.isinf, np.isnan, np.signbit]: |
| 312 | + # copy and paste from idx fixture as pytest doesn't support |
| 313 | + # parameters and fixtures at the same time. |
| 314 | + major_axis = Index(['foo', 'bar', 'baz', 'qux']) |
| 315 | + minor_axis = Index(['one', 'two']) |
| 316 | + major_labels = np.array([0, 0, 1, 2, 3, 3]) |
| 317 | + minor_labels = np.array([0, 1, 0, 1, 0, 1]) |
| 318 | + index_names = ['first', 'second'] |
| 319 | + |
| 320 | + idx = MultiIndex( |
| 321 | + levels=[major_axis, minor_axis], |
| 322 | + labels=[major_labels, minor_labels], |
| 323 | + names=index_names, |
| 324 | + verify_integrity=False |
| 325 | + ) |
| 326 | + |
| 327 | + with pytest.raises(Exception): |
| 328 | + func(idx) |
0 commit comments