|
3 | 3 | # behave identically.
|
4 | 4 | # Specifically for numeric dtypes
|
5 | 5 | from decimal import Decimal
|
| 6 | +from itertools import combinations |
6 | 7 | import operator
|
7 | 8 |
|
8 | 9 | import pytest
|
@@ -846,11 +847,15 @@ def check(series, other):
|
846 | 847 | class TestUFuncCompat(object):
|
847 | 848 |
|
848 | 849 | @pytest.mark.parametrize('holder', [pd.Int64Index, pd.UInt64Index,
|
849 |
| - pd.Float64Index, pd.Series]) |
| 850 | + pd.Float64Index, pd.RangeIndex, |
| 851 | + pd.Series]) |
850 | 852 | def test_ufunc_compat(self, holder):
|
851 | 853 | box = pd.Series if holder is pd.Series else pd.Index
|
852 | 854 |
|
853 |
| - idx = holder(np.arange(5, dtype='int64')) |
| 855 | + if holder is pd.RangeIndex: |
| 856 | + idx = pd.RangeIndex(0, 5) |
| 857 | + else: |
| 858 | + idx = holder(np.arange(5, dtype='int64')) |
854 | 859 | result = np.sin(idx)
|
855 | 860 | expected = box(np.sin(np.arange(5, dtype='int64')))
|
856 | 861 | tm.assert_equal(result, expected)
|
@@ -940,3 +945,117 @@ def test_operators_reverse_object(self, op):
|
940 | 945 | result = op(1., arr)
|
941 | 946 | expected = op(1., arr.astype(float))
|
942 | 947 | tm.assert_series_equal(result.astype(float), expected)
|
| 948 | + |
| 949 | + |
| 950 | +class TestNumericArithmeticUnsorted(object): |
| 951 | + # Tests in this class have been moved from type-specific test modules |
| 952 | + # but not yet sorted, parametrized, and de-duplicated |
| 953 | + |
| 954 | + def check_binop(self, ops, scalars, idxs): |
| 955 | + for op in ops: |
| 956 | + for a, b in combinations(idxs, 2): |
| 957 | + result = op(a, b) |
| 958 | + expected = op(pd.Int64Index(a), pd.Int64Index(b)) |
| 959 | + tm.assert_index_equal(result, expected) |
| 960 | + for idx in idxs: |
| 961 | + for scalar in scalars: |
| 962 | + result = op(idx, scalar) |
| 963 | + expected = op(pd.Int64Index(idx), scalar) |
| 964 | + tm.assert_index_equal(result, expected) |
| 965 | + |
| 966 | + def test_binops(self): |
| 967 | + ops = [operator.add, operator.sub, operator.mul, operator.floordiv, |
| 968 | + operator.truediv] |
| 969 | + scalars = [-1, 1, 2] |
| 970 | + idxs = [pd.RangeIndex(0, 10, 1), pd.RangeIndex(0, 20, 2), |
| 971 | + pd.RangeIndex(-10, 10, 2), pd.RangeIndex(5, -5, -1)] |
| 972 | + self.check_binop(ops, scalars, idxs) |
| 973 | + |
| 974 | + def test_binops_pow(self): |
| 975 | + # later versions of numpy don't allow powers of negative integers |
| 976 | + # so test separately |
| 977 | + # https://github.com/numpy/numpy/pull/8127 |
| 978 | + ops = [pow] |
| 979 | + scalars = [1, 2] |
| 980 | + idxs = [pd.RangeIndex(0, 10, 1), pd.RangeIndex(0, 20, 2)] |
| 981 | + self.check_binop(ops, scalars, idxs) |
| 982 | + |
| 983 | + # TODO: mod, divmod? |
| 984 | + @pytest.mark.parametrize('op', [operator.add, operator.sub, |
| 985 | + operator.mul, operator.floordiv, |
| 986 | + operator.truediv, operator.pow]) |
| 987 | + def test_arithmetic_with_frame_or_series(self, op): |
| 988 | + # check that we return NotImplemented when operating with Series |
| 989 | + # or DataFrame |
| 990 | + index = pd.RangeIndex(5) |
| 991 | + other = pd.Series(np.random.randn(5)) |
| 992 | + |
| 993 | + expected = op(pd.Series(index), other) |
| 994 | + result = op(index, other) |
| 995 | + tm.assert_series_equal(result, expected) |
| 996 | + |
| 997 | + other = pd.DataFrame(np.random.randn(2, 5)) |
| 998 | + expected = op(pd.DataFrame([index, index]), other) |
| 999 | + result = op(index, other) |
| 1000 | + tm.assert_frame_equal(result, expected) |
| 1001 | + |
| 1002 | + def test_numeric_compat2(self): |
| 1003 | + # validate that we are handling the RangeIndex overrides to numeric ops |
| 1004 | + # and returning RangeIndex where possible |
| 1005 | + |
| 1006 | + idx = pd.RangeIndex(0, 10, 2) |
| 1007 | + |
| 1008 | + result = idx * 2 |
| 1009 | + expected = pd.RangeIndex(0, 20, 4) |
| 1010 | + tm.assert_index_equal(result, expected, exact=True) |
| 1011 | + |
| 1012 | + result = idx + 2 |
| 1013 | + expected = pd.RangeIndex(2, 12, 2) |
| 1014 | + tm.assert_index_equal(result, expected, exact=True) |
| 1015 | + |
| 1016 | + result = idx - 2 |
| 1017 | + expected = pd.RangeIndex(-2, 8, 2) |
| 1018 | + tm.assert_index_equal(result, expected, exact=True) |
| 1019 | + |
| 1020 | + # truediv under PY3 |
| 1021 | + result = idx / 2 |
| 1022 | + |
| 1023 | + if PY3: |
| 1024 | + expected = pd.RangeIndex(0, 5, 1).astype('float64') |
| 1025 | + else: |
| 1026 | + expected = pd.RangeIndex(0, 5, 1) |
| 1027 | + tm.assert_index_equal(result, expected, exact=True) |
| 1028 | + |
| 1029 | + result = idx / 4 |
| 1030 | + expected = pd.RangeIndex(0, 10, 2) / 4 |
| 1031 | + tm.assert_index_equal(result, expected, exact=True) |
| 1032 | + |
| 1033 | + result = idx // 1 |
| 1034 | + expected = idx |
| 1035 | + tm.assert_index_equal(result, expected, exact=True) |
| 1036 | + |
| 1037 | + # __mul__ |
| 1038 | + result = idx * idx |
| 1039 | + expected = Index(idx.values * idx.values) |
| 1040 | + tm.assert_index_equal(result, expected, exact=True) |
| 1041 | + |
| 1042 | + # __pow__ |
| 1043 | + idx = pd.RangeIndex(0, 1000, 2) |
| 1044 | + result = idx ** 2 |
| 1045 | + expected = idx._int64index ** 2 |
| 1046 | + tm.assert_index_equal(Index(result.values), expected, exact=True) |
| 1047 | + |
| 1048 | + # __floordiv__ |
| 1049 | + cases_exact = [ |
| 1050 | + (pd.RangeIndex(0, 1000, 2), 2, pd.RangeIndex(0, 500, 1)), |
| 1051 | + (pd.RangeIndex(-99, -201, -3), -3, pd.RangeIndex(33, 67, 1)), |
| 1052 | + (pd.RangeIndex(0, 1000, 1), 2, |
| 1053 | + pd.RangeIndex(0, 1000, 1)._int64index // 2), |
| 1054 | + (pd.RangeIndex(0, 100, 1), 2.0, |
| 1055 | + pd.RangeIndex(0, 100, 1)._int64index // 2.0), |
| 1056 | + (pd.RangeIndex(0), 50, pd.RangeIndex(0)), |
| 1057 | + (pd.RangeIndex(2, 4, 2), 3, pd.RangeIndex(0, 1, 1)), |
| 1058 | + (pd.RangeIndex(-5, -10, -6), 4, pd.RangeIndex(-2, -1, 1)), |
| 1059 | + (pd.RangeIndex(-100, -200, 3), 2, pd.RangeIndex(0))] |
| 1060 | + for idx, div, expected in cases_exact: |
| 1061 | + tm.assert_index_equal(idx // div, expected, exact=True) |
0 commit comments