Skip to content

Commit 314aee5

Browse files
Merge branch 'master' into doctest-fix-2
2 parents 93d5565 + b8d750f commit 314aee5

37 files changed

+290
-162
lines changed

asv_bench/benchmarks/reshape.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ def setup(self, dtype):
102102
columns = np.arange(n)
103103
if dtype == "int":
104104
values = np.arange(m * m * n).reshape(m * m, n)
105+
self.df = DataFrame(values, index, columns)
105106
else:
106107
# the category branch is ~20x slower than int. So we
107108
# cut down the size a bit. Now it's only ~3x slower.
@@ -111,7 +112,10 @@ def setup(self, dtype):
111112
values = np.take(list(string.ascii_letters), indices)
112113
values = [pd.Categorical(v) for v in values.T]
113114

114-
self.df = DataFrame(values, index, columns)
115+
self.df = DataFrame(
116+
{i: cat for i, cat in enumerate(values)}, index, columns
117+
)
118+
115119
self.df2 = self.df.iloc[:-1]
116120

117121
def time_full_product(self, dtype):

ci/deps/actions-39-slow.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ dependencies:
2323
- matplotlib
2424
- moto>=1.3.14
2525
- flask
26+
- numba
2627
- numexpr
2728
- numpy
2829
- openpyxl

ci/deps/actions-39.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ dependencies:
2222
- matplotlib
2323
- moto>=1.3.14
2424
- flask
25+
- numba
2526
- numexpr
2627
- numpy
2728
- openpyxl

ci/deps/azure-windows-39.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ dependencies:
2323
- matplotlib
2424
- moto>=1.3.14
2525
- flask
26+
- numba
2627
- numexpr
2728
- numpy
2829
- openpyxl

ci/run_tests.sh

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ fi
3030
echo $PYTEST_CMD
3131
sh -c "$PYTEST_CMD"
3232

33-
PYTEST_AM_CMD="PANDAS_DATA_MANAGER=array pytest -m \"$PATTERN and arraymanager\" -n $PYTEST_WORKERS --dist=loadfile $TEST_ARGS $COVERAGE pandas"
33+
if [[ "$PANDAS_DATA_MANAGER" != "array" ]]; then
34+
# The ArrayManager tests should have already been run by PYTEST_CMD if PANDAS_DATA_MANAGER was already set to array
35+
PYTEST_AM_CMD="PANDAS_DATA_MANAGER=array pytest -m \"$PATTERN and arraymanager\" -n $PYTEST_WORKERS --dist=loadfile $TEST_ARGS $COVERAGE pandas"
3436

35-
echo $PYTEST_AM_CMD
36-
sh -c "$PYTEST_AM_CMD"
37+
echo $PYTEST_AM_CMD
38+
sh -c "$PYTEST_AM_CMD"
39+
fi

doc/source/whatsnew/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Version 1.3
2424
.. toctree::
2525
:maxdepth: 2
2626

27+
v1.3.2
2728
v1.3.1
2829
v1.3.0
2930

doc/source/whatsnew/v1.3.1.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,4 @@ Bug fixes
4848
Contributors
4949
~~~~~~~~~~~~
5050

51-
.. contributors:: v1.3.0..v1.3.1|HEAD
51+
.. contributors:: v1.3.0..v1.3.1

doc/source/whatsnew/v1.3.2.rst

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
.. _whatsnew_132:
2+
3+
What's new in 1.3.2 (August ??, 2021)
4+
-------------------------------------
5+
6+
These are the changes in pandas 1.3.2. See :ref:`release` for a full changelog
7+
including other versions of pandas.
8+
9+
{{ header }}
10+
11+
.. ---------------------------------------------------------------------------
12+
13+
.. _whatsnew_132.regressions:
14+
15+
Fixed regressions
16+
~~~~~~~~~~~~~~~~~
17+
- Performance regression in :meth:`DataFrame.isin` and :meth:`Series.isin` for nullable data types (:issue:`42714`)
18+
- Regression in updating values of :class:`pandas.Series` using boolean index, created by using :meth:`pandas.DataFrame.pop` (:issue:`42530`)
19+
- Regression in :meth:`DataFrame.from_records` with empty records (:issue:`42456`)
20+
-
21+
22+
.. ---------------------------------------------------------------------------
23+
24+
.. _whatsnew_132.bug_fixes:
25+
26+
Bug fixes
27+
~~~~~~~~~
28+
-
29+
-
30+
31+
.. ---------------------------------------------------------------------------
32+
33+
.. _whatsnew_132.other:
34+
35+
Other
36+
~~~~~
37+
-
38+
-
39+
40+
.. ---------------------------------------------------------------------------
41+
42+
.. _whatsnew_132.contributors:
43+
44+
Contributors
45+
~~~~~~~~~~~~
46+
47+
.. contributors:: v1.3.1..v1.3.2|HEAD

