|
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