Skip to content

Commit eab3192

Browse files
authored
Merge branch 'master' into bug_issue16770
2 parents 7acc09f + 9c44f9b commit eab3192

File tree

17 files changed

+134
-92
lines changed

17 files changed

+134
-92
lines changed

asv_bench/benchmarks/timeseries.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ def setup(self):
5353
self.rng6 = date_range(start='1/1/1', periods=self.N, freq='B')
5454

5555
self.rng7 = date_range(start='1/1/1700', freq='D', periods=100000)
56-
self.a = self.rng7[:50000].append(self.rng7[50002:])
56+
self.no_freq = self.rng7[:50000].append(self.rng7[50002:])
57+
self.d_freq = self.rng7[:50000].append(self.rng7[50000:])
58+
59+
self.rng8 = date_range(start='1/1/1700', freq='B', periods=100000)
60+
self.b_freq = self.rng8[:50000].append(self.rng8[50000:])
5761

5862
def time_add_timedelta(self):
5963
(self.rng + dt.timedelta(minutes=2))
@@ -94,8 +98,14 @@ def time_infer_dst(self):
9498
def time_timeseries_is_month_start(self):
9599
self.rng6.is_month_start
96100

97-
def time_infer_freq(self):
98-
infer_freq(self.a)
101+
def time_infer_freq_none(self):
102+
infer_freq(self.no_freq)
103+
104+
def time_infer_freq_daily(self):
105+
infer_freq(self.d_freq)
106+
107+
def time_infer_freq_business(self):
108+
infer_freq(self.b_freq)
99109

100110

101111
class TimeDatetimeConverter(object):

doc/source/whatsnew/v0.20.3.txt

+14-54
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,61 @@
11
.. _whatsnew_0203:
22

3-
v0.20.3 (June ??, 2017)
3+
v0.20.3 (July 7, 2017)
44
-----------------------
55

6-
This is a minor bug-fix release in the 0.20.x series and includes some small regression fixes,
7-
bug fixes and performance improvements.
8-
We recommend that all users upgrade to this version.
6+
This is a minor bug-fix release in the 0.20.x series and includes some small regression fixes
7+
and bug fixes. We recommend that all users upgrade to this version.
98

109
.. contents:: What's new in v0.20.3
1110
:local:
1211
:backlinks: none
1312

14-
15-
.. _whatsnew_0203.enhancements:
16-
17-
Enhancements
18-
~~~~~~~~~~~~
19-
20-
21-
22-
23-
24-
25-
.. _whatsnew_0203.performance:
26-
27-
Performance Improvements
28-
~~~~~~~~~~~~~~~~~~~~~~~~
29-
30-
31-
32-
33-
34-
3513
.. _whatsnew_0203.bug_fixes:
3614

3715
Bug Fixes
3816
~~~~~~~~~
39-
- Fixed issue with dataframe scatter plot for categorical data that reports incorrect column key not found when categorical data is used for plotting (:issue:`16199`)
40-
- Fixed issue with :meth:`DataFrame.style` where element id's were not unique (:issue:`16780`)
41-
- Fixed a pytest marker failing downstream packages' tests suites (:issue:`16680`)
42-
- Fixed compat with loading a ``DataFrame`` with a ``PeriodIndex``, from a ``format='fixed'`` HDFStore, in Python 3, that was written in Python 2 (:issue:`16781`)
43-
- Fixed a bug in failing to compute rolling computations of a column-MultiIndexed ``DataFrame`` (:issue:`16789`, :issue:`16825`)
44-
- Bug in a DataFrame/Series with a ``TimedeltaIndex`` when slice indexing (:issue:`16637`)
4517

18+
- Fixed a bug in failing to compute rolling computations of a column-MultiIndexed ``DataFrame`` (:issue:`16789`, :issue:`16825`)
19+
- Fixed a pytest marker failing downstream packages' tests suites (:issue:`16680`)
4620

