Skip to content

Commit bf2964b

Browse files
committed
List indexer on PeriodIndex doesn't coerce strings (pandas-dev#11278)
1 parent cde73af commit bf2964b

File tree

3 files changed

+89
-2
lines changed

3 files changed

+89
-2
lines changed

doc/source/whatsnew/v1.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,7 @@ Indexing
778778
- Bug when indexing with ``.loc`` where the index was a :class:`CategoricalIndex` with non-string categories didn't work (:issue:`17569`, :issue:`30225`)
779779
- :meth:`Index.get_indexer_non_unique` could fail with `TypeError` in some cases, such as when searching for ints in a string index (:issue:`28257`)
780780
- Bug in :meth:`Float64Index.get_loc` incorrectly raising ``TypeError`` instead of ``KeyError`` (:issue:`29189`)
781+
- List datetime string indexer could fail on `PeriodIndex` or `DatetimeIndex` (:issue:`11278`)
781782

782783
Missing
783784
^^^^^^^

pandas/core/indexing.py

+25-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from pandas._libs.indexing import _NDFrameIndexerBase
66
from pandas._libs.lib import item_from_zerodim
7+
from pandas._libs.tslibs import Period, Timestamp
78
from pandas.errors import AbstractMethodError
89
from pandas.util._decorators import Appender
910

@@ -18,7 +19,13 @@
1819
is_sparse,
1920
)
2021
from pandas.core.dtypes.concat import concat_compat
21-
from pandas.core.dtypes.generic import ABCDataFrame, ABCMultiIndex, ABCSeries
22+
from pandas.core.dtypes.generic import (
23+
ABCDataFrame,
24+
ABCDatetimeIndex,
25+
ABCMultiIndex,
26+
ABCPeriodIndex,
27+
ABCSeries,
28+
)
2229
from pandas.core.dtypes.missing import _infer_fill_value, isna
2330

2431
import pandas.core.common as com
@@ -1660,6 +1667,23 @@ def _get_partial_string_timestamp_match_key(self, key, labels):
16601667
new_key.append(component)
16611668
key = tuple(new_key)
16621669

1670+
elif isinstance(labels, (ABCDatetimeIndex, ABCPeriodIndex)):
1671+
if isinstance(key, list):
1672+
object_type_mapper = {"period": Period, "datetime64": Timestamp}
1673+
object_type = labels.inferred_type
1674+
freq_str = labels.freqstr
1675+
1676+
for i, comp in enumerate(key):
1677+
try:
1678+
"""
1679+
if labels type is period and labels freq is 'D'
1680+
'2019-12-27' to Period('2019-12-27', 'D')
1681+
"""
1682+
key[i] = object_type_mapper[object_type](comp, freq=freq_str)
1683+
1684+
except (TypeError, ValueError, KeyError):
1685+
pass
1686+
16631687
return key
16641688

16651689
def _getitem_axis(self, key, axis: int):

pandas/tests/indexing/test_loc.py

+63-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import pytest
77

88
import pandas as pd
9-
from pandas import DataFrame, Series, Timestamp, date_range
9+
from pandas import DataFrame, Period, Series, Timestamp, date_range, period_range
1010
from pandas.api.types import is_scalar
1111
from pandas.tests.indexing.common import Base
1212
import pandas.util.testing as tm
@@ -939,6 +939,68 @@ def test_loc_reverse_assignment(self):
939939

940940
tm.assert_series_equal(result, expected)
941941

942+
@pytest.mark.parametrize(
943+
"idx,labels,expected_idx",
944+
[
945+
(
946+
period_range(start="2000", periods=20, freq="D"),
947+
["2000-01-04", "2000-01-08", "2000-01-12"],
948+
[
949+
Period("2000-01-04", freq="D"),
950+
Period("2000-01-08", freq="D"),
951+
Period("2000-01-12", freq="D"),
952+
],
953+
),
954+
(
955+
date_range(start="2000", periods=20, freq="D"),
956+
["2000-01-04", "2000-01-08", "2000-01-12"],
957+
[
958+
Timestamp("2000-01-04", freq="D"),
959+
Timestamp("2000-01-08", freq="D"),
960+
Timestamp("2000-01-12", freq="D"),
961+
],
962+
),
963+
],
964+
)
965+
def test_loc_with_datetime_string_list(self, idx, labels, expected_idx):
966+
# GH 11278
967+
s = Series(range(20), index=idx)
968+
df = DataFrame(range(20), index=idx)
969+
970+
expected_value = [3, 7, 11]
971+
expected_s = Series(expected_value, expected_idx)
972+
expected_df = DataFrame(expected_value, expected_idx)
973+
974+
tm.assert_series_equal(expected_s, s.loc[labels])
975+
tm.assert_series_equal(expected_s, s[labels])
976+
tm.assert_frame_equal(expected_df, df.loc[labels])
977+
978+
@pytest.mark.parametrize(
979+
"idx,labels",
980+
[
981+
(
982+
period_range(start="2000", periods=20, freq="D"),
983+
["2000-01-04", "2000-01-30", "2000-01-12"],
984+
),
985+
(
986+
date_range(start="2000", periods=20, freq="D"),
987+
["2000-01-04", "2000-01-30", "2000-01-12"],
988+
),
989+
],
990+
)
991+
def test_loc_with_datetime_string_and_missing_value(self, idx, labels):
992+
# GH 11278
993+
s = Series(range(20), index=idx)
994+
df = DataFrame(range(20), index=idx)
995+
996+
msg = r"Passing list-likes to .loc or \[\] with any missing labels"
997+
with pytest.raises(KeyError, match=msg):
998+
s.loc[labels]
999+
with pytest.raises(KeyError, match=msg):
1000+
s[labels]
1001+
with pytest.raises(KeyError, match=msg):
1002+
df.loc[labels]
1003+
9421004

9431005
def test_series_loc_getitem_label_list_missing_values():
9441006
# gh-11428

0 commit comments

Comments
 (0)