Skip to content

Commit ae2e3a4

Browse files
committed
Merge pull request #4675 from jreback/numeric
CLN/API: Refactor of _get_numeric_data/_get_bool_data to core/generic.py, allowing Series/Panel functionaility
2 parents e25976a + 06c2d5b commit ae2e3a4

File tree

8 files changed

+73
-31
lines changed

8 files changed

+73
-31
lines changed

doc/source/release.rst

+1
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ See :ref:`Internal Refactoring<whatsnew_0130.refactoring>`
193193
- Refactor ``rename`` methods to core/generic.py; fixes ``Series.rename`` for (:issue:`4605`), and adds ``rename``
194194
with the same signature for ``Panel``
195195
- Series (for index) / Panel (for items) now as attribute access to its elements (:issue:`1903`)
196+
- Refactor of ``_get_numeric_data/_get_bool_data`` to core/generic.py, allowing Series/Panel functionaility
196197

197198
**Experimental Features**
198199

doc/source/v0.13.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ and behaviors. Series formerly subclassed directly from ``ndarray``. (:issue:`40
268268
- ``Series.copy`` no longer accepts the ``order`` parameter and is now consistent with ``NDFrame`` copy
269269
- Refactor ``rename`` methods to core/generic.py; fixes ``Series.rename`` for (:issue`4605`), and adds ``rename``
270270
with the same signature for ``Panel``
271+
- Refactor of ``_get_numeric_data/_get_bool_data`` to core/generic.py, allowing Series/Panel functionaility
271272
- ``Series`` (for index) / ``Panel`` (for items) now allow attribute access to its elements (:issue:`1903`)
272273

273274
.. ipython:: python

pandas/core/frame.py

-6
Original file line numberDiff line numberDiff line change
@@ -4388,12 +4388,6 @@ def _get_agg_axis(self, axis_num):
43884388
else:
43894389
raise Exception('Must have 0<= axis <= 1')
43904390

4391-
def _get_numeric_data(self):
4392-
return self._constructor(self._data.get_numeric_data(), index=self.index, copy=False)
4393-
4394-
def _get_bool_data(self):
4395-
return self._constructor(self._data.get_bool_data(), index=self.index, copy=False)
4396-
43974391
def quantile(self, q=0.5, axis=0, numeric_only=True):
43984392
"""
43994393
Return values at the given quantile over requested axis, a la

pandas/core/generic.py

+6
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,12 @@ def _protect_consolidate(self, f):
13191319
self._clear_item_cache()
13201320
return result
13211321

1322+
def _get_numeric_data(self):
1323+
return self._constructor(self._data.get_numeric_data())
1324+
1325+
def _get_bool_data(self):
1326+
return self._constructor(self._data.get_bool_data())
1327+
13221328
#----------------------------------------------------------------------
13231329
# Internal Interface Methods
13241330

pandas/core/internals.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -1574,9 +1574,11 @@ def __init__(self, blocks, axes, do_integrity_check=True, fastpath=True):
15741574
if not self.items.is_unique:
15751575
self._set_ref_locs(do_refs=True)
15761576

1577-
@classmethod
1578-
def make_empty(cls):
1579-
return cls([], [[], []])
1577+
def make_empty(self, axes=None):
1578+
""" return an empty BlockManager with the items axis of len 0 """
1579+
if axes is None:
1580+
axes = [_ensure_index([]) ] + [ _ensure_index(a) for a in self.axes[1:] ]
1581+
return self.__class__(np.array([]), axes)
15801582

15811583
def __nonzero__(self):
15821584
return True
@@ -2074,7 +2076,7 @@ def get_data(self, copy=False, columns=None, **kwargs):
20742076
blocks = self.get_block_map(
20752077
typ='list', copy=copy, columns=columns, **kwargs)
20762078
if len(blocks) == 0:
2077-
return self.__class__.make_empty()
2079+
return self.make_empty()
20782080

20792081
return self.combine(blocks)
20802082

pandas/tests/test_frame.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -10667,8 +10667,8 @@ def test_tslib_tz_convert_trans_pos_plus_1__bug(self):
1066710667

1066810668
test_vector = pd.Series([3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1066910669
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
10670-
3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
10671-
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
10670+
3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
10671+
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
1067210672
4, 4, 4, 4, 4, 4, 4, 4, 5], dtype=int)
1067310673

1067410674
hours = idx.hour

pandas/tests/test_generic.py

+56-4
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,43 @@ def setUp(self):
3636
import warnings
3737
warnings.filterwarnings(action='ignore', category=FutureWarning)
3838

39+
@property
40+
def _ndim(self):
41+
return self._typ._AXIS_LEN
42+
3943
def _axes(self):
4044
""" return the axes for my object typ """
4145
return self._typ._AXIS_ORDERS
4246

43-
def _construct(self, shape=None, **kwargs):
44-
""" construct an object for the given shape """
47+
def _construct(self, shape, value=None, **kwargs):
48+
""" construct an object for the given shape
49+
if value is specified use that if its a scalar
50+
if value is an array, repeat it as needed """
4551

4652
if isinstance(shape,int):
47-
shape = tuple([shape] * self._typ._AXIS_LEN)
48-
return self._typ(np.random.randn(*shape),**kwargs)
53+
shape = tuple([shape] * self._ndim)
54+
if value is not None:
55+
if np.isscalar(value):
56+
if value == 'empty':
57+
arr = None
58+
59+
# remove the info axis
60+
kwargs.pop(self._typ._info_axis_name,None)
61+
else:
62+
arr = np.empty(shape)
63+
arr.fill(value)
64+
else:
65+
fshape = np.prod(shape)
66+
arr = value.ravel()
67+
new_shape = fshape/arr.shape[0]
68+
if fshape % arr.shape[0] != 0:
69+
raise Exception("invalid value passed in _construct")
70+
71+
arr = np.repeat(arr,new_shape).reshape(shape)
72+
else:
73+
arr = np.random.randn(*shape)
74+
return self._typ(arr,**kwargs)
75+
4976

5077
def _compare(self, result, expected):
5178
self._comparator(result,expected)
@@ -68,6 +95,31 @@ def test_rename(self):
6895

6996
# multiple axes at once
7097

98+
def test_get_numeric_data(self):
99+
100+
n = 4
101+
kwargs = { }
102+
for i in range(self._ndim):
103+
kwargs[self._typ._AXIS_NAMES[i]] = list(range(n))
104+
105+
# get the numeric data
106+
o = self._construct(n,**kwargs)
107+
result = o._get_numeric_data()
108+
self._compare(result, o)
109+
110+
# non-inclusion
111+
result = o._get_bool_data()
112+
expected = self._construct(n,value='empty',**kwargs)
113+
self._compare(result,expected)
114+
115+
# get the bool data
116+
arr = np.array([True,True,False,True])
117+
o = self._construct(n,value=arr,**kwargs)
118+
result = o._get_numeric_data()
119+
self._compare(result, o)
120+
121+
# _get_numeric_data is includes _get_bool_data, so can't test for non-inclusion
122+
71123
class TestSeries(unittest.TestCase, Generic):
72124
_typ = Series
73125
_comparator = lambda self, x, y: assert_series_equal(x,y)

pandas/tools/plotting.py

+1-15
Original file line numberDiff line numberDiff line change
@@ -932,21 +932,7 @@ def _get_layout(self):
932932
return (len(self.data.columns), 1)
933933

934934
def _compute_plot_data(self):
935-
try:
936-
# might be an ndframe
937-
numeric_data = self.data._get_numeric_data()
938-
except AttributeError: # TODO: rm in 0.13 (series-inherit-ndframe)
939-
numeric_data = self.data
940-
orig_dtype = numeric_data.dtype
941-
942-
# possible object array of numeric data
943-
if orig_dtype == np.object_:
944-
numeric_data = numeric_data.convert_objects() # soft convert
945-
946-
# still an object dtype so we can't plot it
947-
if numeric_data.dtype == np.object_:
948-
raise TypeError('Series has object dtype and cannot be'
949-
' converted: no numeric data to plot')
935+
numeric_data = self.data.convert_objects()._get_numeric_data()
950936

951937
try:
952938
is_empty = numeric_data.empty

0 commit comments

Comments
 (0)