Skip to content

Commit 7f31567

Browse files
committed
BLD: py3 compat
TST/BUG: test/bugfix for GH4463 BUG: fix core/internals/setitem to work for boolean types (weird numpy bug!) BUG: partial frame setting with dtype change (GH4204) BUG: Indexing with dtype conversions fixed GH4463 (int->float), GH4204(boolean->float) BUG: provide better ndarray compat CLN: removed some duped methods MERGE: fix an issue cropping up on the rebase
1 parent 370f8c8 commit 7f31567

16 files changed

+202
-97
lines changed

doc/source/release.rst

+2
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ and behaviors. Series formerly subclassed directly from ``ndarray``. (:issue:`40
184184
- Bug in Series update where the parent frame is not updating its cache based on
185185
changes (:issue:`4080`) or types (:issue:`3217`), fillna (:issue:`3386`)
186186

187+
- Indexing with dtype conversions fixed (:issue:`4463`, :issue:`4204`)
188+
187189
**Experimental Features**
188190

189191
**Bug Fixes**

doc/source/v0.13.0.txt

+2
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ and behaviors. Series formerly subclassed directly from ``ndarray``. (:issue:`40
202202
- Bug in Series update where the parent frame is not updating its cached based on
203203
changes (:issue:`4080`) or types (:issue:`3217`), fillna (:issue:`3386`)
204204

205+
- Indexing with dtype conversions fixed (:issue:`4463`, :issue:`4204`)
206+
205207
Bug Fixes
206208
~~~~~~~~~
207209

pandas/compat/pickle_compat.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import pickle
55
import numpy as np
66
import pandas
7-
from pandas.util import py3compat
7+
from pandas import compat
88
from pandas.core.series import Series
99
from pandas.sparse.series import SparseSeries
1010

@@ -20,7 +20,7 @@ def load_reduce(self):
2020
elif n == 'DeprecatedSparseSeries':
2121
stack[-1] = object.__new__(SparseSeries)
2222
return
23-
23+
2424
try:
2525
value = func(*args)
2626
except:
@@ -30,7 +30,7 @@ def load_reduce(self):
3030

3131
stack[-1] = value
3232

33-
if py3compat.PY3:
33+
if compat.PY3:
3434
class Unpickler(pickle._Unpickler):
3535
pass
3636
else:

pandas/core/frame.py

+18-8
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,8 @@ def __init__(self, data=None, index=None, columns=None, dtype=None,
410410
if columns is None:
411411
columns = data_columns
412412
mgr = self._init_dict(data, index, columns, dtype=dtype)
413+
elif getattr(data,'name',None):
414+
mgr = self._init_dict({ data.name : data }, index, columns, dtype=dtype)
413415
else:
414416
mgr = self._init_ndarray(data, index, columns, dtype=dtype,
415417
copy=copy)
@@ -4853,9 +4855,12 @@ def convert(v):
48534855
# we could have a 1-dim or 2-dim list here
48544856
# this is equiv of np.asarray, but does object conversion
48554857
# and platform dtype preservation
4856-
if com.is_list_like(values[0]) or hasattr(values[0], 'len'):
4857-
values = np.array([convert(v) for v in values])
4858-
else:
4858+
try:
4859+
if com.is_list_like(values[0]) or hasattr(values[0], 'len'):
4860+
values = np.array([convert(v) for v in values])
4861+
else:
4862+
values = convert(values)
4863+
except:
48594864
values = convert(values)
48604865

48614866
else:
@@ -4945,18 +4950,23 @@ def _list_of_series_to_arrays(data, columns, coerce_float=False, dtype=None):
49454950
from pandas.core.index import _get_combined_index
49464951

49474952
if columns is None:
4948-
columns = _get_combined_index([s.index for s in data])
4953+
columns = _get_combined_index([s.index for s in data if getattr(s,'index',None) is not None ])
49494954

49504955
indexer_cache = {}
49514956

49524957
aligned_values = []
49534958
for s in data:
4954-
index = s.index
4959+
index = getattr(s,'index',None)
4960+
if index is None:
4961+
index = _default_index(len(s))
4962+
49554963
if id(index) in indexer_cache:
49564964
indexer = indexer_cache[id(index)]
49574965
else:
49584966
indexer = indexer_cache[id(index)] = index.get_indexer(columns)
4959-
aligned_values.append(com.take_1d(s.values, indexer))
4967+
4968+
values = _values_from_object(s)
4969+
aligned_values.append(com.take_1d(values, indexer))
49604970

49614971
values = np.vstack(aligned_values)
49624972

@@ -5000,13 +5010,13 @@ def _convert_object_array(content, columns, coerce_float=False, dtype=None):
50005010

50015011
def _get_names_from_index(data):
50025012
index = lrange(len(data))
5003-
has_some_name = any([s.name is not None for s in data])
5013+
has_some_name = any([getattr(s,'name',None) is not None for s in data])
50045014
if not has_some_name:
50055015
return index
50065016

50075017
count = 0
50085018
for i, s in enumerate(data):
5009-
n = s.name
5019+
n = getattr(s,'name',None)
50105020
if n is not None:
50115021
index[i] = n
50125022
else:

pandas/core/generic.py

+16-44
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,22 @@
11
# pylint: disable=W0231,E1101
22
import warnings
3-
from pandas import compat
4-
import itertools
53
import operator
64
import weakref
75
import numpy as np
86
import pandas.lib as lib
9-
from pandas.core.base import PandasObject
107

8+
from pandas.core.base import PandasObject
119
from pandas.core.index import Index, MultiIndex, _ensure_index
1210
import pandas.core.indexing as indexing
1311
from pandas.core.indexing import _maybe_convert_indices
1412
from pandas.tseries.index import DatetimeIndex
1513
from pandas.core.internals import BlockManager
16-
import pandas.lib as lib
17-
from pandas.util import py3compat
1814
import pandas.core.common as com
15+
from pandas import compat
1916
from pandas.compat import map, zip
2017
from pandas.core.common import (isnull, notnull, is_list_like,
2118
_values_from_object,
2219
_infer_dtype_from_scalar, _maybe_promote)
23-
from pandas.core.base import PandasObject
24-
2520

2621
class NDFrame(PandasObject):
2722

@@ -78,10 +73,6 @@ def _init_mgr(self, mgr, axes=None, dtype=None, copy=False):
7873
def _constructor(self):
7974
raise NotImplementedError
8075

81-
def __hash__(self):
82-
raise TypeError('{0!r} objects are mutable, thus they cannot be'
83-
' hashed'.format(self.__class__.__name__))
84-
8576
def __unicode__(self):
8677
# unicode representation based upon iterating over self
8778
# (since, by definition, `PandasContainers` are iterable)
@@ -111,12 +102,12 @@ def _setup_axes(
111102
"""
112103

113104
cls._AXIS_ORDERS = axes
114-
cls._AXIS_NUMBERS = dict([(a, i) for i, a in enumerate(axes)])
105+
cls._AXIS_NUMBERS = dict((a, i) for i, a in enumerate(axes))
115106
cls._AXIS_LEN = len(axes)
116107
cls._AXIS_ALIASES = aliases or dict()
117-
cls._AXIS_IALIASES = dict([(v, k)
118-
for k, v in cls._AXIS_ALIASES.items()])
119-
cls._AXIS_NAMES = dict([(i, a) for i, a in enumerate(axes)])
108+
cls._AXIS_IALIASES = dict((v, k)
109+
for k, v in cls._AXIS_ALIASES.items())
110+
cls._AXIS_NAMES = dict(enumerate(axes))
120111
cls._AXIS_SLICEMAP = slicers or None
121112
cls._AXIS_REVERSED = axes_are_reversed
122113

@@ -271,23 +262,6 @@ def axes(self):
271262
the block manager shows then reversed """
272263
return [self._get_axis(a) for a in self._AXIS_ORDERS]
273264

274-
def _construct_axes_dict(self, axes=None, **kwargs):
275-
""" return an axes dictionary for myself """
276-
d = dict([(a, getattr(self, a)) for a in (axes or self._AXIS_ORDERS)])
277-
d.update(kwargs)
278-
return d
279-
280-
@staticmethod
281-
def _construct_axes_dict_from(self, axes, **kwargs):
282-
""" return an axes dictionary for the passed axes """
283-
d = dict([(a, ax) for a, ax in zip(self._AXIS_ORDERS, axes)])
284-
d.update(kwargs)
285-
return d
286-
287-
@property
288-
def values(self):
289-
return self._data.as_matrix()
290-
291265
@property
292266
def ndim(self):
293267
return self._data.ndim
@@ -445,9 +419,6 @@ def rename_axis(self, mapper, axis=0, copy=True):
445419
def _indexed_same(self, other):
446420
return all([self._get_axis(a).equals(other._get_axis(a)) for a in self._AXIS_ORDERS])
447421

448-
def reindex(self, *args, **kwds):
449-
raise NotImplementedError
450-
451422
def __neg__(self):
452423
arr = operator.neg(_values_from_object(self))
453424
return self._wrap_array(arr, self.axes, copy=False)
@@ -460,7 +431,8 @@ def __invert__(self):
460431
# Iteration
461432

462433
def __hash__(self):
463-
raise TypeError
434+
raise TypeError('{0!r} objects are mutable, thus they cannot be'
435+
' hashed'.format(self.__class__.__name__))
464436

465437
def __iter__(self):
466438
"""
@@ -483,7 +455,6 @@ def iterkv(self, *args, **kwargs):
483455
"release, use ``iteritems`` instead.", DeprecationWarning)
484456
return self.iteritems(*args, **kwargs)
485457

486-
487458
def __len__(self):
488459
"""Returns length of info axis """
489460
return len(self._info_axis)
@@ -1142,7 +1113,7 @@ def filter(self, items=None, like=None, regex=None, axis=None):
11421113
if items is not None:
11431114
return self.reindex(**{axis_name: [r for r in items if r in axis_values]})
11441115
elif like:
1145-
matchf = lambda x: (like in x if isinstance(x, basestring)
1116+
matchf = lambda x: (like in x if isinstance(x, compat.string_types)
11461117
else like in str(x))
11471118
return self.select(matchf, axis=axis_name)
11481119
elif regex:
@@ -1285,6 +1256,7 @@ def get_dtype_counts(self):
12851256

12861257
def get_ftype_counts(self):
12871258
""" return the counts of ftypes in this frame """
1259+
from pandas import Series
12881260
return Series(self._data.get_ftype_counts())
12891261

12901262
def as_blocks(self, columns=None):
@@ -1446,7 +1418,7 @@ def fillna(self, value=None, method=None, axis=0, inplace=False,
14461418
'by column')
14471419

14481420
result = self if inplace else self.copy()
1449-
for k, v in value.iteritems():
1421+
for k, v in compat.iteritems(value):
14501422
if k not in result:
14511423
continue
14521424
obj = result[k]
@@ -1595,7 +1567,7 @@ def is_dictlike(x):
15951567
regex = True
15961568

15971569
items = to_replace.items()
1598-
keys, values = itertools.izip(*items)
1570+
keys, values = zip(*items)
15991571

16001572
are_mappings = [is_dictlike(v) for v in values]
16011573

@@ -1629,7 +1601,7 @@ def is_dictlike(x):
16291601
if is_dictlike(to_replace):
16301602
if is_dictlike(value): # {'A' : NA} -> {'A' : 0}
16311603
new_data = self._data
1632-
for c, src in to_replace.iteritems():
1604+
for c, src in compat.iteritems(to_replace):
16331605
if c in value and c in self:
16341606
new_data = new_data.replace(src, value[c],
16351607
filter=[c],
@@ -1639,7 +1611,7 @@ def is_dictlike(x):
16391611
# {'A': NA} -> 0
16401612
elif not isinstance(value, (list, np.ndarray)):
16411613
new_data = self._data
1642-
for k, src in to_replace.iteritems():
1614+
for k, src in compat.iteritems(to_replace):
16431615
if k in self:
16441616
new_data = new_data.replace(src, value,
16451617
filter=[k],
@@ -1679,7 +1651,7 @@ def is_dictlike(x):
16791651
if is_dictlike(value): # NA -> {'A' : 0, 'B' : -1}
16801652
new_data = self._data
16811653

1682-
for k, v in value.iteritems():
1654+
for k, v in compat.iteritems(value):
16831655
if k in self:
16841656
new_data = new_data.replace(to_replace, v,
16851657
filter=[k],
@@ -1729,7 +1701,7 @@ def interpolate(self, to_replace, method='pad', axis=0, inplace=False,
17291701

17301702
method = com._clean_fill_method(method)
17311703

1732-
if isinstance(to_replace, (dict, Series)):
1704+
if isinstance(to_replace, (dict, com.ABCSeries)):
17331705
if axis == 0:
17341706
return self.replace(to_replace, method=method, inplace=inplace,
17351707
limit=limit, axis=axis)

pandas/core/index.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
from pandas.core.common import isnull
1616
import pandas.core.common as com
1717
from pandas.core.common import _values_from_object
18-
from pandas.util import py3compat
1918
from pandas.core.config import get_option
2019
import warnings
2120

@@ -808,7 +807,7 @@ def get_value(self, series, key):
808807
k = _values_from_object(key)
809808
try:
810809
return self._engine.get_value(s, k)
811-
except KeyError, e1:
810+
except KeyError as e1:
812811
if len(self) > 0 and self.inferred_type == 'integer':
813812
raise
814813

@@ -1447,7 +1446,7 @@ def __new__(cls, data, dtype=None, copy=False, name=None, fastpath=False):
14471446
data = list(data)
14481447
data = np.asarray(data)
14491448

1450-
if issubclass(data.dtype.type, basestring):
1449+
if issubclass(data.dtype.type, compat.string_types):
14511450
raise TypeError('String dtype not supported, you may need '
14521451
'to explicitly cast to int')
14531452
elif issubclass(data.dtype.type, np.integer):
@@ -1865,7 +1864,7 @@ def get_value(self, series, key):
18651864
k = _values_from_object(key)
18661865
try:
18671866
return self._engine.get_value(s, k)
1868-
except KeyError, e1:
1867+
except KeyError as e1:
18691868
try:
18701869
# TODO: what if a level contains tuples??
18711870
loc = self.get_loc(key)

pandas/core/indexing.py

+4-7
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
from pandas.compat import range, zip
77
import pandas.compat as compat
88
import pandas.core.common as com
9-
from pandas.core.common import _is_bool_indexer, ABCSeries, ABCDataFrame
9+
from pandas.core.common import (_is_bool_indexer,
10+
ABCSeries, ABCDataFrame, ABCPanel)
1011
import pandas.lib as lib
1112

1213
import numpy as np
@@ -104,7 +105,6 @@ def _convert_tuple(self, key):
104105
def _setitem_with_indexer(self, indexer, value):
105106

106107
# also has the side effect of consolidating in-place
107-
108108
# mmm, spaghetti
109109

110110
if self.obj._is_mixed_type:
@@ -182,13 +182,10 @@ def setter(item, v):
182182
elif isinstance(value, ABCDataFrame):
183183
value = self._align_frame(indexer, value)
184184

185-
if isinstance(value, Panel):
185+
if isinstance(value, ABCPanel):
186186
value = self._align_panel(indexer, value)
187187

188-
# 2096
189-
values = self.obj.values
190-
if np.prod(values.shape):
191-
values[indexer] = value
188+
self.obj._data = self.obj._data.setitem(indexer,value)
192189

193190
def _align_series(self, indexer, ser):
194191
# indexer to assign Series can be tuple or scalar

0 commit comments

Comments
 (0)