4721
Conversion
4822
^^^^^^^^^^
4923

5024
- Bug in pickle compat prior to the v0.20.x series, when ``UTC`` is a timezone in a Series/DataFrame/Index (:issue:`16608`)
5125
- Bug in ``Series`` construction when passing a ``Series`` with ``dtype='category'`` (:issue:`16524`).
52-
- Bug in ``DataFrame.astype()`` when passing a ``Series`` as the ``dtype`` kwarg. (:issue:`16717`).
26+
- Bug in :meth:`DataFrame.astype` when passing a ``Series`` as the ``dtype`` kwarg. (:issue:`16717`).
5327

5428
Indexing
5529
^^^^^^^^
5630

5731
- Bug in ``Float64Index`` causing an empty array instead of ``None`` to be returned from ``.get(np.nan)`` on a Series whose index did not contain any ``NaN`` s (:issue:`8569`)
5832
- Bug in ``MultiIndex.isin`` causing an error when passing an empty iterable (:issue:`16777`)
33+
- Fixed a bug in a slicing DataFrame/Series that have a ``TimedeltaIndex`` (:issue:`16637`)
5934

6035
I/O
6136
^^^
6237

6338
- Bug in :func:`read_csv` in which files weren't opened as binary files by the C engine on Windows, causing EOF characters mid-field, which would fail (:issue:`16039`, :issue:`16559`, :issue:`16675`)
6439
- Bug in :func:`read_hdf` in which reading a ``Series`` saved to an HDF file in 'fixed' format fails when an explicit ``mode='r'`` argument is supplied (:issue:`16583`)
65-
- Bug in :func:`DataFrame.to_latex` where ``bold_rows`` was wrongly specified to be ``True`` by default, whereas in reality row labels remained non-bold whatever parameter provided. (:issue:`16707`)
40+
- Bug in :meth:`DataFrame.to_latex` where ``bold_rows`` was wrongly specified to be ``True`` by default, whereas in reality row labels remained non-bold whatever parameter provided. (:issue:`16707`)
41+
- Fixed an issue with :meth:`DataFrame.style` where generated element ids were not unique (:issue:`16780`)
42+
- Fixed loading a ``DataFrame`` with a ``PeriodIndex``, from a ``format='fixed'`` HDFStore, in Python 3, that was written in Python 2 (:issue:`16781`)
6643

6744
Plotting
6845
^^^^^^^^
69-
- Fix regression in series plotting that prevented RGB and RGBA tuples from being used as color arguments (:issue:`16233`)
70-
71-
72-
73-
Groupby/Resample/Rolling
74-
^^^^^^^^^^^^^^^^^^^^^^^^
75-
76-
77-
78-
Sparse
79-
^^^^^^
80-
81-
8246

47+
- Fixed regression that prevented RGB and RGBA tuples from being used as color arguments (:issue:`16233`)
48+
- Fixed an issue with :meth:`DataFrame.plot.scatter` that incorrectly raised a ``KeyError`` when categorical data is used for plotting (:issue:`16199`)
8349

8450
Reshaping
8551
^^^^^^^^^
8652

53+
- ``PeriodIndex`` / ``TimedeltaIndex.join`` was missing the ``sort=`` kwarg (:issue:`16541`)
8754
- Bug in joining on a ``MultiIndex`` with a ``category`` dtype for a level (:issue:`16627`).
8855
- Bug in :func:`merge` when merging/joining with multiple categorical columns (:issue:`16767`)
8956

90-
91-
Numeric
92-
^^^^^^^
93-
94-
9557
Categorical
9658
^^^^^^^^^^^
9759

98-
- Bug in ``DataFrame.sort_values`` not respecting the ``kind`` with categorical data (:issue:`16793`)
9960

100-
Other
101-
^^^^^
61+
- Bug in ``DataFrame.sort_values`` not respecting the ``kind`` with categorical data (:issue:`16793`)

