|
18 | 18 | from pandas.core.dtypes.generic import (
|
19 | 19 | ABCSeries, ABCDataFrame,
|
20 | 20 | ABCMultiIndex,
|
21 |
| - ABCPeriodIndex, ABCTimedeltaIndex, |
| 21 | + ABCPeriodIndex, ABCTimedeltaIndex, ABCDatetimeIndex, |
22 | 22 | ABCDateOffset)
|
23 | 23 | from pandas.core.dtypes.missing import isna, array_equivalent
|
24 | 24 | from pandas.core.dtypes.cast import maybe_cast_to_integer_array
|
@@ -545,6 +545,10 @@ def _shallow_copy(self, values=None, **kwargs):
|
545 | 545 |
|
546 | 546 | # _simple_new expects an ndarray
|
547 | 547 | values = getattr(values, 'values', values)
|
| 548 | + if isinstance(values, ABCDatetimeIndex): |
| 549 | + # `self.values` returns `self` for tz-aware, so we need to unwrap |
| 550 | + # more specifically |
| 551 | + values = values.asi8 |
548 | 552 |
|
549 | 553 | return self._simple_new(values, **attributes)
|
550 | 554 |
|
@@ -2947,7 +2951,8 @@ def difference(self, other):
|
2947 | 2951 | self._assert_can_do_setop(other)
|
2948 | 2952 |
|
2949 | 2953 | if self.equals(other):
|
2950 |
| - return self._shallow_copy([]) |
| 2954 | + # pass an empty np.ndarray with the appropriate dtype |
| 2955 | + return self._shallow_copy(self._data[:0]) |
2951 | 2956 |
|
2952 | 2957 | other, result_name = self._convert_can_do_setop(other)
|
2953 | 2958 |
|
@@ -3715,7 +3720,8 @@ def reindex(self, target, method=None, level=None, limit=None,
|
3715 | 3720 | if not isinstance(target, Index) and len(target) == 0:
|
3716 | 3721 | attrs = self._get_attributes_dict()
|
3717 | 3722 | attrs.pop('freq', None) # don't preserve freq
|
3718 |
| - target = self._simple_new(None, dtype=self.dtype, **attrs) |
| 3723 | + values = self._data[:0] # appropriately-dtyped empty array |
| 3724 | + target = self._simple_new(values, dtype=self.dtype, **attrs) |
3719 | 3725 | else:
|
3720 | 3726 | target = ensure_index(target)
|
3721 | 3727 |
|
@@ -3930,46 +3936,72 @@ def join(self, other, how='left', level=None, return_indexers=False,
|
3930 | 3936 |
|
3931 | 3937 | def _join_multi(self, other, how, return_indexers=True):
|
3932 | 3938 | from .multi import MultiIndex
|
| 3939 | + from pandas.core.reshape.merge import _restore_dropped_levels_multijoin |
| 3940 | + |
| 3941 | + # figure out join names |
| 3942 | + self_names = set(com._not_none(*self.names)) |
| 3943 | + other_names = set(com._not_none(*other.names)) |
| 3944 | + overlap = self_names & other_names |
| 3945 | + |
| 3946 | + # need at least 1 in common |
| 3947 | + if not overlap: |
| 3948 | + raise ValueError("cannot join with no overlapping index names") |
| 3949 | + |
3933 | 3950 | self_is_mi = isinstance(self, MultiIndex)
|
3934 | 3951 | other_is_mi = isinstance(other, MultiIndex)
|
3935 | 3952 |
|
3936 |
| - # figure out join names |
3937 |
| - self_names = com._not_none(*self.names) |
3938 |
| - other_names = com._not_none(*other.names) |
3939 |
| - overlap = list(set(self_names) & set(other_names)) |
3940 |
| - |
3941 |
| - # need at least 1 in common, but not more than 1 |
3942 |
| - if not len(overlap): |
3943 |
| - raise ValueError("cannot join with no level specified and no " |
3944 |
| - "overlapping names") |
3945 |
| - if len(overlap) > 1: |
3946 |
| - raise NotImplementedError("merging with more than one level " |
3947 |
| - "overlap on a multi-index is not " |
3948 |
| - "implemented") |
3949 |
| - jl = overlap[0] |
| 3953 | + if self_is_mi and other_is_mi: |
| 3954 | + |
| 3955 | + # Drop the non-matching levels from left and right respectively |
| 3956 | + ldrop_names = list(self_names - overlap) |
| 3957 | + rdrop_names = list(other_names - overlap) |
| 3958 | + |
| 3959 | + self_jnlevels = self.droplevel(ldrop_names) |
| 3960 | + other_jnlevels = other.droplevel(rdrop_names) |
| 3961 | + |
| 3962 | + # Join left and right |
| 3963 | + # Join on same leveled multi-index frames is supported |
| 3964 | + join_idx, lidx, ridx = self_jnlevels.join(other_jnlevels, how, |
| 3965 | + return_indexers=True) |
| 3966 | + |
| 3967 | + # Restore the dropped levels |
| 3968 | + # Returned index level order is |
| 3969 | + # common levels, ldrop_names, rdrop_names |
| 3970 | + dropped_names = ldrop_names + rdrop_names |
| 3971 | + |
| 3972 | + levels, labels, names = ( |
| 3973 | + _restore_dropped_levels_multijoin(self, other, |
| 3974 | + dropped_names, |
| 3975 | + join_idx, |
| 3976 | + lidx, ridx)) |
3950 | 3977 |
|
| 3978 | + # Re-create the multi-index |
| 3979 | + multi_join_idx = MultiIndex(levels=levels, labels=labels, |
| 3980 | + names=names, verify_integrity=False) |
| 3981 | + |
| 3982 | + multi_join_idx = multi_join_idx.remove_unused_levels() |
| 3983 | + |
| 3984 | + return multi_join_idx, lidx, ridx |
| 3985 | + |
| 3986 | + jl = list(overlap)[0] |
| 3987 | + |
| 3988 | + # Case where only one index is multi |
3951 | 3989 | # make the indices into mi's that match
|
3952 |
| - if not (self_is_mi and other_is_mi): |
3953 |
| - |
3954 |
| - flip_order = False |
3955 |
| - if self_is_mi: |
3956 |
| - self, other = other, self |
3957 |
| - flip_order = True |
3958 |
| - # flip if join method is right or left |
3959 |
| - how = {'right': 'left', 'left': 'right'}.get(how, how) |
3960 |
| - |
3961 |
| - level = other.names.index(jl) |
3962 |
| - result = self._join_level(other, level, how=how, |
3963 |
| - return_indexers=return_indexers) |
3964 |
| - |
3965 |
| - if flip_order: |
3966 |
| - if isinstance(result, tuple): |
3967 |
| - return result[0], result[2], result[1] |
3968 |
| - return result |
| 3990 | + flip_order = False |
| 3991 | + if self_is_mi: |
| 3992 | + self, other = other, self |
| 3993 | + flip_order = True |
| 3994 | + # flip if join method is right or left |
| 3995 | + how = {'right': 'left', 'left': 'right'}.get(how, how) |
| 3996 | + |
| 3997 | + level = other.names.index(jl) |
| 3998 | + result = self._join_level(other, level, how=how, |
| 3999 | + return_indexers=return_indexers) |
3969 | 4000 |
|
3970 |
| - # 2 multi-indexes |
3971 |
| - raise NotImplementedError("merging with both multi-indexes is not " |
3972 |
| - "implemented") |
| 4001 | + if flip_order: |
| 4002 | + if isinstance(result, tuple): |
| 4003 | + return result[0], result[2], result[1] |
| 4004 | + return result |
3973 | 4005 |
|
3974 | 4006 | def _join_non_unique(self, other, how='left', return_indexers=False):
|
3975 | 4007 | from pandas.core.reshape.merge import _get_join_indexers
|
|
0 commit comments