Skip to content

Commit 7d4e93d

Browse files
committed
Merge branch 'master' of https://github.com/pandas-dev/pandas into overwrite_xl
2 parents e8716c7 + 4ef033f commit 7d4e93d

File tree

15 files changed

+370
-200
lines changed

15 files changed

+370
-200
lines changed

doc/source/reference/style.rst

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ Style application
3535
Styler.applymap
3636
Styler.where
3737
Styler.format
38-
Styler.set_precision
3938
Styler.set_td_classes
4039
Styler.set_table_styles
4140
Styler.set_table_attributes
@@ -44,7 +43,6 @@ Style application
4443
Styler.set_caption
4544
Styler.set_properties
4645
Styler.set_uuid
47-
Styler.set_na_rep
4846
Styler.clear
4947
Styler.pipe
5048

@@ -53,9 +51,9 @@ Builtin styles
5351
.. autosummary::
5452
:toctree: api/
5553

54+
Styler.highlight_null
5655
Styler.highlight_max
5756
Styler.highlight_min
58-
Styler.highlight_null
5957
Styler.background_gradient
6058
Styler.bar
6159

doc/source/whatsnew/v1.3.0.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ Other enhancements
136136
- :meth:`.Styler.set_tooltips_class` and :meth:`.Styler.set_table_styles` amended to optionally allow certain css-string input arguments (:issue:`39564`)
137137
- :meth:`.Styler.apply` now more consistently accepts ndarray function returns, i.e. in all cases for ``axis`` is ``0, 1 or None`` (:issue:`39359`)
138138
- :meth:`.Styler.apply` and :meth:`.Styler.applymap` now raise errors if wrong format CSS is passed on render (:issue:`39660`)
139+
- Builtin highlighting methods in :class:`Styler` have a more consistent signature and css customisability (:issue:`40242`)
139140
- :meth:`Series.loc.__getitem__` and :meth:`Series.loc.__setitem__` with :class:`MultiIndex` now raising helpful error message when indexer has too many dimensions (:issue:`35349`)
140141
- :meth:`pandas.read_stata` and :class:`StataReader` support reading data from compressed files.
141142
- Add support for parsing ``ISO 8601``-like timestamps with negative signs to :meth:`pandas.Timedelta` (:issue:`37172`)
@@ -364,6 +365,7 @@ Deprecations
364365
- Deprecated :meth:`core.window.ewm.ExponentialMovingWindow.vol` (:issue:`39220`)
365366
- Using ``.astype`` to convert between ``datetime64[ns]`` dtype and :class:`DatetimeTZDtype` is deprecated and will raise in a future version, use ``obj.tz_localize`` or ``obj.dt.tz_localize`` instead (:issue:`38622`)
366367
- Deprecated casting ``datetime.date`` objects to ``datetime64`` when used as ``fill_value`` in :meth:`DataFrame.unstack`, :meth:`DataFrame.shift`, :meth:`Series.shift`, and :meth:`DataFrame.reindex`, pass ``pd.Timestamp(dateobj)`` instead (:issue:`39767`)
368+
- Deprecated :meth:`.Styler.set_na_rep` and :meth:`.Styler.set_precision` in favour of :meth:`.Styler.format` with ``na_rep`` and ``precision`` as existing and new input arguments respectively (:issue:`40134`)
367369
- Deprecated allowing partial failure in :meth:`Series.transform` and :meth:`DataFrame.transform` when ``func`` is list-like or dict-like; will raise if any function fails on a column in a future version (:issue:`40211`)
368370

369371
.. ---------------------------------------------------------------------------

pandas/_libs/internals.pyx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,24 @@ cimport numpy as cnp
1515
from numpy cimport (
1616
NPY_INT64,
1717
int64_t,
18+
ndarray,
1819
)
1920

2021
cnp.import_array()
2122

2223
from pandas._libs.algos import ensure_int64
24+
from pandas._libs.util cimport is_integer_object
2325

2426

2527
@cython.final
2628
cdef class BlockPlacement:
2729
# __slots__ = '_as_slice', '_as_array', '_len'
2830
cdef:
2931
slice _as_slice
30-
object _as_array
32+
ndarray _as_array # Note: this still allows `None`
3133
bint _has_slice, _has_array, _is_known_slice_like
3234

33-
def __init__(self, val):
35+
def __cinit__(self, val):
3436
cdef:
3537
slice slc
3638

@@ -39,7 +41,7 @@ cdef class BlockPlacement:
3941
self._has_slice = False
4042
self._has_array = False
4143

42-
if isinstance(val, int):
44+
if is_integer_object(val):
4345
slc = slice(val, val + 1, 1)
4446
self._as_slice = slc
4547
self._has_slice = True
@@ -160,12 +162,12 @@ cdef class BlockPlacement:
160162
np.concatenate([self.as_array] + [o.as_array for o in others])
161163
)
162164