doc/source/whatsnew/v0.21.0.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ Groupby/Resample/Rolling
170170
^^^^^^^^^^^^^^^^^^^^^^^^
171171
- Bug in ``DataFrame.resample().size()`` where an empty ``DataFrame`` did not return a ``Series`` (:issue:`14962`)
172172

173-
173+
- Bug in ``infer_freq`` causing indices with 2-day gaps during the working week to be wrongly inferred as business daily (:issue:`16624`)
174174

175175
Sparse
176176
^^^^^^

pandas/core/indexes/base.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2704,7 +2704,7 @@ def get_indexer_non_unique(self, target):
27042704
tgt_values = target._values
27052705

27062706
indexer, missing = self._engine.get_indexer_non_unique(tgt_values)
2707-
return indexer, missing
2707+
return _ensure_platform_int(indexer), missing
27082708

27092709
def get_indexer_for(self, target, **kwargs):
27102710
"""
@@ -3126,7 +3126,7 @@ def _join_non_unique(self, other, how='left', return_indexers=False):
31263126
left_idx = _ensure_platform_int(left_idx)
31273127
right_idx = _ensure_platform_int(right_idx)
31283128

3129-
join_index = self.values.take(left_idx)
3129+
join_index = np.asarray(self.values.take(left_idx))
31303130
mask = left_idx == -1
31313131
np.putmask(join_index, mask, other._values.take(right_idx))
31323132

pandas/core/indexes/category.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,6 @@ def get_indexer(self, target, method=None, limit=None, tolerance=None):
500500
codes = self.categories.get_indexer(target)
501501

502502
indexer, _ = self._engine.get_indexer_non_unique(codes)
503-
504503
return _ensure_platform_int(indexer)
505504

506505
@Appender(_index_shared_docs['get_indexer_non_unique'] % _index_doc_kwargs)
@@ -511,7 +510,8 @@ def get_indexer_non_unique(self, target):
511510
target = target.categories
512511

513512
codes = self.categories.get_indexer(target)
514-
return self._engine.get_indexer_non_unique(codes)
513+
indexer, missing = self._engine.get_indexer_non_unique(codes)
514+
return _ensure_platform_int(indexer), missing
515515

516516
@Appender(_index_shared_docs['_convert_scalar_indexer'])
517517
def _convert_scalar_indexer(self, key, kind=None):

pandas/core/indexes/period.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -912,14 +912,16 @@ def insert(self, loc, item):
912912
self[loc:].asi8))
913913
return self._shallow_copy(idx)
914914

915-
def join(self, other, how='left', level=None, return_indexers=False):
915+
def join(self, other, how='left', level=None, return_indexers=False,
916+
sort=False):
916917
"""
917918
See Index.join
918919
"""
919920
self._assert_can_do_setop(other)
920921

921922
result = Int64Index.join(self, other, how=how, level=level,
922-
return_indexers=return_indexers)
923+
return_indexers=return_indexers,
924+
sort=sort)
923925

924926
if return_indexers:
925927
result, lidx, ridx = result

pandas/core/indexes/timedeltas.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,8 @@ def union(self, other):
516516
result.freq = to_offset(result.inferred_freq)
517517
return result
518518

519-
def join(self, other, how='left', level=None, return_indexers=False):
519+
def join(self, other, how='left', level=None, return_indexers=False,
520+
sort=False):
520521
"""
521522
See Index.join
522523
"""
@@ -527,7 +528,8 @@ def join(self, other, how='left', level=None, return_indexers=False):
527528
pass
528529

529530
return Index.join(self, other, how=how, level=level,
530-
return_indexers=return_indexers)
531+
return_indexers=return_indexers,
532+
sort=sort)
531533

532534
def _wrap_joined_index(self, joined, other):
533535
name = self.name if self.name == other.name else None

pandas/tests/frame/test_join.py

+27-1
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,19 @@
33
import pytest
44
import numpy as np
55

6-
from pandas import DataFrame, Index
6+
from pandas import DataFrame, Index, PeriodIndex
77
from pandas.tests.frame.common import TestData
88
import pandas.util.testing as tm
99

1010

11+
@pytest.fixture
12+
def frame_with_period_index():
13+
return DataFrame(
14+
data=np.arange(20).reshape(4, 5),
15+
columns=list('abcde'),
16+
index=PeriodIndex(start='2000', freq='A', periods=4))
17+
18+
1119
@pytest.fixture
1220
def frame():
1321
return TestData().frame
@@ -139,3 +147,21 @@ def test_join_overlap(frame):
139147

140148
# column order not necessarily sorted
141149
tm.assert_frame_equal(joined, expected.loc[:, joined.columns])
150+
151+
152+
def test_join_period_index(frame_with_period_index):
153+
other = frame_with_period_index.rename(
154+
columns=lambda x: '{key}{key}'.format(key=x))
155+
156+
joined_values = np.concatenate(
157+
[frame_with_period_index.values] * 2, axis=1)
158+
159+
joined_cols = frame_with_period_index.columns.append(other.columns)
160+
161+
joined = frame_with_period_index.join(other)
162+
expected = DataFrame(
163+
data=joined_values,
164+
columns=joined_cols,
165+
index=frame_with_period_index.index)
166+
167+
tm.assert_frame_equal(joined, expected)

pandas/tests/indexes/common.py

+22-1
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,20 @@ def test_reindex_base(self):
132132
with tm.assert_raises_regex(ValueError, 'Invalid fill method'):
133133
idx.get_indexer(idx, method='invalid')
134134

135+
def test_get_indexer_consistency(self):
136+
# See GH 16819
137+
for name, index in self.indices.items():
138+
if isinstance(index, IntervalIndex):
139+
continue
140+
141+
indexer = index.get_indexer(index[0:2])
142+
assert isinstance(indexer, np.ndarray)
143+
assert indexer.dtype == np.intp
144+
145+
indexer, _ = index.get_indexer_non_unique(index[0:2])
146+
assert isinstance(indexer, np.ndarray)
147+
assert indexer.dtype == np.intp
148+
135149
def test_ndarray_compat_properties(self):
136150
idx = self.create_index()
137151
assert idx.T.equals(idx)
@@ -905,7 +919,7 @@ def test_fillna(self):
905919

906920
def test_nulls(self):
907921
# this is really a smoke test for the methods
908-
# as these are adequantely tested for function elsewhere
922+
# as these are adequately tested for function elsewhere
909923

910924
for name, index in self.indices.items():
911925
if len(index) == 0:
@@ -933,3 +947,10 @@ def test_empty(self):
933947
index = self.create_index()
934948
assert not index.empty
935949
assert index[:0].empty
950+
951+
@pytest.mark.parametrize('how', ['outer', 'inner', 'left', 'right'])
952+
def test_join_self_unique(self, how):
953+
index = self.create_index()
954+
if index.is_unique:
955+
joined = index.join(index, how=how)
956+
assert (index == joined).all()

pandas/tests/indexes/period/test_period.py

+6
Original file line numberDiff line numberDiff line change
@@ -773,3 +773,9 @@ def test_map(self):
773773
result = index.map(lambda x: x.ordinal)
774774
exp = Index([x.ordinal for x in index])
775775
tm.assert_index_equal(result, exp)
776+
777+
@pytest.mark.parametrize('how', ['outer', 'inner', 'left', 'right'])
778+
def test_join_self(self, how):
779+
index = period_range('1/1/2000', periods=10)
780+
joined = index.join(index, how=how)
781+
assert index is joined

pandas/tests/indexes/test_base.py

-11
Original file line numberDiff line numberDiff line change
@@ -1131,17 +1131,6 @@ def test_get_indexer_strings(self):
11311131
with pytest.raises(TypeError):
11321132
idx.get_indexer(['a', 'b', 'c', 'd'], method='pad', tolerance=2)
11331133

1134-
def test_get_indexer_consistency(self):
1135-
# See GH 16819
1136-
for name, index in self.indices.items():
1137-
indexer = index.get_indexer(index[0:2])
1138-
assert isinstance(indexer, np.ndarray)
1139-
assert indexer.dtype == np.intp
1140-
1141-
indexer, _ = index.get_indexer_non_unique(index[0:2])
1142-
assert isinstance(indexer, np.ndarray)
1143-
assert indexer.dtype == np.intp
1144-
11451134
def test_get_loc(self):
11461135
idx = pd.Index([0, 1, 2])
11471136
all_methods = [None, 'pad', 'backfill', 'nearest']

pandas/tests/indexes/test_category.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -401,23 +401,23 @@ def test_reindex_dtype(self):
401401
exp = CategoricalIndex(['a', 'a', 'c'], categories=['a', 'c'])
402402
tm.assert_index_equal(res, exp, exact=True)
403403
tm.assert_numpy_array_equal(indexer,
404-
np.array([0, 3, 2], dtype=np.int64))
404+
np.array([0, 3, 2], dtype=np.intp))
405405

406406
c = CategoricalIndex(['a', 'b', 'c', 'a'],
407407
categories=['a', 'b', 'c', 'd'])
408408
res, indexer = c.reindex(['a', 'c'])
409409
exp = Index(['a', 'a', 'c'], dtype='object')
410410
tm.assert_index_equal(res, exp, exact=True)
411411
tm.assert_numpy_array_equal(indexer,
412-
np.array([0, 3, 2], dtype=np.int64))
412+
np.array([0, 3, 2], dtype=np.intp))
413413

414414
c = CategoricalIndex(['a', 'b', 'c', 'a'],
415415
categories=['a', 'b', 'c', 'd'])
416416
res, indexer = c.reindex(Categorical(['a', 'c']))
417417
exp = CategoricalIndex(['a', 'a', 'c'], categories=['a', 'c'])
418418
tm.assert_index_equal(res, exp, exact=True)
419419
tm.assert_numpy_array_equal(indexer,
420-
np.array([0, 3, 2], dtype=np.int64))
420+
np.array([0, 3, 2], dtype=np.intp))
421421

422422
def test_reindex_empty_index(self):
423423
# See GH16770

pandas/tests/indexes/timedeltas/test_timedelta.py

+14-6
Original file line numberDiff line numberDiff line change
@@ -564,15 +564,23 @@ def test_freq_conversion(self):
564564

565565

566566
class TestSlicing(object):
567+
@pytest.mark.parametrize('freq', ['B', 'D'])
568+
def test_timedelta(self, freq):
569+
index = date_range('1/1/2000', periods=50, freq=freq)
567570

568-
def test_timedelta(self):
569-
# this is valid too
570-
index = date_range('1/1/2000', periods=50, freq='B')
571571
shifted = index + timedelta(1)
572572
back = shifted + timedelta(-1)
573-
assert tm.equalContents(index, back)
574-
assert shifted.freq == index.freq
575-
assert shifted.freq == back.freq
573+
tm.assert_index_equal(index, back)
574+
575+
if freq == 'D':
576+
expected = pd.tseries.offsets.Day(1)
577+
assert index.freq == expected
578+
assert shifted.freq == expected
579+
assert back.freq == expected
580+
else: # freq == 'B'
581+
assert index.freq == pd.tseries.offsets.BusinessDay(1)
582+
assert shifted.freq is None
583+
assert back.freq == pd.tseries.offsets.BusinessDay(1)
576584

577585
result = index - timedelta(1)
578586
expected = index + timedelta(-1)

0 commit comments

Comments
 (0)