|
21 | 21 | from pandas.core.missing import _clean_reindex_fill_method |
22 | 22 | from pandas.core.common import (isnull, array_equivalent, |
23 | 23 | is_object_dtype, is_datetimetz, ABCSeries, |
24 | | - ABCPeriodIndex, |
| 24 | + ABCPeriodIndex, ABCMultiIndex, |
25 | 25 | _values_from_object, is_float, is_integer, |
26 | 26 | is_iterator, is_categorical_dtype, |
27 | 27 | _ensure_object, _ensure_int64, is_bool_indexer, |
28 | 28 | is_list_like, is_bool_dtype, |
29 | | - is_integer_dtype) |
| 29 | + is_integer_dtype, is_float_dtype) |
30 | 30 | from pandas.core.strings import StringAccessorMixin |
31 | 31 |
|
32 | 32 | from pandas.core.config import get_option |
@@ -162,7 +162,46 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None, |
162 | 162 |
|
163 | 163 | if dtype is not None: |
164 | 164 | try: |
165 | | - data = np.array(data, dtype=dtype, copy=copy) |
| 165 | + |
| 166 | + # we need to avoid having numpy coerce |
| 167 | + # things that look like ints/floats to ints unless |
| 168 | + # they are actually ints, e.g. '0' and 0.0 |
| 169 | + # should not be coerced |
| 170 | + # GH 11836 |
| 171 | + if is_integer_dtype(dtype): |
| 172 | + inferred = lib.infer_dtype(data) |
| 173 | + if inferred == 'integer': |
| 174 | + data = np.array(data, copy=copy, dtype=dtype) |
| 175 | + elif inferred in ['floating', 'mixed-integer-float']: |
| 176 | + |
| 177 | + # if we are actually all equal to integers |
| 178 | + # then coerce to integer |
| 179 | + from .numeric import Int64Index, Float64Index |
| 180 | + try: |
| 181 | + res = data.astype('i8') |
| 182 | + if (res == data).all(): |
| 183 | + return Int64Index(res, copy=copy, |
| 184 | + name=name) |
| 185 | + except (TypeError, ValueError): |
| 186 | + pass |
| 187 | + |
| 188 | + # return an actual float index |
| 189 | + return Float64Index(data, copy=copy, dtype=dtype, |
| 190 | + name=name) |
| 191 | + |
| 192 | + elif inferred == 'string': |
| 193 | + pass |
| 194 | + else: |
| 195 | + data = data.astype(dtype) |
| 196 | + elif is_float_dtype(dtype): |
| 197 | + inferred = lib.infer_dtype(data) |
| 198 | + if inferred == 'string': |
| 199 | + pass |
| 200 | + else: |
| 201 | + data = data.astype(dtype) |
| 202 | + else: |
| 203 | + data = np.array(data, dtype=dtype, copy=copy) |
| 204 | + |
166 | 205 | except (TypeError, ValueError): |
167 | 206 | pass |
168 | 207 |
|
@@ -930,35 +969,32 @@ def _convert_scalar_indexer(self, key, kind=None): |
930 | 969 | kind : optional, type of the indexing operation (loc/ix/iloc/None) |
931 | 970 |
|
932 | 971 | right now we are converting |
933 | | - floats -> ints if the index supports it |
934 | 972 | """ |
935 | 973 |
|
936 | | - def to_int(): |
937 | | - ikey = int(key) |
938 | | - if ikey != key: |
939 | | - return self._invalid_indexer('label', key) |
940 | | - return ikey |
941 | | - |
942 | 974 | if kind == 'iloc': |
943 | 975 | if is_integer(key): |
944 | 976 | return key |
945 | | - elif is_float(key): |
946 | | - key = to_int() |
947 | | - warnings.warn("scalar indexers for index type {0} should be " |
948 | | - "integers and not floating point".format( |
949 | | - type(self).__name__), |
950 | | - FutureWarning, stacklevel=5) |
951 | | - return key |
952 | 977 | return self._invalid_indexer('label', key) |
| 978 | + else: |
953 | 979 |
|
954 | | - if is_float(key): |
955 | | - if isnull(key): |
956 | | - return self._invalid_indexer('label', key) |
957 | | - warnings.warn("scalar indexers for index type {0} should be " |
958 | | - "integers and not floating point".format( |
959 | | - type(self).__name__), |
960 | | - FutureWarning, stacklevel=3) |
961 | | - return to_int() |
| 980 | + if len(self): |
| 981 | + |
| 982 | + # we can safely disallow |
| 983 | + # if we are not a MultiIndex |
| 984 | + # or a Float64Index |
| 985 | + # or have mixed inferred type (IOW we have the possiblity |
| 986 | + # of a float in with say strings) |
| 987 | + if is_float(key): |
| 988 | + if not (isinstance(self, ABCMultiIndex,) or |
| 989 | + self.is_floating() or self.is_mixed()): |
| 990 | + return self._invalid_indexer('label', key) |
| 991 | + |
| 992 | + # we can disallow integers with loc |
| 993 | + # if could not contain and integer |
| 994 | + elif is_integer(key) and kind == 'loc': |
| 995 | + if not (isinstance(self, ABCMultiIndex,) or |
| 996 | + self.holds_integer() or self.is_mixed()): |
| 997 | + return self._invalid_indexer('label', key) |
962 | 998 |
|
963 | 999 | return key |
964 | 1000 |
|
@@ -991,14 +1027,6 @@ def f(c): |
991 | 1027 | v = getattr(key, c) |
992 | 1028 | if v is None or is_integer(v): |
993 | 1029 | return v |
994 | | - |
995 | | - # warn if it's a convertible float |
996 | | - if v == int(v): |
997 | | - warnings.warn("slice indexers when using iloc should be " |
998 | | - "integers and not floating point", |
999 | | - FutureWarning, stacklevel=7) |
1000 | | - return int(v) |
1001 | | - |
1002 | 1030 | self._invalid_indexer('slice {0} value'.format(c), v) |
1003 | 1031 |
|
1004 | 1032 | return slice(*[f(c) for c in ['start', 'stop', 'step']]) |
@@ -1057,7 +1085,7 @@ def is_int(v): |
1057 | 1085 | indexer = key |
1058 | 1086 | else: |
1059 | 1087 | try: |
1060 | | - indexer = self.slice_indexer(start, stop, step) |
| 1088 | + indexer = self.slice_indexer(start, stop, step, kind=kind) |
1061 | 1089 | except Exception: |
1062 | 1090 | if is_index_slice: |
1063 | 1091 | if self.is_integer(): |
@@ -1891,10 +1919,7 @@ def get_value(self, series, key): |
1891 | 1919 | s = _values_from_object(series) |
1892 | 1920 | k = _values_from_object(key) |
1893 | 1921 |
|
1894 | | - # prevent integer truncation bug in indexing |
1895 | | - if is_float(k) and not self.is_floating(): |
1896 | | - raise KeyError |
1897 | | - |
| 1922 | + k = self._convert_scalar_indexer(k, kind='getitem') |
1898 | 1923 | try: |
1899 | 1924 | return self._engine.get_value(s, k, |
1900 | 1925 | tz=getattr(series.dtype, 'tz', None)) |
@@ -2236,6 +2261,7 @@ def reindex(self, target, method=None, level=None, limit=None, |
2236 | 2261 | if self.equals(target): |
2237 | 2262 | indexer = None |
2238 | 2263 | else: |
| 2264 | + |
2239 | 2265 | if self.is_unique: |
2240 | 2266 | indexer = self.get_indexer(target, method=method, |
2241 | 2267 | limit=limit, |
@@ -2722,7 +2748,9 @@ def _maybe_cast_slice_bound(self, label, side, kind): |
2722 | 2748 | # datetimelike Indexes |
2723 | 2749 | # reject them |
2724 | 2750 | if is_float(label): |
2725 | | - self._invalid_indexer('slice', label) |
| 2751 | + if not (kind in ['ix'] and (self.holds_integer() or |
| 2752 | + self.is_floating())): |
| 2753 | + self._invalid_indexer('slice', label) |
2726 | 2754 |
|
2727 | 2755 | # we are trying to find integer bounds on a non-integer based index |
2728 | 2756 | # this is rejected (generally .loc gets you here) |
|
0 commit comments