163-
cdef iadd(self, other):
165+
cdef BlockPlacement iadd(self, other):
164166
cdef:
165167
slice s = self._ensure_has_slice()
166168
Py_ssize_t other_int, start, stop, step, l
167169

168-
if isinstance(other, int) and s is not None:
170+
if is_integer_object(other) and s is not None:
169171
other_int = <Py_ssize_t>other
170172

171173
if other_int == 0:
@@ -438,13 +440,13 @@ def get_blkno_placements(blknos, group: bool = True):
438440
"""
439441
Parameters
440442
----------
441-
blknos : array of int64
443+
blknos : np.ndarray[int64]
442444
group : bool, default True
443445
444446
Returns
445447
-------
446448
iterator
447-
yield (BlockPlacement, blkno)
449+
yield (blkno, BlockPlacement)
448450
"""
449451
blknos = ensure_int64(blknos)
450452

pandas/core/array_algos/take.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,43 @@ def _take_nd_ndarray(
121121
return out
122122

123123

124+
def take_1d(
125+
arr: ArrayLike,
126+
indexer: np.ndarray,
127+
fill_value=None,
128+
allow_fill: bool = True,
129+
) -> ArrayLike:
130+
"""
131+
Specialized version for 1D arrays. Differences compared to take_nd:
132+
133+
- Assumes input (arr, indexer) has already been converted to numpy array / EA
134+
- Only works for 1D arrays
135+
136+
To ensure the lowest possible overhead.
137+
138+
TODO(ArrayManager): mainly useful for ArrayManager, otherwise can potentially
139+
be removed again if we don't end up with ArrayManager.
140+
"""
141+
if not isinstance(arr, np.ndarray):
142+
# ExtensionArray -> dispatch to their method
143+
return arr.take(indexer, fill_value=fill_value, allow_fill=allow_fill)
144+
145+
indexer, dtype, fill_value, mask_info = _take_preprocess_indexer_and_fill_value(
146+
arr, indexer, 0, None, fill_value, allow_fill
147+
)
148+
149+
# at this point, it's guaranteed that dtype can hold both the arr values
150+
# and the fill_value
151+
out = np.empty(indexer.shape, dtype=dtype)
152+
153+
func = _get_take_nd_function(
154+
arr.ndim, arr.dtype, out.dtype, axis=0, mask_info=mask_info
155+
)
156+
func(arr, indexer, out, fill_value)
157+
158+
return out
159+
160+
124161
def take_2d_multi(
125162
arr: np.ndarray, indexer: np.ndarray, fill_value=np.nan
126163
) -> np.ndarray:

pandas/core/indexes/base.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4534,7 +4534,6 @@ def __getitem__(self, key):
45344534
# There's no custom logic to be implemented in __getslice__, so it's
45354535
# not overloaded intentionally.
45364536
getitem = self._data.__getitem__
4537-
promote = self._shallow_copy
45384537

45394538
if is_scalar(key):
45404539
key = com.cast_scalar_indexer(key, warn_float=True)
@@ -4543,7 +4542,9 @@ def __getitem__(self, key):
45434542
if isinstance(key, slice):
45444543
# This case is separated from the conditional above to avoid
45454544
# pessimization of basic indexing.
4546-
return promote(getitem(key))
4545+
result = getitem(key)
4546+
# Going through simple_new for performance.
4547+
return type(self)._simple_new(result, name=self.name)
45474548

45484549
if com.is_bool_indexer(key):
45494550
key = np.asarray(key, dtype=bool)
@@ -4553,7 +4554,9 @@ def __getitem__(self, key):
45534554
if np.ndim(result) > 1:
45544555
deprecate_ndim_indexing(result)
45554556
return result
4556-
return promote(result)
4557+
# NB: Using _constructor._simple_new would break if MultiIndex
4558+
# didn't override __getitem__
4559+
return self._constructor._simple_new(result, name=self.name)
45574560
else:
45584561
return result
45594562

pandas/core/indexes/category.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ def _simple_new(cls, values: Categorical, name: Optional[Hashable] = None):
231231
result = object.__new__(cls)
232232

233233
result._data = values
234-
result.name = name
234+
result._name = name
235235
result._cache = {}
236236

237237
result._reset_identity()

pandas/core/indexes/multi.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2076,15 +2076,16 @@ def __getitem__(self, key):
20762076

20772077
return tuple(retval)
20782078
else:
2079+
# in general cannot be sure whether the result will be sorted
2080+
sortorder = None
20792081
if com.is_bool_indexer(key):
20802082
key = np.asarray(key, dtype=bool)
20812083
sortorder = self.sortorder
2082-
else:
2083-
# cannot be sure whether the result will be sorted
2084-
sortorder = None
2085-
2086-
if isinstance(key, Index):
2087-
key = np.asarray(key)
2084+
elif isinstance(key, slice):
2085+
if key.step is None or key.step > 0:
2086+
sortorder = self.sortorder
2087+
elif isinstance(key, Index):
2088+
key = np.asarray(key)
20882089

20892090
new_codes = [level_codes[key] for level_codes in self.codes]
20902091

pandas/core/indexes/range.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def _simple_new(cls, values: range, name: Hashable = None) -> RangeIndex:
164164
assert isinstance(values, range)
165165

166166
result._range = values
167-
result.name = name
167+
result._name = name
168168
result._cache = {}
169169
result._reset_identity()
170170
return result

pandas/core/internals/array_manager.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858

5959
import pandas.core.algorithms as algos
6060
from pandas.core.array_algos.quantile import quantile_compat
61-
from pandas.core.array_algos.take import take_nd
61+
from pandas.core.array_algos.take import take_1d
6262
from pandas.core.arrays import (
6363
DatetimeArray,
6464
ExtensionArray,
@@ -991,7 +991,7 @@ def _reindex_indexer(
991991
else:
992992
validate_indices(indexer, len(self._axes[0]))
993993
new_arrays = [
994-
take_nd(
994+
take_1d(
995995
arr,
996996
indexer,
997997
allow_fill=True,
@@ -1073,7 +1073,7 @@ def unstack(self, unstacker, fill_value) -> ArrayManager:
10731073
new_arrays = []
10741074
for arr in self.arrays:
10751075
for i in range(unstacker.full_shape[1]):
1076-
new_arr = take_nd(
1076+
new_arr = take_1d(
10771077
arr, new_indexer2D[:, i], allow_fill=True, fill_value=fill_value
10781078
)
10791079
new_arrays.append(new_arr)

pandas/core/internals/blocks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ def _split_op_result(self, result) -> List[Block]:
449449
nbs = []
450450
for i, loc in enumerate(self.mgr_locs):
451451
vals = result[i]
452-
block = self.make_block(values=vals, placement=[loc])
452+
block = self.make_block(values=vals, placement=loc)
453453
nbs.append(block)
454454
return nbs
455455

pandas/core/internals/managers.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ class BlockManager(DataManager):
149149
_blknos: np.ndarray
150150
_blklocs: np.ndarray
151151

152+
# Non-trivially faster than a property
153+
ndim = 2 # overridden by SingleBlockManager
154+
152155
def __init__(
153156
self,
154157
blocks: Sequence[Block],
@@ -173,6 +176,21 @@ def __init__(
173176
self._blknos = None
174177
self._blklocs = None
175178

179+
@classmethod
180+
def _simple_new(cls, blocks: Tuple[Block, ...], axes: List[Index]):
181+
"""
182+
Fastpath constructor; does NO validation.
183+
"""
184+
obj = cls.__new__(cls)
185+
obj.axes = axes
186+
obj.blocks = blocks
187+
188+
# Populate known_consolidate, blknos, and blklocs lazily
189+
obj._known_consolidated = False
190+
obj._blknos = None
191+
obj._blklocs = None
192+
return obj
193+
176194
@classmethod
177195
def from_blocks(cls, blocks: List[Block], axes: List[Index]):
178196
"""
@@ -233,10 +251,6 @@ def __nonzero__(self) -> bool:
233251
def shape(self) -> Shape:
234252
return tuple(len(ax) for ax in self.axes)
235253

236-
@property
237-
def ndim(self) -> int:
238-
return len(self.axes)
239-
240254
def _normalize_axis(self, axis):
241255
# switch axis to follow BlockManager logic
242256
if self.ndim == 2:
@@ -800,8 +814,7 @@ def get_slice(self, slobj: slice, axis: int = 0) -> BlockManager:
800814
new_axes = list(self.axes)
801815
new_axes[axis] = new_axes[axis][slobj]
802816

803-
bm = type(self)(new_blocks, new_axes, verify_integrity=False)
804-
return bm
817+
return type(self)._simple_new(tuple(new_blocks), new_axes)
805818

806819
@property
807820
def nblocks(self) -> int:
@@ -1322,7 +1335,7 @@ def reindex_indexer(
13221335

13231336
def _slice_take_blocks_ax0(
13241337
self, slice_or_indexer, fill_value=lib.no_default, only_slice: bool = False
1325-
):
1338+
) -> List[Block]:
13261339
"""
13271340
Slice/take blocks along axis=0.
13281341

0 commit comments

Comments
 (0)