doc/source/whatsnew/v1.4.0.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ enhancement2
2929

3030
Other enhancements
3131
^^^^^^^^^^^^^^^^^^
32+
- :class:`DataFrameGroupBy` operations with ``as_index=False`` now correctly retain ``ExtensionDtype`` dtypes for columns being grouped on (:issue:`41373`)
3233
- Add support for assigning values to ``by`` argument in :meth:`DataFrame.plot.hist` and :meth:`DataFrame.plot.box` (:issue:`15079`)
3334
- :meth:`Series.sample`, :meth:`DataFrame.sample`, and :meth:`.GroupBy.sample` now accept a ``np.random.Generator`` as input to ``random_state``. A generator will be more performant, especially with ``replace=False`` (:issue:`38100`)
3435
- Additional options added to :meth:`.Styler.bar` to control alignment and display, with keyword only arguments (:issue:`26070`, :issue:`36419`)
@@ -165,6 +166,7 @@ Performance improvements
165166
~~~~~~~~~~~~~~~~~~~~~~~~
166167
- Performance improvement in :meth:`.GroupBy.sample`, especially when ``weights`` argument provided (:issue:`34483`)
167168
- Performance improvement in :meth:`.GroupBy.transform` for user-defined functions (:issue:`41598`)
169+
- Performance improvement in constructing :class:`DataFrame` objects (:issue:`42631`)
168170

169171
.. ---------------------------------------------------------------------------
170172
@@ -224,7 +226,6 @@ Indexing
224226
- Bug in :meth:`Series.loc` when with a :class:`MultiIndex` whose first level contains only ``np.nan`` values (:issue:`42055`)
225227
- Bug in indexing on a :class:`Series` or :class:`DataFrame` with a :class:`DatetimeIndex` when passing a string, the return type depended on whether the index was monotonic (:issue:`24892`)
226228
- Bug in indexing on a :class:`MultiIndex` failing to drop scalar levels when the indexer is a tuple containing a datetime-like string (:issue:`42476`)
227-
-
228229

229230
Missing
230231
^^^^^^^
@@ -235,6 +236,7 @@ MultiIndex
235236
^^^^^^^^^^
236237
- Bug in :meth:`MultiIndex.get_loc` where the first level is a :class:`DatetimeIndex` and a string key is passed (:issue:`42465`)
237238
- Bug in :meth:`MultiIndex.reindex` when passing a ``level`` that corresponds to an ``ExtensionDtype`` level (:issue:`42043`)
239+
- Bug in :meth:`MultiIndex.get_loc` raising ``TypeError`` instead of ``KeyError`` on nested tuple (:issue:`42440`)
238240
-
239241

240242
I/O
@@ -262,7 +264,7 @@ Groupby/resample/rolling
262264

263265
Reshaping
264266
^^^^^^^^^
265-
-
267+
- :func:`concat` creating :class:`MultiIndex` with duplicate level entries when concatenating a :class:`DataFrame` with duplicates in :class:`Index` and multiple keys (:issue:`42651`)
266268
-
267269

268270
Sparse

environment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ dependencies:
108108
- fsspec>=0.7.4, <2021.6.0 # for generic remote file operations
109109
- gcsfs>=0.6.0 # file IO when using 'gcs://...' path
110110
- sqlalchemy # pandas.read_sql, DataFrame.to_sql
111-
- xarray # DataFrame.to_xarray
111+
- xarray<0.19 # DataFrame.to_xarray
112112
- cftime # Needed for downstream xarray.CFTimeIndex test
113113
- pyreadstat # pandas.read_spss
114114
- tabulate>=0.8.3 # DataFrame.to_markdown

pandas/core/arrays/masked.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ def isin(self, values) -> BooleanArray: # type: ignore[override]
417417
# see https://github.com/pandas-dev/pandas/pull/38379 for some discussion
418418
result[self._mask] = values_have_NA
419419

420-
mask = np.zeros_like(self, dtype=bool)
420+
mask = np.zeros(self._data.shape, dtype=bool)
421421
return BooleanArray(result, mask, copy=False)
422422

423423
def copy(self: BaseMaskedArrayT) -> BaseMaskedArrayT:

pandas/core/frame.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3745,7 +3745,7 @@ def _set_item_mgr(self, key, value: ArrayLike) -> None:
37453745
# try to set first as we want an invalid
37463746
# value exception to occur first
37473747
if len(self):
3748-
self._check_setitem_copy(stacklevel=5)
3748+
self._check_setitem_copy()
37493749

37503750
def _iset_item(self, loc: int, value) -> None:
37513751
arraylike = self._sanitize_column(value)

pandas/core/generic.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
doc,
6868
rewrite_axis_style_signature,
6969
)
70+
from pandas.util._exceptions import find_stack_level
7071
from pandas.util._validators import (
7172
validate_ascending,
7273
validate_bool_kwarg,
@@ -3506,7 +3507,7 @@ def _maybe_update_cacher(
35063507
"""
35073508

35083509
if verify_is_copy:
3509-
self._check_setitem_copy(stacklevel=5, t="referent")
3510+
self._check_setitem_copy(t="referent")
35103511

35113512
if clear:
35123513
self._clear_item_cache()
@@ -3853,26 +3854,21 @@ def _check_is_chained_assignment_possible(self) -> bool_t:
38533854
setting.
38543855
"""
38553856
if self._is_copy:
3856-
self._check_setitem_copy(stacklevel=4, t="referent")
3857+
self._check_setitem_copy(t="referent")
38573858
return False
38583859

38593860
@final
3860-
def _check_setitem_copy(self, stacklevel=4, t="setting", force=False):
3861+
def _check_setitem_copy(self, t="setting", force=False):
38613862
"""
38623863
38633864
Parameters
38643865
----------
3865-
stacklevel : int, default 4
3866-
the level to show of the stack when the error is output
38673866
t : str, the type of setting error
38683867
force : bool, default False
38693868
If True, then force showing an error.
38703869
38713870
validate if we are doing a setitem on a chained copy.
38723871
3873-
If you call this function, be sure to set the stacklevel such that the
3874-
user will see the error *at the level of setting*
3875-
38763872
It is technically possible to figure out that we are setting on
38773873
a copy even WITH a multi-dtyped pandas object. In other words, some
38783874
blocks may be views while other are not. Currently _is_view will ALWAYS
@@ -3931,7 +3927,7 @@ def _check_setitem_copy(self, stacklevel=4, t="setting", force=False):
39313927
if value == "raise":
39323928
raise com.SettingWithCopyError(t)
39333929
elif value == "warn":
3934-
warnings.warn(t, com.SettingWithCopyWarning, stacklevel=stacklevel)
3930+
warnings.warn(t, com.SettingWithCopyWarning, stacklevel=find_stack_level())
39353931

39363932
def __delitem__(self, key) -> None:
39373933
"""

pandas/core/groupby/generic.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1033,7 +1033,7 @@ def aggregate(self, func=None, *args, engine=None, engine_kwargs=None, **kwargs)
10331033
self._insert_inaxis_grouper_inplace(result)
10341034
result.index = Index(range(len(result)))
10351035

1036-
return result._convert(datetime=True)
1036+
return result
10371037

10381038
agg = aggregate
10391039

@@ -1684,6 +1684,8 @@ def _wrap_agged_manager(self, mgr: Manager2D) -> DataFrame:
16841684
if self.axis == 1:
16851685
result = result.T
16861686

1687+
# Note: we only need to pass datetime=True in order to get numeric
1688+
# values converted
16871689
return self._reindex_output(result)._convert(datetime=True)
16881690

16891691
def _iterate_column_groupbys(self, obj: FrameOrSeries):

pandas/core/groupby/grouper.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -619,11 +619,20 @@ def group_arraylike(self) -> ArrayLike:
619619
Analogous to result_index, but holding an ArrayLike to ensure
620620
we can can retain ExtensionDtypes.
621621
"""
622+
if self._group_index is not None:
623+
# _group_index is set in __init__ for MultiIndex cases
624+
return self._group_index._values
625+
626+
elif self._all_grouper is not None:
627+
# retain dtype for categories, including unobserved ones
628+
return self.result_index._values
629+
622630
return self._codes_and_uniques[1]
623631

624632
@cache_readonly
625633
def result_index(self) -> Index:
626-
# TODO: what's the difference between result_index vs group_index?
634+
# result_index retains dtype for categories, including unobserved ones,
635+
# which group_index does not
627636
if self._all_grouper is not None:
628637
group_idx = self.group_index
629638
assert isinstance(group_idx, CategoricalIndex)
@@ -635,7 +644,8 @@ def group_index(self) -> Index:
635644
if self._group_index is not None:
636645
# _group_index is set in __init__ for MultiIndex cases
637646
return self._group_index
638-
uniques = self.group_arraylike
647+
648+
uniques = self._codes_and_uniques[1]
639649
return Index(uniques, name=self.name)
640650

641651
@cache_readonly

pandas/core/groupby/ops.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,7 @@ def result_arraylike(self) -> ArrayLike:
885885
if len(self.groupings) == 1:
886886
return self.groupings[0].group_arraylike
887887

888+
# result_index is MultiIndex
888889
return self.result_index._values
889890

890891
@cache_readonly
@@ -903,12 +904,12 @@ def get_group_levels(self) -> list[ArrayLike]:
903904
# Note: only called from _insert_inaxis_grouper_inplace, which
904905
# is only called for BaseGrouper, never for BinGrouper
905906
if len(self.groupings) == 1:
906-
return [self.groupings[0].result_index]
907+
return [self.groupings[0].group_arraylike]
907908

908909
name_list = []
909910
for ping, codes in zip(self.groupings, self.reconstructed_codes):
910911
codes = ensure_platform_int(codes)
911-
levels = ping.result_index.take(codes)
912+
levels = ping.group_arraylike.take(codes)
912913

913914
name_list.append(levels)
914915

pandas/core/indexes/base.py

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5514,16 +5514,6 @@ def _get_indexer_non_comparable(
55145514
"""
55155515
if method is not None:
55165516
other = unpack_nested_dtype(target)
5517-
if self._is_multi ^ other._is_multi:
5518-
kind = other.dtype.type if self._is_multi else self.dtype.type
5519-
raise TypeError(
5520-
f"'<' not supported between instances of {kind} and 'tuple'"
5521-
)
5522-
elif self._is_multi and other._is_multi:
5523-
assert self.nlevels != other.nlevels
5524-
# Python allows comparison between tuples of different lengths,
5525-
# but for our purposes such a comparison is not meaningful.
5526-
raise TypeError("'<' not supported between tuples of different lengths")
55275517
raise TypeError(f"Cannot compare dtypes {self.dtype} and {other.dtype}")
55285518

55295519
no_matches = -1 * np.ones(target.shape, dtype=np.intp)
@@ -5653,14 +5643,6 @@ def _should_compare(self, other: Index) -> bool:
56535643

56545644
other = unpack_nested_dtype(other)
56555645
dtype = other.dtype
5656-
if other._is_multi:
5657-
if not self._is_multi:
5658-
# other contains only tuples so unless we are object-dtype,
5659-
# there can never be any matches
5660-
return self._is_comparable_dtype(dtype)
5661-
return self.nlevels == other.nlevels
5662-
# TODO: we can get more specific requiring levels are comparable?
5663-
56645646
return self._is_comparable_dtype(dtype) or is_object_dtype(dtype)
56655647

56665648
def _is_comparable_dtype(self, dtype: DtypeObj) -> bool:

pandas/core/indexes/multi.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2836,7 +2836,7 @@ def _maybe_to_slice(loc):
28362836
try:
28372837
return self._engine.get_loc(key)
28382838
except TypeError:
2839-
# e.g. partial string slicing
2839+
# e.g. test_partial_slicing_with_multiindex partial string slicing
28402840
loc, _ = self.get_loc_level(key, list(range(self.nlevels)))
28412841
return loc
28422842

@@ -2846,9 +2846,17 @@ def _maybe_to_slice(loc):
28462846
# needs linear search within the slice
28472847
i = self._lexsort_depth
28482848
lead_key, follow_key = key[:i], key[i:]
2849-
start, stop = (
2850-
self.slice_locs(lead_key, lead_key) if lead_key else (0, len(self))
2851-
)
2849+
2850+
if not lead_key:
2851+
start = 0
2852+
stop = len(self)
2853+
else:
2854+
try:
2855+
start, stop = self.slice_locs(lead_key, lead_key)
2856+
except TypeError as err:
2857+
# e.g. test_groupby_example key = ((0, 0, 1, 2), "new_col")
2858+
# when self has 5 integer levels
2859+
raise KeyError(key) from err
28522860

28532861
if start == stop:
28542862
raise KeyError(key)

0 commit comments

Comments
 (0)